当前位置: 首页 > news >正文

解决用Three.js实现嘴型和语音同步时只能播放部分部位的问题 Three.js同时渲染播放多个组件变形动画的方法

前言

参考这篇文章ThreeJS+ChatGPT 实现前端3D数字人AI互动,前面搭后端、训练模型组内小伙伴都没有什么问题,到前端的时候,脸部就出问题了。看我是怎么解决的。

好文章啊,可惜百度前几个都找不到,o(╥﹏╥)o

问题情况

展示到页面上,是这么个效果(模型动作有夸大部分):

这样的:

《眉飞色舞》

这样的:

《流连赏目》

这样:

《目无全牛》

这样:

眼角:我不感动

以及这样:

嘴巴:该配合你演出的我演视而不见

很明显,这整个脸就没打算一起好好动。

解决方法

原因

出现这个问题,是因为你的网格分开了,但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) {// 这里混合器只混合了一个meshconst 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互动

(偷偷告诉你,这种开源社区大佬的实现项目,不是一般人能随便搜到的哦)

相关文章:

  • MATLAB画图时添加标注显示有效数字的位数,可以编辑此函数
  • 使用Kotlin编写一个Http服务器
  • MEMS:Lecture 19 Wafer bonding package
  • Vue 3 中的状态管理:使用 reactive 函数实现组件间通信和状态管理
  • Flutter 应用加速之本地缓存管理
  • zookeeper、kakfa添加用户加密
  • k8s基础命令集合
  • Wake Lock API:保持设备唤醒的利器
  • Oracle阅读Java帮助文档
  • Pytorch-Padding Layers
  • 【定义通讯数据类型】LCM搭建系统通讯
  • 重温react-01
  • Mongodb学习
  • Nginx之HTTP模块详解
  • 【LeetCode 5.】 最长回文子串
  • [分享]iOS开发-关于在xcode中引用文件夹右边出现问号的解决办法
  • 2017届校招提前批面试回顾
  • css选择器
  • JavaScript 无符号位移运算符 三个大于号 的使用方法
  • JavaScript-Array类型
  • Java比较器对数组,集合排序
  • RxJS: 简单入门
  • VUE es6技巧写法(持续更新中~~~)
  • 更好理解的面向对象的Javascript 1 —— 动态类型和多态
  • 构造函数(constructor)与原型链(prototype)关系
  • 使用前端开发工具包WijmoJS - 创建自定义DropDownTree控件(包含源代码)
  • 学习JavaScript数据结构与算法 — 树
  • MiKTeX could not find the script engine ‘perl.exe‘ which is required to execute ‘latexmk‘.
  • ​secrets --- 生成管理密码的安全随机数​
  • #07【面试问题整理】嵌入式软件工程师
  • #include到底该写在哪
  • #Ubuntu(修改root信息)
  • #面试系列-腾讯后端一面
  • (27)4.8 习题课
  • (42)STM32——LCD显示屏实验笔记
  • (第8天)保姆级 PL/SQL Developer 安装与配置
  • (二)基于wpr_simulation 的Ros机器人运动控制,gazebo仿真
  • (附源码)springboot 校园学生兼职系统 毕业设计 742122
  • (全部习题答案)研究生英语读写教程基础级教师用书PDF|| 研究生英语读写教程提高级教师用书PDF
  • (十六)视图变换 正交投影 透视投影
  • (十七)devops持续集成开发——使用jenkins流水线pipeline方式发布一个微服务项目
  • (详细文档!)javaswing图书管理系统+mysql数据库
  • (转) Face-Resources
  • (自用)仿写程序
  • .NET 2.0中新增的一些TryGet,TryParse等方法
  • .net 按比例显示图片的缩略图
  • .NET(C#) Internals: as a developer, .net framework in my eyes
  • .Net7 环境安装配置
  • .net和php怎么连接,php和apache之间如何连接
  • .net开发日常笔记(持续更新)
  • .net快速开发框架源码分享
  • .NET委托:一个关于C#的睡前故事
  • .Net中ListT 泛型转成DataTable、DataSet
  • .NET中的Event与Delegates,从Publisher到Subscriber的衔接!
  • ?