前言
先看看这张图,那是在2023年以ChatGPT为首的AI技术开始火爆互联网的时候,我们做过的一个AI技术应用场景探索,回头发现很多设想都已经在市面上实现并产品化了。那时我很想把虚拟小助手应用里面的智城IP小Z做出来,实现一个立体的、有动作的形象, 苦于当时能力没能投入。时隔1年多,AI能力又有了许多涌现,除了最初的语言大模型,AI在生成图像和生成3D模型方面有非常大的能力提升,甚至已经可以辅助把这个立体生活的角色形象实现,我觉得是时候动手了。
经过这几天的摸索,终于实现了在网页上展示小Z的3D形象,并控制它做出各种指定动作,下面我来有所侧重地分享整个工作流程。
实现思路
- 设计小Z的形象轮廓,提供正面、侧面、背面三视图
- 使用SD生成质感的角色图
- 角色建模,可以人工建模也可以AI辅助生成
- 模型骨骼绑定,在动作库挑选动作合并入模型
- 使用three.js调用模型
使用工具
工具 | 版本 | 说明 |
---|---|---|
illustrator | 2020 | 角色线稿绘制 |
StableDiffusion | 简称SD,AI生图工具,可以根据线框图,生成立体的、有质感的角色图片 | |
blender | 4.2 | 角色建模,绑定骨骼,添加动作 |
autoRig | 3.70 | blender插件,用于自动绑定骨骼,生成姿态控制器 |
quad remesher | 1.2 | blender插件,模型的网格优化工具(非必须) |
mixamo | Adobe官方的3D角色动画工具网站,可以提供各种各样的角色姿态和动作 | |
wander3D | AI工具,1张图片生成高质量3D模型(非必须) | |
three.js | 0.157 | 经典的前端3d引擎,用于加载和控制模型 |
具体步骤
-
设计小Z的形象轮廓,提供正面、侧面、背面三视图,设计的时候需要注意各个身体部件在后面的步骤里能够实现。这里我就踩了一个坑,小Z最初是形象一个章鱼腿,后来在建模的时候发现做成手办会站不稳,才在第二版改成了阿童木的靴子腿。
-
将正面图片导入StableDiffusion,使用插件ControlNet辅助生成质感的角色图,网上已经有很多教程了,这里碍于篇幅就不赘述,AI生图的诀窍就是要耐心、且不断调整提示词抽卡和局部重绘,最终达到理想的效果。
-
根据三视图对小Z角色进行建模,如果不会建模可以用Wander3D,本文的示例模型是我曾经的好同事刘睿博帮忙创建的,他还顺便帮我用3D打印机把模型打印出来了(他哭死,我真的),这里着重表扬他。
-
将模型导入blender,可以用quad remesher进行网格优化,再进行稍微的调整、UV帖图
-
贴图,最省事的做法是使用视角投影贴图。模型朝向正面,全选顶点后按U,选择"从视角投影",但是这样的话贴图会直接映射在正面和背面模型上,不适合会展示到背面的场景。拆分组件后各自UV贴图,虽然费时间,但产出的模型精细化程度高;需要注意的是组件接缝处如果面没没有封闭好,可能会因为做动作出现破面的问题,可以适当把关节对接处延长。
-
使用autoRig进行骨骼自动绑定,导出FBX格式的文件备用,这里看后面小技巧部分。
-
打开mixamo,上传FBX文件成功后,即可选择并下载各种姿态动作。我们只需要下载一个蒙皮的动作,其余的动作全部选择不带皮的就可以了,这样文件体积更小容易下载成功。
-
使用blender合并动作到一个模型上,并导出模型文件FBX或gltf,使用系统自带的3D查看器就可以看到动作被合成进来,具体教程可以看参考链接。
-
使用three.js调用模型,核心操作就是加载模型和控制动作切换两个,源代码我放在这里了
jsx// 加载模型 import { FBXLoader } from 'three/addons/loaders/FBXLoader.js'; const loader = new FBXLoader(); loader.load("../static/gltf/xiaoz.fbx", function ( object ) { const size = 0.05 object.scale.set(size, size, size); // const index = object.children.findIndex(v=>v.name=="Light") object.children.splice(index, 1) object.children.forEach(element => { const {material ,name } = element if(['Retopo_ball','Retopo_face'].includes(name)){ const material = element.material material.transparent = false } }); scene.add( object ); createGUI(object, object.animations) } ); function createGUI(model, animations) { const states = animations.map(v=>{ return v.name }); gui = new GUI(); mixer = new THREE.AnimationMixer(model); actions = {}; for (let i = 0; i < animations.length; i++) { const clip = animations[i]; const action = mixer.clipAction(clip); actions[clip.name] = action; } const statesFolder = gui.addFolder("States"); const clipCtrl = statesFolder.add(api, "state").options(states); clipCtrl.onChange(function () { fadeToAction(api.state, 0.5); }); statesFolder.open(); activeAction = actions[states[0]]; activeAction.play(); } /** * @description 切换动作 * @param name {String} 动作名 * @param duration {Number} 切换过渡时间 */ function fadeToAction(name, duration) { previousAction = activeAction; activeAction = actions[name]; if (previousAction !== activeAction) { previousAction.fadeOut(duration); } activeAction .reset() .setEffectiveTimeScale(1) .setEffectiveWeight(1) .fadeIn(duration) .play(); }
-
页面实现的效果如下图
小技巧
在绑定骨骼时如何创建镜像
-
选择想要复制镜像的骨骼,修改骨骼中各关节的命名,注意目前是在人体的右边,所以命名以R.开头,比如R.hand如下图所示。否则无法正常生成对称的骨骼。
-
在编辑模式下,再次选择骨骼,点击左上角"骨架 - 对称",即可直接生成镜像,且骨骼会自动以L.为开头命名
如何使用autoRig绑定骨骼
-
安装插件auto-rig-pro,选择所有模型相关Mesh,点击Auto-Rig Rro:Smart 折叠项,展开后点击 "Get Selected Objects"。此时将模型朝向正面,根据控制面板按钮提示选择模型的关键节点(Neck、Chin、Spine root等)后就能自动生成骨骼,调整好骨骼以适应当前的模型。
-
回到最初的Atuo-Rig Pro折叠项,点击Match To Ring,此时就会生成一堆姿态控制器
-
打开在"蒙皮"TAB,点击其中的"绑定"按钮,此时就会自动将骨骼与模型绑定。选中某个控制器,R可以控制旋转,G可以移动位置,S可以进行缩放,Alt+G可以重置位置移动,以此类推。
如何让模型表面更光滑有质感
-
使用blender,在物体模式下,选中模型,右键平滑着色
-
在编辑材质的时候,设置"材质属性-表面曲面 - 光泽BSDF"
创建姿态资产
-
blender 4.0+版本姿态库有所变化,创建资产需要在"动画摄影表"等其他栏目中才能打开。
-
切换到"资产管理器"栏目 可以对资产进行重命名、截图等编辑操作。
-
所有的姿态可以是共存关系,比如姿态A设置了脸部表情,姿态B设置了动作,那么就可以点击姿态A和姿态B将脸部表情和动作结合起来。
-
我们还可以预览2个姿态直渐的动作过渡。在姿态资产选中默认姿态A,在主场景选中会发生动作的几个控制器,然后将鼠标按住目标姿态B,然后拖动鼠标,此时就会出现两个姿态之间的切换动画,顶部还有进度条。
写在最后
至此让小Z从二维平面走入三次元,动起来的这一步实现了,这里面仍有许多需要完善的地方,比如模型做动作时不时出现的穿模和破面等情况,如何给小Z加上脸部表情,实现表情与动作的组合等等。
然而这不是终点,最终的目标是让小Z模型成为一个被调用的前端模块,结合我们的企业AI聊天助手同步各种动作姿态;而在宣传层面,我们可以把小Z的姿态和动作库完善起来,作为各种周边产品的视觉物料,或者形成各种短视频动画,当然这些工作量很大,都需要其他伙伴的参与了。