学习threejs,导入FBX格式骨骼绑定模型

👨‍⚕️ 主页: gis分享者
👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅!
👨‍⚕️ 收录于专栏:threejs gis工程师


文章目录

  • 一、🍀前言
    • 1.1 ☘️THREE.FBXLoader fbx 模型加载插件
    • 1.2 ☘️THREE.AnimationMixer 动画混合器
  • 二、🍀导入FBX格式骨骼绑定模型
    • 1. ☘️实现思路
    • 2. ☘️代码样例


一、🍀前言

本文详细介绍如何基于threejs在三维场景中导入FBX格式骨骼绑定模型,亲测可用。希望能帮助到您。一起学习,加油!加油!

1.1 ☘️THREE.FBXLoader fbx 模型加载插件

FBXLoader是ThreeJS的一个扩展,用于加载和处理FBX格式的3D模型文件。FBX是一种通用的3D模型文件格式,可以包含几何形状、材质、动画和其他相关数据。

1.2 ☘️THREE.AnimationMixer 动画混合器

THREE.AnimationMixer动画混合器是用于场景中特定对象的动画的播放器。当场景中的多个对象独立动画时,每个对象都可以使用同一个动画混合器。
创建方法:
AnimationMixer( rootObject : Object3D )
rootObject 是 混合器播放的动画所属的对象
属性:
time:Number 全局的混合器时间(单位秒; 混合器创建的时刻记作0时刻)。
timeScale:全局时间(mixer time)的比例因子。
说明: 将混合器的时间比例设为0, 稍后再设置为1,可以暂停/取消暂停由该混合器控制的所有动作。
方法:
clipAction(clip : AnimationClip, optionalRoot : Object3D):AnimationAction 返回所传入的剪辑参数的AnimationAction, 根对象参数可选,默认值为混合器的默认根对象。第一个参数可以是动画剪辑(AnimationClip)对象或者动画剪辑的名称。
如果不存在符合传入的剪辑和根对象这两个参数的动作, 该方法将会创建一个。传入相同的参数多次调用将会返回同一个剪辑实例。
existingAction (clip : AnimationClip, optionalRoot : Object3D) : AnimationAction 返回传入剪辑的已有AnimationAction, 根对象参数可选,默认值为混合器的默认根对象。
第一个参数可以是动画剪辑(AnimationClip)对象或者动画剪辑的名称。
update (deltaTimeInSeconds : Number) : AnimationMixer 推进混合器时间并更新动画。
deltaTimeInSeconds 参数表示当前帧与前一帧之间的时间差(以秒为单位)。

二、🍀导入FBX格式骨骼绑定模型

1. ☘️实现思路

  • 1、初始化renderer渲染器
  • 2、初始化Scene三维场景
  • 3、初始化camera相机,定义相机位置 camera.position.set,设置相机方向camera.lookAt。
  • 4、初始化THREE.AmbientLight环境光源,scene场景加入环境光源,初始化THREE.PointLight平行光源,设置平行光源位置,设置平行光源投影,scene添加平行光源。
  • 5、加载几何模型:创建THREE.AxesHelper坐标辅助工具,创建THREE.PlaneBufferGeometry平面几何体、THREE.GridHelper地板割线,scene场景中加入创建的平面几何体和地板割线。创建gui控件datGui。通过THREE.FBXLoader类加载 ‘Samba Dancing…fbx’ 模型文件mesh,scene场景中加入mesh。在加载模型的回调函数中,参入mesh创建THREE.AnimationMixer 动画混合器,根据创建的动画混合器的动画片段获取AnimationAction动画调度器,播放动画。datGui加入动画控制。具体实现参考代码样例。
  • 6、加入controls、gui控制,加入stats监控器,监控帧数信息。

2. ☘️代码样例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>learn51(导入FBX格式骨骼绑定模型)</title>
    <script src="lib/threejs/127/three.js-master/build/three.js"></script>
    <script src="lib/threejs/127/three.js-master/examples/js/controls/OrbitControls.js"></script>
    <script src="lib/threejs/127/three.js-master/examples/js/loaders/FBXLoader.js"></script>
    <script src="lib/threejs/127/three.js-master/examples/js/libs/fflate.min.js"></script>
    <script src="lib/threejs/127/three.js-master/examples/js/libs/stats.min.js"></script>
    <script src="lib/threejs/127/three.js-master/examples/js/libs/dat.gui.min.js"></script>
    <script src="lib/js/Detector.js"></script>
</head>
<style type="text/css">
    html, body {
        margin: 0;
        height: 100%;
    }

    canvas {
        display: block;
    }

</style>
<body onload="draw()">
</body>
<script>
  var renderer, camera, scene, gui, light, stats, controls, meshHelper, mixer, action
  var clock = new THREE.Clock()
  var initRender = () => {
    renderer = new THREE.WebGLRenderer({antialias: true})
    renderer.setPixelRatio(window.devicePixelRatio)
    renderer.setSize(window.innerWidth, window.innerHeight)
    renderer.setClearColor(0xeeeeee)
    renderer.shadowMap.type = THREE.PCFSoftShadowMap
    renderer.shadowMap.enabled = true
    document.body.appendChild(renderer.domElement)
  }
  var initScene = () => {
    scene = new THREE.Scene()
    scene.background = new THREE.Color( 0xa0a0a0 )
    scene.fog = new THREE.Fog( 0xa0a0a0, 200, 1000 )
  }
  var initCamera = () => {
    camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 2000)
    camera.position.set(100, 200, 300)
  }
  var initGui = () => {
    gui = {
      animation: true,
      helper: true
    }
    var datGui = new dat.GUI()
    datGui.add(gui, 'animation').onChange(e => {
      if (e) {
        action.play()
      } else {
        action.stop()
      }
    })
    datGui.add(gui, 'helper').onChange(e => {
      meshHelper.visible = e
    })
  }
  var initLight = () => {
    scene.add(new THREE.AmbientLight(0x444444))
    light = new THREE.DirectionalLight(0xffffff)
    light.position.set(0, 200, 100)
    light.castShadow = true
    light.shadow.camera.top = 180
    light.shadow.camera.bottom = -100
    light.shadow.camera.left = -120
    light.shadow.camera.right = 120
    // light.shadow.camera.near = 20
    // light.shadow.camera.far = 200
    // light.shadow.mapSize.width = 1024
    // light.shadow.mapSize.height = 1024
    light.castShadow = true
    var debug = new THREE.CameraHelper(light.shadow.camera)
    debug.name = 'debug'
    // scene.add(debug)
    scene.add(light)
  }
  var initModel = () => {
    var helper = new THREE.AxesHelper(50)
    scene.add(helper)

    // 地板
    // var mesh = new THREE.Mesh(new THREE.PlaneBufferGeometry(2000, 2000), new THREE.MeshPhongMaterial({
    //   color: 0xffffff,
    //   depthWrite: false
    // }))
    // mesh.rotation.x = Math.PI / 2
    // mesh.position.y = -0
    // mesh.receiveShadow = true
    // scene.add(mesh)
    // 底面
    var planeGeometry = new THREE.PlaneBufferGeometry(2000, 2000)
    // var planeMatarial = new THREE.MeshStandardMaterial({color: 0xaaaaaa})
    var planeMatarial = new THREE.MeshPhongMaterial({
      color: 0xffffff,
      depthWrite: false
    })
    var plane = new THREE.Mesh(planeGeometry, planeMatarial)
    plane.rotation.x = -0.5 * Math.PI
    plane.position.y = -0
    plane.receiveShadow = true
    scene.add(plane)

    // 加载地板割线
    var grid = new THREE.GridHelper(2000, 20, 0x000000, 0x000000)
    grid.material.opacity = 0.2
    grid.material.transparent = true
    scene.add(grid)

    // 加载模型
    var loader = new THREE.FBXLoader()
    loader.load('data/model/SambaDancing/Samba Dancing.fbx', mesh => {
      meshHelper = new THREE.SkeletonHelper(mesh)
      scene.add(meshHelper)
      mesh.traverse(function (child) {
        if (child.isMesh) {
          child.castShadow = true
          child.receiveShadow = true
        }
      })
      // mesh.castShadow = true
      mixer = mesh.mixer = new THREE.AnimationMixer(mesh)
      action = mixer.clipAction(mesh.animations[0])
      action.play()
      scene.add(mesh)
    })
  }
  var initStats = () => {
    stats = new Stats()
    document.body.appendChild(stats.dom)
  }
  var initControls = () => {
    controls = new THREE.OrbitControls(camera, renderer.domElement)
    controls.enableDamping = true
    controls.target.set(0, 100, 0)
    //设置相机距离原点的最远距离
    controls.minDistance = 1
    //设置相机距离原点的最远距离
    controls.maxDistance = 2000
  }
  var render = () => {
    var time = clock.getDelta()
    if (mixer) {
      mixer.update(time)
    }
    controls.update()
  }
  var onWindowResize = () => {
    camera.aspect = window.innerWidth / window.innerHeight
    camera.updateProjectionMatrix()
    renderer.setSize(window.innerWidth, window.innerHeight)
  }
  var animate = () => {
    render()
    stats.update()
    renderer.render(scene, camera)
    requestAnimationFrame(animate)
  }
  var draw = () => {
    if (!Detector.webgl) Detector.addGetWebGLMessage()

    initGui()
    initRender()
    initScene()
    initCamera()
    initLight()
    initModel()
    initControls()
    initStats()

    animate()

    window.onresize = onWindowResize
  }
</script>
</html>

效果如下:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/920455.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【腾讯云产品最佳实践】腾讯云CVM入门技术与实践:通过腾讯云快速构建云上应用

目录 前言 什么是腾讯云CVM&#xff1f; 腾讯云CVM的技术优势 基于最佳技术实践&#xff0c;使用腾讯云CVM搭建应用 1. 开通CVM实例 2. 连接CVM实例 3. 配置Web环境 4. 部署PHP应用 腾讯云CVM行业应用案例&#xff1a;电商平台的双十一攻略 1. 弹性伸缩解决高并发问题…

mongodb多表查询,五个表查询

需求是这样的&#xff0c;而数据是从mysql导入进来的&#xff0c;由于mysql不支持数组类型的数据&#xff0c;所以有很多关联表。药剂里找药物&#xff0c;需要药剂与药物的关联表&#xff0c;然后再找药物表。从药物表里再找药物与成分关联表&#xff0c;最后再找成分表。 这里…

STL中vector实现——简单易懂版

本章内容 模拟实现 vector 的部分重要功能 1.迭代器的引入1.1 之前写法1.2 STL库中的写法 2.默认成员函数2.1构造与拷贝构造2.2拷贝赋值2.3析构函数 3.增删查改功能3.1插入3.2删除 4.为什么STL中vector没有find函数&#xff1f;5.&#x1f525;&#x1f525;迭代器失效场景&am…

Springboot + vue 健身房管理系统项目部署

1、前言 ​ 许多人在拿到 Spring Boot 项目的源码后&#xff0c;不知道如何运行。我以 Spring Boot Vue 健身房管理系统的部署为例&#xff0c;详细介绍一下部署流程。大多数 Spring Boot 项目都可以通过这种方式部署&#xff0c;希望能帮助到大家。 ​ 2、项目查看 ​ 首…

NuGet如何支持HTTP源

今天是2024年11月21号&#xff0c;最近更新了VisualStudio后发现HTTP的包源已经默认禁止使用了&#xff0c;生成时会直接报错。如下图&#xff1a; 官方也明确指出了要想使用HTTP包源的解决办法&#xff0c;这里就简单总结一下。 一、全局配置 1、全局NuGet包的配置文件路径在…

SpringBoot学习记录(四)之分页查询

SpringBoot学习记录&#xff08;四&#xff09;之分页查询 一、业务需求1、基本信息2、请求参数3、相应数据 二、传统方式分页三、使用PageHelper分页插件 一、业务需求 根据条件进行员工数据的条件分页查询 1、基本信息 请求路径&#xff1a; /emps 请求方式&#xff1a; …

JavaParser如何获取方法的返回类型

使用JavaParser 如何获取一个Java类中的某个方法的返回类型呢&#xff1f; 假如有一个如下的简单的Java 类&#xff1a; /*** Copyright (C) Oscar Chen(XM):* * Date: 2024-11-21* Author: XM*/ package com.osxm.ai.sdlc.codeparse.codesample;public class MyClass {public…

2024亚太杯国际赛C题宠物预测1234问完整解题思路代码+成品参考文章

中国宠物业发展趋势及预测模型 一、问题背景与研究目标 近年来&#xff0c;中国宠物业经历了快速发展&#xff0c;特别是在城市化进程加快、人口结构变化和消费水平提升的背景下&#xff0c;宠物作为家庭成员的角色变得愈发重要。根据相关数据&#xff0c;中国宠物数量&#…

Java实现离线身份证号码OCR识别

最近公司要求做离线身份证OCR功能&#xff0c;找了一圈总算是找到了&#xff0c;在这里对文档做个整理&#xff0c;方便后来者&#xff0c;感谢码龄23年博主的分享 系统&#xff1a;Windows11&#xff0c;红旗Linux Asianux8.1 文档中Linux全root用户操作&#xff1b;需先安装…

Gradle核心概念总结

这部分内容主要根据 Gradle 官方文档整理&#xff0c;做了对应的删减&#xff0c;主要保留比较重要的部分&#xff0c;不涉及实战&#xff0c;主要是一些重要概念的介绍。 Gradle 这部分内容属于可选内容&#xff0c;可以根据自身需求决定是否学习&#xff0c;目前国内还是使用…

鸿蒙网络编程系列50-仓颉版TCP回声服务器示例

1. TCP服务端简介 TCP服务端是基于TCP协议构建的一种网络服务模式&#xff0c;它为HTTP&#xff08;超文本传输协议&#xff09;、SMTP&#xff08;简单邮件传输协议&#xff09;等高层协议的应用程序提供了可靠的底层支持。在TCP服务端中&#xff0c;服务器启动后会监听一个或…

第5-1节:SpringBoot对SpringMVC的自动配置

我的后端学习大纲 SpringBoot学习大纲 1、SpringBoot对SpringMVC自动配置概览

Emacs进阶之插入时间信息(一百六十三)

简介&#xff1a; CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布&#xff1a;《Android系统多媒体进阶实战》&#x1f680; 优质专栏&#xff1a; Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a; 多媒体系统工程师系列【…

嵌入式实验报告:家用计时器

实验目的和要求 1、实验目的 掌握STM32串口通信原理。学习编程实现STM32的UART通信掌握STM32中断程序设计流程。熟悉STM32固件库的基本使用。熟悉STM32定时器中断设计流程。2、实验要求 设计一个家用计时器,其功能如下: 利用串口设置计时时间,格式:XX:XX:X 例如01:59:…

【WRF理论第十二期】Registry.EM 文件详解

【WRF理论第十二期】Registry.EM 文件详解 Registry.EM 文件的作用Registry.EM 文件的结构Registry.EM 文件内容理解如何修改 Registry.EM 文件以输出特定变量WRF-Urban 修改 Registry.EM 文件以输出 UCM 相关变量1. 修改 Registry.EM 文件2. 重新编译 WRF 注意事项参考 在 WRF…

Midjourney 图生图,真人二次元保持一致性,场景多元可选择

Midjourney 拥有强大的图生图的功能&#xff0c;下面我们就来看一下&#xff0c;如何在我们的AceDataCloud网站上实现将照片切换成任意的二次元场景&#xff0c;同时保持人物的一致性。 我们可以按照如下的步骤去实现人物一致性。 下面我们来看看效果吧&#xff0c;原图如下。…

三种复制只有阅读权限的飞书网络文档的方法

大家都知道&#xff0c;飞书是一款功能强大的在线协作工具&#xff0c;可以帮助团队更高效地协作和沟通。越来越多的资料都在使用飞书文档&#xff0c;在使用飞书的过程中&#xff0c;发现很多文档没有复制权限&#xff0c;如果想要摘抄笔记&#xff0c;只能一个字一个字地敲出…

【GL003】TCP/IP 协议

目录 一、TCP/IP协议简介 二、TCP/IP协议的分层模型 2.1 OSI模型的七层框架 2.2 TCP/IP协议层&#xff08;四层&#xff09; 2.2.1 TCP/IP协议层与ISO模型 2.2.2 TCP/IP协议层的作用 三、TCP协议的报文格式 3.1 什么是报文 3.2 TCP报文 四、TCP的通信连接 4.1 TCP…

Spring WebFlux学习笔记(二)

目标 运行第一个spring webflux项目 官网操作 https://start.spring.io/ 依赖、工具 jdk 21、idea、maven 运行过程 将下载的代码直接导入到idea后运行 运行上个笔记的例子 注意 需要更改为MediaType.TEXT_EVENT_STREAM_VALUE 未完待续。。。

【YOLOv8】安卓端部署-2-项目实战

文章目录 1 准备Android项目文件1.1 解压文件1.2 放置ncnn模型文件1.3 放置ncnn和opencv的android文件1.4 修改CMakeLists.txt文件 2 手机连接电脑并编译软件2.1 编译软件2.2 更新配置及布局2.3 编译2.4 连接手机 3 自己数据集训练模型的部署4 参考 1 准备Android项目文件 1.1…