今天翻到 AMD 七月发的一篇文章,讲怎么对海量动画几何体做光线追踪,作者是 Holger Gruen,AMD Fellow,一直在做实时光追方向。文章里的测试场景是大约 5.85 亿个动画三角形,在 Radeon RX 9070 XT 上 1080p 跑到 60fps。第一眼看到这个数字我是怀疑的,动画网格的光追向来贵在“每帧都要重建加速结构”,5.85 亿个三角形按老思路每帧重建一遍,想都不敢想。所以这篇的核心其实不是“跑得快”,而是把动画成本和三角形数量解耦了,这个思路值得记一笔。
原理是这样:动画不再作用在每个三角形上,而是作用在一个低分辨率的四面体笼子上。预处理阶段把原始网格切成一小块一小块互不重叠的碎片,绑到各个四面体上,然后为这些碎片建一次静态的 mini-BLAS,之后一直复用。运行时光线进入某个正在动的四面体时,把光线变换到 rest-pose 空间去和静态几何求交,出来的是分段线性的近似运动。用伪代码表示大概是这样:
ray r = camera_ray(x, y)
tet = find_tet(cage, r) // 在动画后的笼子里找四面体
r_rest = tet.inverse_xform(r) // 变换回 rest-pose 空间
hit = intersect_mini_BLAS(tet, r_rest)
我一开始没搞懂为什么要“切网格”这一步,后来才想明白——不切成小块绑到四面体上,就没法让每个四面体独立携带一份静态几何,后面“建一次、永久复用”也就不成立了。这一步是整个方案的地基。
真正让我觉得巧妙的是复用那部分:同一个资产的很多份各自动画的拷贝,可以共享同一套 rest-pose 碎片网格和 mini-BLAS,每份拷贝只需要各自动画自己的笼子。也就是说一份静态数据喂 N 个不同的变形实例,内存和构建成本都摊薄了。做开放世界或者人群场景的人应该能立刻意识到这意味着什么。
验证方面,除了那个 5.85 亿三角形、60fps@1080p 的组合场景,文章还提到这篇论文在 High-Performance Graphics 2026 的 Wolfgang Straßer 最佳论文奖里拿了第三名,至少说明同行评审那边也认。另外文章也老实提了 Luton 和 Tricard 在 2026 年的独立类似工作,那条路线用多条硬件光线做四面体间接寻址,而且不需要 clipping 步骤——我没细看那篇,这里先留一个坑,回头补。
工程兼容性上两点值得划出来:可以和分区的顶层加速结构组合,也能和 cluster 级加速结构共存。这意味着不是“推倒重来换一套管线”,而是能往现有架构里塞,对实际落地来说这比性能数字更重要。
AMD 说后续会放 DXR sample 和一个 header-only 的 C++ 库,用来给蒙皮、关键帧动画和静态物体建四面体笼子。等库出来我打算跑一遍:
- 找一个带蒙皮动画的资产,用库生成笼子;
- 先在小的测试场景里验证光线变换那一步,确认求交结果和直接对动画后网格求交的偏差在可接受范围;
- 再试着复制多份不同变形的实例,确认共享 mini-BLAS 那条路径真的省了构建开销;
- 最后才碰大场景。
这个坑我之前在别的地方也绕过两次——直接上大场景,出了偏差根本分不清是笼子太粗还是自己管线接错了,从小场景一步步来反而快。
划重点:第一,动画成本和三角形数量解耦,靠的是“动画笼子 + 静态碎片”这个拆分,不是什么魔法;第二,光线变换到 rest-pose 空间求交,换来的是 mini-BLAS 建一次永久复用;第三,多实例共享静态数据这条,对人群和植被类场景可能是最大的实际收益。等 sample 放出来你可以自己试试,拿一个现成的蒙皮模型生成笼子跑一遍,比看十遍文章都清楚。这篇先记到这里,库出来之后我再来补实测的笔记。
