👨⚕️ 主页: gis分享者
👨⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅!
文章目录
- 一、🍀前言
-
- [1.1 ☘️THREE.FBXLoader fbx 模型加载插件](#1.1 ☘️THREE.FBXLoader fbx 模型加载插件)
- [1.2 ☘️THREE.AnimationMixer 动画混合器](#1.2 ☘️THREE.AnimationMixer 动画混合器)
- 二、🍀导入FBX格式骨骼绑定模型
-
- [1. ☘️实现思路](#1. ☘️实现思路)
- [2. ☘️代码样例](#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. ☘️代码样例
html
<!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>
效果如下: