この記事は、Three.js Advent Calendar 2019 20日目の記事です。
AnimationMixerが扱いづらい
Three.js内でglTFなどを読み込んでアニメーションさせる場合、AnimationMixerを使用して徐々にモーションが変わるようにするには以下のようなコードを書くことになります。
const loader = new THREE.GLTFLoader();
loader.load('assets/zensuke.gltf', (gltf) {
scene.add(gltf.scene)
const mixer = new THREE.AnimationMixer(gltf.scene)
const actionA = mixer.clipAction(gltf.animations[0])
const actionB = mixer.clipAction(gltf.animations[1])
let actionAWeight = 0
let actionBWeight = 1
mixer.play()
function tick() {
requestAnimationFrame(tick);
// ↓適当です。AとBのWeightが入替わるような処理
actionAWeight += 0.01
actionBWeight -= 0.01
// ...省略...
actionA.setEffectiveWeight(actionAWeight)
actionB.setEffectiveWeight(actionBWeight)
renderer.render(scene, camera);
}
})
各Actionのweightを調整するために冗長でとてもわかりにくいコードに仕上がりました。厳密にweightのバリデーションを追加するともっと複雑になります。
もっと簡潔にアニメーションを切り替えたい
上のような面倒をしなくてもなめらかにモーションが切り替わってくれるだけでいいので、以下の3点だけ指定すればアニメーションが切り替わるようなツールが欲しい。。。
- 次のアニメーション名
- 切り替わりにかかる時間
- ループするかどうか
また作ってみました
ということで utsuroi
というツールを作ってみました。
簡単な使用例
import { Manipulator } from 'utsuroi'
let manipulator;
// Load asset
var loader = new THREE.GLTFLoader();
loader.load('assets/model.gltf', (gltf) {
scene.add(gltf.scene)
// アニメーションの操作者を作成
manipulator = new Manipulator(gltf.scene, gltf.animations);
// 初期状態として再生したいアニメーション名を指定
manipulator.play('Rest Pose', true);
});
毎フレームに update
メソッドを実行することを忘れないでください
function tick() {
requestAnimationFrame(tick);
manipulator.update(); // これをしないとweightの更新がされない
}
tick();
アニメーションを切り替える
glTFに含まれているアニメーション名を指定することで切り替えられます
// manipulator.to('アニメーション名', 切り替えにかかる時間ms, ループするか否か);
manipulator.to('Walk', 200, true);
アニメーションを止める
manipulator.pause();
ちなみにBlenderからglTF書き出した時の設定はは以下になります。NLAスタックに登録がされていないと gltf.animations
にアニメーション情報が入ってこないので注意です。
まとめ
とてもシンプルになり簡単に切り替えが可能になりました。アニメーションに特にこだわりが無い方や、とりあえずアニメーションを確認したい方におすすめです。ぜひ使ってみてください