
数分钟处理数十亿个三角形
2025年9月30日消息,今年年初,NVIDIA发布全新光线追踪技术[RTX Mega Geometry],还展示[Zorah演示]。该演示以约100GB的Unreal Engine场景形式发布,只能在Unreal Engine的特殊分支NvRTX中打开,展示了新驱动支持的光线追踪功能,特别是集群光线追踪与Nanite集群LOD管线结合的应用,可在不使用Unreal Engine当前为光线追踪生成的Nanite代理网格的情况下,流式传输并显示具有完整光线追踪效果的高细节场景。
因与Unreal Engine关联度高,难以大量实验。9月初,NVIDIA更新[vk_lod_clusters开源示例],将Zorah场景以glTF文件形式呈现,激起好奇心,促使改进[meshoptimizer]对分层集群LOD的支持。
技术原理
若了解Nanite,后续内容更好理解;若不了解,推荐阅读Brian Karis等人撰写的[《Nanite:深度剖析》]。对于可能含大量三角形的网格,任务有三:生成能在任意细节级别表示该网格的分层结构;在适当细节级别流式传输该结构的部分内容;在适当细节级别渲染网格的可见部分。采用的结构是由集群组成的有向无环图(DAG),每个集群是一组小三角形,代表给定细节级别的一小片网格,结构包含不同细节级别的集群,运行时代码负责流式传输和渲染这些集群,以最小化视觉误差,只有当替换集群导致的视觉误差小于1像素时,才会用较粗的集群替换。
这项技术有三个难点:从高细节网格生成结构、压缩结果以提高流式传输效率,以及实时渲染结果。构建结构时,先将网格拆分为多个集群,合并相邻集群,对每个组独立简化并保留组的边界边,再拆分结果组为更多集群,重复此过程直到没有可合并的集群。自2021年Nanite发布以来,多个引擎开始采用这种处理模式。meshoptimizer从2024年起有示例展示如何结合其提供的多种算法构建这种结构。
规模挑战
原始Zorah场景是Unreal Engine资产,NVIDIA在开源Vulkan示例中发布Zorah的glTF场景。该场景有16.4亿个三角形,实例化后有189亿个三角形,磁盘占用36.1GB,渲染缓存磁盘占用62GB。尝试在Blender和Unreal Engine中导入该glTF文件,均因内存不足而失败。
无需导入该文件,运行NVIDIA处理此文件的示例代码。9月初尝试时,使用16个线程会导致内存不足,经实验,使用8个线程能可靠运行处理代码,使用7个线程时,处理时间约为30分钟。
基准测试
构建分层结构需要集群化、分区和简化,meshoptimizer提供了这三种算法。截至0.25版本,meshoptimizer包含两种主要的集群化算法,一种为光栅化和网格着色器设计,一种为光线追踪和新的集群光线追踪扩展设计。最初演示使用的是光栅化优化的集群,将演示代码重构为易于理解且接口简洁的代码,新接口还集成了简化算法的一些新功能。
测试代码使用内存映射避免将整个文件同步加载到内存,还对网格重新索引。经过调整,小程序在Linux上使用16个线程处理该文件,使用光栅化优化设置约需9分20秒,占用约54.6GB RAM;切换到新的光线追踪优化集群器,约需7分10秒,占用约57.6GB RAM。
稀疏性问题
使用[Superluminal]性能分析工具分析代码,发现`memset`操作耗时很长。两个集群器都使用由顶点索引的数组跟踪顶点是否已分配给当前网格片,当对大量三角形的网格子集进行集群化时,该操作会变慢。简化器中也存在类似问题。2024年添加`meshopt_SimplifySparse`标志以减少对顶点数量的依赖。修复这些问题后,光栅化版本需3分31秒,光线追踪版本需3分57秒。
线程平衡
使用`/usr/bin/time -v`查看命令的CPU使用率,代码的CPU使用率在1240% - 1260%之间。使用Superluminal查看结果,发现场景中网格的三角形数量分布不平衡,处理大网格的工作可能在后期才开始。按三角形数量降序对网格进行排序,重新运行代码后,16个线程执行更平衡,CPU利用率为1574%。执行时间改善,光栅化版本需2分56秒,光线追踪版本需3分07秒,且峰值内存消耗略有降低。
更快的集群化
此前结果是使用meshoptimizer v0.25(加上稀疏性修复)得到的,在最新的`master`分支上测试。对光线追踪优化的结构进行性能分析,发现新的空间集群器(`meshopt_buildMeshletsSpatial`)占据大部分运行时间,确定`bvhComputeArea`函数是主要问题。将相关代码转换为SSE2代码,运行时间从3分07秒缩短到2分51秒。使用Morton顺序对三角形进行空间排序,得到2分44秒的结果。
缓存分配
上述函数处理过程中需分配内存,在16个线程同时分配大量内存的情况下,默认分配器可能导致线程等待。在Linux和Windows平台上测试,发现多线程内存分配与默认大内存块策略存在不良交互。使用每个线程的内存池分配内存,在Linux上代码运行时间约为2分35秒,在Windows上从4分20秒缩短到2分38秒。该解决方案未来可能集成到meshoptimizer版本中。
最终结果
大部分改进已集成到示例代码中,代码以单头文件“微库”形式通过meshoptimizer仓库分发。`meshopt_spatialSortTriangles`函数调用可在外部进行,线程缓存改进可能在今年晚些时候meshoptimizer v1.0版本发布后集成。`vk_lod_clusters`将示例代码作为选项集成,在NVIDIA GeForce 3050上,使用光线追踪渲染约2GB的几何图形池需26毫秒,使用光栅化需16毫秒。在`vk_lod_clusters`中,包含所有优化后,处理时间约为3分20秒。仍有改进空间,如需要单独的分层加速结构,不过该问题已得到修复。
感谢Christoph Kubisch的讨论等工作,感谢NVIDIA公开分享,感谢Valve对meshoptimizer开发的赞助。



被折叠的 条评论
为什么被折叠?



