前言
参考这篇文章ThreeJS+ChatGPT 实现前端3D数字人AI互动,前面搭后端、训练模型组内小伙伴都没有什么问题,到前端的时候,脸部就出问题了。看我是怎么解决的。
问题情况
展示到页面上,是这么个效果(模型动作有夸大部分):
这样的:
这样的:
这样:
这样:
以及这样:
很明显,这整个脸就没打算一起好好动。
解决方法
原因
出现这个问题,是因为你的网格分开了,但Threejs的混合器AnimationMixer创建一次只能混合一个网格Mesh。
这样子写,一次就只能混合其中一个Mesh:
... // 省略了很多地方,只列出了关键的细节
loader.load('path/to/your/model.gltf', function(gltf) {
const model = gltf.scene;
scene.add(model);
model.traverse(o => {
...
if(o.isMesh) {
...
if (o.morphTargetDictionary) {
// 这里混合器只混合了一个mesh
const mixer = new THREE.AnimationMixer(o);
...
}
}
}
}
...
const clip = getAnimationClip(msg); // 调用参考文章中得到动画的方法
let action = mixer.clipAction(clip); // 此时此刻也只有一个mixer的动画
action.play(); // 播放动画
function animate() {
mixer.update(0.016); // 更新动画混合器
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();
其实得一个Mesh一个混合器,最后把所有混合器都播放好。这样就能实现脸部的协调啦~
代码示例
const mixers = [] // 先准备好一个数组,存放mixer们
...
loader.load('path/to/your/model.gltf', function(gltf) {
const model = gltf.scene;
scene.add(model);
model.traverse(o => {
...
if(o.isMesh) {
...
if (o.morphTargetDictionary) {
// 不再只混合一个了
// const mixer = new THREE.AnimationMixer(o);
// 这里把混合了其中一个mesh的混合器给push进数组了
mixers.push(new THREE.AnimationMixer(o));
...
}
}
}
}
...
const clip = getAnimationClip(msg); // 调用参考文章中得到动画切片帧的方法
// 播放动画也不能只用一个的了
// let action = mixer.clipAction(clip);
// action.play();
for(let i = 0; i < mixers.length; i++) {
let action = mixers[i].clipAction(clip); //所有mixer都生成对应的动作
action.play(); // 动画全都给播放了
}
function animate() {
// 这里也记得都要播放哦
// mixer.update(0.016);
for(let i = 0; i < mixers.length; i++) {
mixers[i].update(0.016); // 更新全部动画混合器
}
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();
效果展示
当当当当!~
不好意思,搞错了,再来:
效果还不错的赶脚~
后记
网上这方面的资料太少了,这次真就是自己在脑子里构思一个个方案,做出一小步一小步的修改,最终给我试出来是这个毛病了……不容易啊不容易(o(╥﹏╥)o)
希望本文能给其他用Threejs的小伙伴带来帮助,不要放下你敲代码的热情,总有前人在为你们探路中~(✿◠‿◠)
参考
ThreeJS+ChatGPT 实现前端3D数字人AI互动
(偷偷告诉你,这种开源社区大佬的实现项目,不是一般人能随便搜到的哦)