【threejs】实现不同动画的播放和平滑切换
关键代码
主要是通过 修改动作的速度和幅度达到平滑切换
action.setEffectiveTimeScale(1);
action.setEffectiveWeight(weight);//0-1
要用到的工具 ,一个简易的动画class Anim
代码点击下方链接获取
开箱即用,无需安装
加载模型并创建mixer和actions
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
import { AnimationMixer, Clock } from "three";
//前置条件
this.actions = []
this.clock = new Clock()
this.mixer = null
this.currentAct = "idle"
this.weights = {
idle: 1,
walk: 0,
run: 0,
workOnDevice: 0,
waving: 0
}
//加载带动画的模型
let url = `/static/threeResources/models/cyberPerson.glb`
let loader = new GLTFLoader()
loader.load(url, (gltf) => {
let animations = gltf.animations
let model = gltf.scene
this.add(model)//加入场景
let mixer = new AnimationMixer(model)
//创建mixer和action
let actions = []
for (let i = 0; i < animations.length; i++) {
let animation = animations[i]
let name = animation.name
let action = mixer.clipAction(animation);
// let animationName = animation.name
Object.assign(action, { name })//这里标记名称方便后面切换动画查找
actions.push(action)
}
this.actions = actions
this.mixer = mixer
this._mesh = model
this.modelUrl = ""
this.activateAllActions()
console.log(mixer, actions);
})
//激活所有动画轨道
activateAllActions() {
let { actions, weights } = this
for (let i = 0; i < actions.length; i++) {
let action = actions[i]
let name = action.name//这里是上面加载后添加了name信息,原生action没有这个属性
console.log(name, weights[name]);
if (weights[name]) {
this.setWeight(action, weights[name])
} else {
this.setWeight(action, 0)
}
action.play();
}
}
activateAllActions()
setWeight(action, weight) {
action.enabled = true;
action.setEffectiveTimeScale(1);
action.setEffectiveWeight(weight);
}
//使用刚才备注的名称可以平滑切换动画
/**
主要是通过
action.setEffectiveTimeScale(1);
action.setEffectiveWeight(weight);
修改动作的速度和幅度达到平滑切换
*/
setAnimate(animate = 'idle') {
let { weights, actions } = this
let nWeights = {
idle: 0,
walk: 0,
run: 0,
workOnDevice: 0,
waving: 0
}
for (let k in nWeights) {
if (k == animate) {
nWeights[k] = 1
}
}
console.log(nWeights);
let anim = new Anim(weights, nWeights, {
duration: 750,
easingFunction: Anim.linear,
onUpdate: (_weights) => {
for (let i = 0; i < actions.length; i++) {
let action = actions[i]
let name = action.name
if (_weights[name]) {
this.setWeight(action, _weights[name])
} else {
this.setWeight(action, 0)
}
}
},
onComplete: () => {
this.weights = nWeights
}
})
anim.start()
}
//这个函数在更新renderer的时候执行,一般用requestAnimationFrame(){
//}循环调用
_render(t) {
let mixerUpdateDelta = this.clock.getDelta();
this.mixer.update(mixerUpdateDelta);
}