在Blender里给对象添加了一个动画后,假设是在帧1到帧40添加的动画帧,那么正常播放时是从帧1到帧40,反向播放则是从帧40到帧1,本文讲述如何在Threejs里方向播放Blender里添加的动画。
一 添加动画
之前文章中已经讲述如何在Blender里添加多个动画,这里只需要添加一个动画。
首先在Blender里添加2个立方体,然后通过添加材质(Material)来让他们有不同的颜色,
1. 添加材质
材质添加步骤如下,
点击New后在新界面里点击Base Color来修改材质颜色,
最后结果如下,一个蓝色,一个红色
2. 添加动画
在之前的文章中讲解了如何添加动画,这里添加的动画如下,
- 蓝色立方体: 帧1 (x:0, y:0, z:0) —> 帧40 (x:5, y:0, z:0)
- 红色立方体: 帧1 (x:0, y:5, z:0) —> 帧40 (x:-5, y:5, z:0)
注意,这2个立方体y的位置不一样,这样才能把他们分开,不然会重叠在一起
添加好之后,把模型导出,格式为glTF 2.0,名字为cube_reverse_play.gltf
二 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 );
window.addEventListener( 'resize', onWindowResize );
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/cube_reverse_play.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 = {
normal: function() {
playAnimationNoamal(actions[0]);
playAnimationNoamal(actions[1]);
},
reverse: function() {
playAnimationReverse(actions[0]);
playAnimationReverse(actions[1]);
}
}
function playAnimationNoamal(targetAnimation) {
targetAnimation.paused = false;
targetAnimation.timeScale = 1;
targetAnimation.clampWhenFinished = true;
targetAnimation.setLoop(THREE.LoopOnce);
targetAnimation.play();
}
function playAnimationReverse(targetAnimation) {
targetAnimation.paused = false;
targetAnimation.timeScale = -1;
targetAnimation.clampWhenFinished = true;
targetAnimation.setLoop(THREE.LoopOnce);
targetAnimation.play();
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
// 添加正向和反向播放的按钮
const gui = new GUI()
gui.add(obj, 'normal');
gui.add(obj, 'reverse');
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();
代码里的关键点有3个,
- 设置动画执行一次
- 正向播放把timeScale属性设置为1,这个也是默认值,不设置也行
- 反向播放把timeScale属性设置为-1
执行npx vite
后,在浏览器里打开地址,显示如下,
点击normal按钮,可以看到动画开始播放,从帧1到帧40,然后再点击reverse,就会从帧40播放到帧1
三 总结
本文讲述了如何在Threejs里反向播放Blender里添加的动画。
另外欢迎大家关注本人的微信公众号,文章会同步更新到公众号里。