承接上文,本文讲述如何在Threejs里播放对象的多个动画,这也是研究了很久才解决的…
一 导出模型
在Blender里按照File->Export,选择glTF2.0
然后在弹框的右上角选择导出为glTF Embedded (.gltf)
这样就把模型导出来了,该模型里包含了2个动画。
二 Threejs样例
Threejs的安装本文不会描述,可以参考官方文档,比较简单。
main.js内容如下,
import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { GUI } from 'lil-gui'
const scene = new THREE.Scene();
scene.background = new THREE.Color(0xffffff );
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1e-5, 1e10 );
camera.position.set(0, 15, 30);
var ambient = new THREE.AmbientLight(0xffffff);
scene.add(ambient);
const renderer = new THREE.WebGLRenderer({ antialias: true, logarithmicDepthBuffer: true });
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setPixelRatio(window.devicePixelRatio);
renderer.outputColorSpace = THREE.SRGBColorSpace;
document.body.appendChild( renderer.domElement );
const loader = new GLTFLoader();
const dracoLoader = new DRACOLoader();
loader.setDRACOLoader(dracoLoader);
let modelReady = false;
let gltfscene;
let horsevisible = false;
let mixer;
let actions;
loader.load(
'/models/33.gltf',
function (gltf) {
gltfscene = gltf.scene;
scene.add(gltfscene);
console.log(gltf.animations);
mixer = new THREE.AnimationMixer(gltf.scene);
let Action1 = mixer.clipAction( gltf.animations[0] );
let Action2 = mixer.clipAction( gltf.animations[1] );
actions = [Action1, Action2];
modelReady = true;
},
function(xhr) {
console.log((xhr.loaded / xhr.total * 100) + '% loaded');
},
function (error) {
console.log('An error happened.');
}
)
const obj = {
myFunction: function () {
if (horsevisible == false)
{
actions[0].clampWhenFinished = true;
actions[0].setLoop(THREE.LoopOnce);
actions[0].play();
actions[1].stop(); // 非常关键
}
else
{
actions[1].clampWhenFinished = true;
actions[1].setLoop(THREE.LoopOnce);
actions[1].play();
actions[0].stop(); // 非常关键
}
horsevisible = !horsevisible;
}
}
const gui = new GUI()
gui.add(obj, 'myFunction'); // 按钮
const grid = new THREE.GridHelper( 2000, 20, 0x000000, 0x000000 );
grid.material.opacity = 0.3;
grid.material.transparent = true;
scene.add( grid );
const controls = new OrbitControls(camera, renderer.domElement);
controls.update();
const clock = new THREE.Clock();
function animate() {
requestAnimationFrame( animate );
if (modelReady)
{
mixer.update(clock.getDelta());
}
controls.update();
renderer.render( scene, camera );
}
animate();
然后运行npx vite
来启动server,打印如下,
然后在浏览器里打开这个地址,显示如下,
然后点击myFunction按钮,可以看到这个立方体会移动到右边,再次点击myFunction按钮,立方体又会移到中间。
代码里关键点是myFunction对应的回调函数,因为动画的默认参数会重复执行这个动画,这里把clampWhenFinished设置为true,并把loop设置为THREE.LoopOnce,然后调用play(),这样可以保证这个动画只执行一次。
最后一定要执行一下另外一个动画的stop()函数,这样可以保证另外动画的正确执行,否则会出现位置不正确的情况。
三 总结
本文讲述了如何在Threejs里播放同一对象的多个动画。关键点有2个,
- 设置动画只执行一次
- 调用下一个动画的stop()函数来保证下一个动画可以正确执行。