上一节建好了一棵近乎完美的静态树,本节第一件事就是把它弄乱:让角色迈步、车轮旋转、粒子迸溅。树是按某一帧的几何长出来的,几何一动,树的假设就作废——重走 4.2 的建树流程每帧来一遍?SAH 建树在百万三角形上要几十到几百毫秒,实时预算根本不允许。本节给出工业界的完整答案:先按运动类型选维护策略(refit 还是 rebuild),再用 TLAS 与 BLAS 的双层结构把更新代价精准隔离到"真正动了的那一小块"。这一节也是第 7、8 章实时管线的直接地基。
动态性不是一种东西,先分光谱。刚体运动:物体整体平移旋转,内部顶点相对关系不变——树结构完全不用动,第 3 章的实例化技巧原样生效,每帧只更新一个变换矩阵,成本几乎为零。形变运动:骨骼蒙皮、软体仿真让顶点位移但拓扑不变——树的骨架大体仍有效,问题只出在包围盒撑不住新位置。拓扑运动:物体分裂融合、粒子生成消亡,基元集合本身在变——旧树逻辑上已死,只能重建。给三类运动各配一副药:
刚体: 只动变换矩阵,BLAS 原样复用(代价 ≈ 0) 形变: refit——自底向上重算包围盒(毫秒级,树不变,质量缓慢退化) 拓扑: rebuild——重新执行建树(贵;用时间切片或异步分摊到多帧)
Refit 的做法朴素到一目了然:按层次从叶往根扫一遍,每个节点的新盒子等于两个子盒的并。它快在只算包围盒、不重排基元,缺点是树形不再贴合新的几何分布——基元大幅移动后盒子互相重叠、裁剪失效,遍历性能逐帧滑坡。Rebuild 是 4.2 的全套 SAH 流程,质量最优但贵。两者之间还有折中派:定期 rebuild 加每帧 refit、只在 SAH 代价恶化的子树局部重建(所谓可重构树)。选型的算术很简单:refit 成本约为树的节点数乘常数,rebuild 成本约为基元数乘对数——前者对帧率友好,后者对质量负责,预算夹在中间时按子树分摊。

TLAS 与 BLAS 的分工是把第 3 章实例化推到加速结构层面。**BLAS(底层加速结构)**管"一件几何内部":一个角色的蒙皮网格、一辆车的车身,内部是标准的 SAH 树。**TLAS(顶层加速结构)**管"实例怎么摆":节点是每个实例的世界空间包围盒加变换矩阵,本质是一棵以实例为叶子的粗粒度树。遍历时射线先走世界树——大多数盒子很快被裁掉——命中哪个实例,就乘逆变换进它的局部树继续查。更新账本由此重新计价:一百个动画实例的形变,只触发各自 BLAS 的 refit(每棵几万节点的小树),加上 TLAS 的一百个盒子刷新;世界级的 SAH 树则从头到尾不用重见。第 8 章你会看到,DXR 与 Vulkan 光追接口在 API 层面原样暴露这两层,构建 BLAS 与 TLAS 是两个独立操作——届时本节就是那套 API 的设计说明书。
两个实务细节值得预付。其一,BLAS 粒度决定更新成本:把整辆车连人带轮塞进一个 BLAS,车轮旋转就拖累全树 refit;把车轮独立成实例,它只是 TLAS 里一个会动的盒子。粒度切在哪,要按"哪些部件以相同方式运动"来切。其二,混合粒度允许 BLAS 里再嵌实例(引擎实现允许时),场景层级深的项目要警惕嵌套带来的遍历开销与驱动兼容性差异。
把本节内容组装成一个完整复盘。场景:一辆行驶的车(刚体)、一个挥手角色(蒙皮形变,六万三角形)、八千粒子的喷泉(拓扑运动),外加十万平方米静态建筑。第一步做粒度切分:车身、四个车轮、角色、喷泉各自成 BLAS,建筑合成一个静态大 BLAS(构建一次,永不更新)。第二步定更新策略:车轮四个矩阵每帧刷新,成本约等于零;角色 BLAS 每帧 refit(约十五万节点,实测零点几毫秒量级),每三十帧在空闲时段做一次局部 rebuild 防质量滑坡;喷泉放弃树结构,降级为面向相机的公告板网格进静态 BLAS——粒子级精确求交的收益撑不起它的 rebuild 账单。第三步算总账:每帧加速结构维护总预算压进一毫秒上下,剩下的预算留给遍历与着色。解读关键在于那笔"降级":动态加速的功力不在让一切都精确,而在把精确度当预算花。变式:若角色换成八帧一次的预制动画,可预构建八套 BLAS 按帧切换,refit 也省了——用内存换时间,静态与动态之间又多了一档选择。
双层结构里最容易埋雷的是那次坐标变换。射线命中 TLAS 的实例盒后,要乘实例的逆矩阵进入局部空间再走 BLAS——行李必须带全三件。第一件是逆矩阵本身:把射线的起点与方向变换到局部空间,方向变换后不再归一化没关系,但 t 的语义随之变成"缩放后的参数距离",出来时要按雅可比换算回世界距离,漏掉这步的渲染器症状是"实例物体命中的阴影与反射深度忽深忽浅"。第二件是逆转置矩阵:法线不能跟方向用同一个矩阵,非均匀缩放下用错矩阵,法线会歪出表面,光照随即错位——第 3 章埋的法线双轨制,在这一步兑现。第三件是变换的更新时间戳:实例矩阵被动画改写后,命中记录里缓存的世界空间信息(比如上一帧的命中位置)必须作废,否则运动物体身后会拖出鬼影。
顺带回答一个高频疑问:为什么不让 TLAS 直接存世界空间的三角形,一层了事?答案是更新账单。百万三角形每帧动几个实例,世界空间树要全部重建;双层结构下只有动过的实例才需要重新装配,静态几何的大树纹丝不动。层的价值不在遍历快那一点,而在把"变化的传播范围"关进最小房间——这条设计律在第 9 章软件架构里还会以别的名字出现。
再补一个十分钟动手校验:造一个只有两个实例的微型场景(一个静态大盒子、一颗绕原点旋转的小球),分别用"全局单树每帧重建"与"双层结构每帧只刷 TLAS"两种方案计时。盒子只有几十个三角形时两者差距不明显;把盒子换成二十万三角形的大厅,单树方案的帧时间随静态几何规模线性恶化,双层方案几乎纹丝不动——双层的收益随静态场景规模放大,这正是开放世界必须双层的原因。顺手记一个实现细节:TLAS 的实例盒要在世界空间下略微外扩(按速度或运动模糊余量),否则高速物体的反射会在帧间出现边缘破洞;这个余量没有公式,开运动模糊的镜头要留得更足,视觉验收时专门盯快速横移物体的边缘。预算再紧也要给这个余量留一个专门验收项,它是双层结构少数几个纯经验参数之一。另外,外扩只作用于 TLAS 盒,BLAS 的局部盒不必跟风——两层各管各的保守度,混在一起会无谓放大遍历量。
树的学问到此完整:建得快、走得快、动得起。接下来该回答"撞上之后光怎么改道"——下一章进入材质与 BSDF,实验室从钳工台转向光学台。