4.4 动画:CPU 改矩阵 vs GPU 蒙皮


文档摘要

4.4 动画:CPU 改矩阵 vs GPU 蒙皮 本节摘要:物体整体旋转平移,CPU 改模型矩阵再上传 Uniform,顶点仓库不动。角色皮肤要随骨骼弯,每顶点不同变换:要么 CPU 把变形后的位置写入 VBO(每帧 STREAM),要么把骨骼矩阵和权重交给 GPU,顶点着色器做蒙皮乘法。变形目标同理。交互(指针拾取、轨道相机)发生在 CPU,结果仍应尽量变成矩阵或少量 Uniform,而不是每帧重建网格。

4.4 动画:CPU 改矩阵 vs GPU 蒙皮

本节摘要:物体整体旋转平移,CPU 改模型矩阵再上传 Uniform,顶点仓库不动。角色皮肤要随骨骼弯,每顶点不同变换:要么 CPU 把变形后的位置写入 VBO(每帧 STREAM),要么把骨骼矩阵和权重交给 GPU,顶点着色器做蒙皮乘法。变形目标同理。交互(指针拾取、轨道相机)发生在 CPU,结果仍应尽量变成矩阵或少量 Uniform,而不是每帧重建网格。

本节导读

阅读完本节,你应当能够:

  1. 区分物体级运动、骨骼蒙皮、变形目标三种粒度
  2. 对照 CPU 蒙皮写回 VBO 与 GPU 蒙皮的带宽账单
  3. 说明权重 Attribute 与骨骼矩阵 Uniform 数组或矩阵纹理的搭配
  4. 指出相机动画只改视图矩阵,不应改网格
  5. 给出拾取用 CPU 射线还是 GPU 颜色 ID 的对照

动的是矩阵还是顶点

立方体转,八个顶点相对关系不变,变的是 M。CPU 每帧写 16 个 float。角色抬手,肩附近顶点走一套矩阵,手指另一套,顶点仓库的“绑定姿势”仍在,但每顶点要混合四根骨。若 CPU 做混合再 bufferSubData 整网位置与法线,上传按顶点数涨。GPU 蒙皮让 VS 读权重与骨矩阵,位置仓 STATIC。动画越复杂,越该把乘法搬进 VS。

变形目标(blend shape):CPU 可以混合目标网格再上传,也可以把差量当 Attribute,VS 用系数加权。面部动画常用后者。系数是少量 Uniform,差量是静态仓。

物体运动: CPU 矩阵 → VS 乘一次 GPU 蒙皮: CPU 骨矩阵列表 → VS 按权混合再乘 CPU 蒙皮: CPU 混合位置 → 上传 VBO → VS 只乘 MVP

通道怎么配

数据 推荐 反例
世界矩阵 Uniform 改 VBO 模拟平移
骨骼矩阵列表 Uniform 数组或纹理 每骨一次 draw
骨索引与权重 Attribute,STATIC 每帧改权重
相机 视图矩阵 Uniform 移动所有世界物体反过来追相机
时间波 Uniform 时间 + VS 公式 每帧改位置仓

WebGL1 Uniform 向量数量有限,骨骼多了塞不下,要用矩阵纹理:CPU 把矩阵打进一张 NEAREST 浮点或四通道图,VS 采样。WebGL2 更宽,仍可能用纹理。这是通道表的逃逸,第 2.5 节提过。

// 概念:物体级动画只碰矩阵 mat4.rotateY(model, model, dt); mat4.multiply(mvp, vp, model); gl.uniformMatrix4fv(uMVP, false, mvp);

交互:轨道相机改的是相机位置,CPU 算视图。拖物体改的是该物体 M。拾取:CPU 用射线与包围盒,或 GPU 把 ID 画进离屏小 FBO 再 readPixels 1x1。后者准到三角,前者便宜。产品查看器射线够;复杂 CAD 可能要 GPU ID。

循环、时钟、实例

requestAnimationFrame 在 CPU。里面应少分配、少编译、少读回。动画时钟用回调给的时间戳,不要用累加 dt 而无钳制,后台标签回来会跳。物理若与渲染分步,那是另一套循环;本文集只强调:物理结果应变成矩阵或缓冲更新策略,不要让渲染循环里出现网格重建。

实例化动画:一千个风车角度不同,角度进 instance Attribute,VS 转。不要一千次 Uniform 上传。GPU 粒子用点图元加变换反馈(WebGL2)把下一帧位置留在 GPU。WebGL1 常退回 CPU 粒子池。版本又一次切动画路线。

⚠️ 常见坑:每帧 new Float32Array(16) 上传矩阵。矩阵该复用同一块类型化数组。粒子更甚。分配是 CPU 税,看起来像“动画卡”。

💡 关键直觉:先问变化粒度是物体、实例还是顶点。粒度决定通道,通道决定能不能 60 帧。

引擎动画系统把采样(CPU 读曲线)和蒙皮(常常 GPU)拆开。曲线采样仍在 CPU:时间到关键帧插值出骨矩阵。完全 GPU 蒙皮不等于动画零 CPU。不要看见角色就怪 GPU,可能是曲线与场景图遍历。性能节会再分端。

问题:能不能全用 CPU 蒙皮省掉着色器复杂度?

原型可以,人数一涨或网格一密就不行。CPU 蒙皮还有一个假优点:CPU 上有变形后的位置,方便碰撞。真要碰撞,用简化代理网格,不要用渲染网格的蒙皮结果。把渲染精度和物理精度绑在同一份 VBO,两端都难。

第一个动画:让三角形的 MVP 随时间转。第二个:VS 里用时间扭 y 做布条。对比 VBO 不变。有了这组对照,再看骨骼示例才知道权重 Attribute 为什么是 STATIC。

采样、插值、以及交互不要拆网格

骨骼动画的曲线采样在 CPU:时间对关键帧,插值出局部骨变换,乘层级得到世界骨矩阵,再乘绑定逆,得到蒙皮矩阵。这一串全是物体级以下、顶点级以上的 CPU 工作。矩阵列表上传后 VS 才按权混合。所以“GPU 蒙皮”从不等于“动画零 CPU”。曲线密度、骨骼数、角色数,决定采样税。一百个角色各 60 骨,CPU 采样能先死。实例化同款动画可共享采样结果加不同世界矩阵;不同动画则要分摊采样或降骨骼。

变形目标系数常由面部绑定或程序驱动,仍是少量 Uniform。差量 Attribute 静态。不要每帧把目标网格在 CPU 里加起来再上传,那是 CPU 蒙皮的亲戚。例外是工具里要在 CPU 看见最终顶点做碰撞——用代理。

轨道相机交互:指针增量在 CPU 改球坐标,再重建视图。缩放改半径或 fov,两者观感不同:改 fov 像镜头,改半径像走近。产品查看器常用半径。惯性在 CPU 用阻尼。这些都不碰 VBO。拾取拖拽物体:射线中了哪一个,就改哪一个 M。不要因为拖拽就进入蒙皮代码路径。

手势与 requestAnimationFrame 的对照:输入事件可以 200Hz,绘制 60Hz。在事件里改目标角度,在帧回调里平滑并上传 Uniform。事件里不要 draw。否则输入线程与绘制抢状态。引擎通常已这么做;裸写容易在 mousemove 里直接 draw,移动端直接掉帧。粒度:输入是事件,绘制是帧,矩阵是二者之间的桥。

根运动、绑定逆、以及调试骨骼

绑定逆矩阵把绑定姿势的顶点变到骨空间。导出漏了绑定逆,角色炸成面团。这是资产合同,GPU 蒙皮公式再对也救不了。调试画骨骼线:CPU 用骨世界矩阵画 LINES。线对了再看权重着色:把骨索引当颜色。权重归一化失败会缝。归一化在 CPU 导入时做,不要假设 DCC 软件保证四权之和为 1。导入断言比运行时猜体面。

对照问答:面团、抽搐、拖拽

角色像面团?

绑定逆缺失或骨矩阵空间不一致。画骨骼线。线对了再查权重。权重没归一会缝。导入断言四权之和。面团不是 MVP 错,MVP 错是整角色飞走。飞走查矩阵;面团查蒙皮资产。

动画一卡一卡?

每帧 new 数组、在事件里 draw、或采样在主线程过重。复用类型化数组。输入只改目标,帧回调才采样上传。角色多了要降骨或共享采样。卡在输入时像 GPU 事,其实是 CPU 分配。面板分端能揭穿。

拖模型时网格每帧重建?

把拖拽写成改顶点。应改模型矩阵。重建是 2.2 与 2.3 的反模式。拖拽是物体级运动。只有雕刻类工具才改仓,且要用 SubData 局部。查看器拖拽走矩阵,没有例外。

工程备忘:采样线程与拾取策略

骨采样可放 Worker,传回矩阵列表。角色少时不必。角色多再拆。主线程禁止在 mousemove 里采样加 draw。事件只改目标时间或目标角度。拾取:查看器用 CPU 射线包围盒;零件级用颜色 ID 小 FBO。两套不要混在同一交互。拖拽只改矩阵。雕刻才改仓。动画时钟暂停时仍要能截一帧,时间戳用逻辑时间不是墙钟,后台回来才不会跳。逻辑时间与呈现时间分开,是动画卫生,对标 2.1 的两端。

动画验收:物体自转不改仓;角色走路骨骼线稳定;后台切回不跳时间。三条过了再接业务。采样与绘制分家:事件改目标,帧回调采样。mousemove 里 draw 的代码审查直接打回。角色数量门禁,超了降骨或实例共享。拾取策略按产品写死,查看器射线,编辑器零件用 ID。拖拽改矩阵,断言顶点仓写入次数为零。不为零就是有人走了雕刻路径。绑定逆缺失拒绝角色,不要上屏幕再炸成面团。面团出现在生产,说明导入断言被关了。断言关了等于把 4.4 的资产合同撕掉,GPU 蒙皮再正确也没有绑定姿势。

动画审查看写入次数。物体运动时顶点仓写入必须为零。不为零就打回。这条比看代码里有没有蒙皮函数更硬。函数可能叫 updateMesh 实际在改仓。次数不撒谎。后台切回用逻辑时间。墙钟跳跃会把插值拉成瞬移。瞬移被当成骨骼 bug。其实是时钟合同。合同写在帧回调第一行。

现场对照时只改一个变量。同时改版本、封装、通道,归因会消失。消失之后只能靠感觉,感觉正是本书要拆掉的东西。把改动写成一条,测完再写下一条。一条一条,四组对照才用得上。用不上的对照表只是装饰。装饰填不满格子,格子空着就不要标完工。动画这一格改完,看写入次数是否为零,不要直接上百人跑步。

要点速记

  • 物体级走矩阵:仓库 STATIC,Uniform 每帧 16 个数。
  • 皮肤级走蒙皮:权重 STATIC,骨矩阵每帧;避免整网 STREAM。
  • 相机只改 V:不要反推所有 M。
  • 实例化吃差异角度:instance Attribute 减 draw。
  • 拾取两条路:射线便宜,颜色 ID 更准但要离屏。
  • 时钟在 CPU:动画循环里禁止编译与大分配。

下一节把 WebGL1 扩展补丁对照成 WebGL2 内置,看哪些洞补得上、哪些必须换合同。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U