
首先需要在blender中创建骨骼动画,并且导出glb格式文件。

然后将模型导入到threejs中,在控制台查看文件,可以找到非常重要的两个部分。animations存放骨骼动画,scene.children存放的是模型。需要找到这两部分才能播放骨骼动画。

代码如下:
import * as THREE from 'three'; import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; // 用于解压压缩文件 import {DRACOLoader} from 'three/examples/jsm/loaders/DRACOLoader.js'; const clock=new THREE.Clock() // 创建场景 const scene = new THREE.Scene(); // 场景加入坐标 scene.add(new THREE.AxesHelper(2,2,2)) // 透视相机(PerspectiveCamera) // 创建相机,视角为75°,宽高比为浏览器窗口,最近0.1,最远1000 const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 ); // 相机位置 camera.position.set(0, 0, 30) // 相机对准原点 camera.lookAt(0, 0, 0) scene.add(new THREE.AmbientLight(0xadadad)) // 添加点光源 const light=new THREE.DirectionalLight(0xffffff,10) light.position.set(10,10,10) light.castShadow=true const helper = new THREE.DirectionalLightHelper( light, 5 ) scene.add( helper ) scene.add(light) // 创建渲染器,设置渲染器透明 const renderer = new THREE.WebGLRenderer({alpha:true}); // 设置渲染器以RGB格式进行渲染 renderer.outputEncoding=THREE.sRGBEncoding renderer.toneMapping=THREE.ACESFilmicToneMapping // 设置渲染器的曝光程度,曝光低,夜晚效果 renderer.toneMappingExposure=0.2 // 设置渲染器可以渲染阴影 renderer.shadowMap.enabled=true // 设置渲染器窗口的大小 renderer.setSize( window.innerWidth, window.innerHeight ); // 设置像素比,让渲染器使用和浏览器一样的像素比 renderer.setPixelRatio(Math.min(window.devicePixelRatio,2)) // 设置场景颜色 renderer.setClearColor(new THREE.Color(0x000000),1) // 把渲染内容添加到页面上 document.body.appendChild( renderer.domElement ); //添加鼠标交互需要传入相机和canvas参数 const orbitControls = new OrbitControls(camera,renderer.domElement) // 设置控制器阻尼 orbitControls.enableDamping=true // blender导出使用压缩后的文件需要解压 const dracoloader=new DRACOLoader() // 设置如何解压方式的路径。将/three/examples/jsm/libs/draco/文件夹复制到public文件夹下 dracoloader.setDecoderPath("./public/draco/") // 创建gltf加载器 const loader=new GLTFLoader() // 将设置好的解压器传给gltf加载器 loader.setDRACOLoader(dracoloader) loader.load('public/renou.glb',(gltf)=>{ scene.add(gltf.scene) gltf.scene.traverse((child)=>{ if(child.name.includes('骨架')){ // 加入动画混合器 mixer=new THREE.AnimationMixer(child) // 定义动作片段 let clip // 将动画赋值给动作片段 clip=gltf.animations[0] // 动画混合器加入动画片段 const action=mixer.clipAction(clip) // 播放动画 action.play() } }) }) let mixer function animate() { orbitControls.update() const time=clock.getDelta() // 更新动画混合器 if(mixer){ mixer.update(time) } helper.update() renderer.render( scene, camera ) requestAnimationFrame( animate ) } animate();