ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Mesh2Splat渲染管线深度解析:8大RenderPass如何协同工作?

Mesh2Splat渲染管线深度解析:8大RenderPass如何协同工作?

【免费下载链接】mesh2splat

Fast mesh to 3D gaussian splat conversion

项目地址:https://gitcode.com/gh_mirrors/me/mesh2splat
点击查看免费下载

Mesh2Splat 是一款可将 3D 网格(Mesh)在亚毫秒级转换为 3D Gaussian Splatting(3DGS)模型的高性能开源工具,并自带一个功能完整的 3DGS 渲染器。这套渲染器的核心是一条由8 大 RenderPass 协同工作的 GPU 渲染管线:从毫秒级网格转 3DGS、深度预渲染、GPU 预筛选、RadixSort 深度排序,到最终的高斯实例化绘制、实时阴影与延迟光照。本文将逐个拆解这 8 个 RenderPass 的职责、依赖关系和数据流,带你完整看懂这条管线的协作机制。

🗺️ 渲染管线全景:8 大 RenderPass 的执行顺序

整个管线的"总调度台"在 renderer.cpp 中:Renderer::initialize()会注册全部 8 个 Pass,并按固定顺序存入renderPassesOrder;每帧renderFrame()遍历该顺序,只执行被 UI 启用的 Pass(Pass 默认关闭,按需开启),同时用GL_TIME_ELPASSED查询池异步统计 GPU 帧耗时。

顺序Pass 类名内部标识核心职责
1ConversionPassconversionMesh → 3DGS 亚毫秒级转换
2DepthPrepassdepthPrepass网格深度预渲染,供高斯遮挡测试
3MeshRenderPassmeshRender渲染网格 GBuffer(分屏对比用)
4GaussiansPrepassgaussianPrepass高斯预筛选与屏幕空间投影
5RadixSortPassradixSort按深度的基数排序
6GaussianSplattingPassgaussianSplatting高斯四边形实例化绘制(写 GBuffer)
7GaussianShadowPassgaussianSplattingShadows点光源 360° 阴影立方体贴图
8GaussianRelightingPassgaussianSplattingDeferredLighting全屏延迟 PBR 光照与合成

Pass 的启停逻辑由 UI 层 guiRendererConcreteMediator.cpp 控制:点击"Convert Mesh to 3DGS"时启用转换+排序+绘制链路;开启光照时追加阴影 Pass;需要网格深度测试或分屏对比时才启用前两个 Pass。这种"按需执行"的设计让每个 Pass 都可以独立开关,也方便学习时单独调试。

⚡ ConversionPass:亚毫秒级 Mesh 转 3DGS 的核心

ConversionPass.cpp 是整个项目的灵魂。它完全绕开了经典 3DGS 的"渲染数据集→离线优化"流程,直接复用 GPU 光栅化器的硬件插值器:

  • VS → GS:几何着色器按三角形做三平面正交投影(Triplanar),计算每个三角形的 Jacobian 矩阵,得到 3D 高斯的 Scale 与 Rotation;
  • 光栅化插值:把归一化 UV 编码进gl_Position,让光栅化器在正交空间逐片元插值,一个片元 = 一个 3D 高斯;
  • PS:采样 Albedo / Normal / Metallic-Roughness 贴图,每个片元通过原子操作向共享 SSBO(gaussianBuffer)追加一个高斯;
  • 转换结束glFinish()同步后读回原子计数器,得到高斯总数,全程平均 < 0.5ms。

转换容量上限为resolutionTarget² × 6 × 网格数,并受 RenderPass.hpp 中MAX_GAUSSIANS_TO_SORT = 7000000的硬顶约束——这也是下游排序缓冲的统一容量。

下图是实际运行效果:点击 Convert 后,左侧界面即可看到高斯数量与帧时间统计。

🧱 DepthPrepass + MeshRenderPass:深度与 GBuffer 双准备

  • DepthPrepass.cpp:只绘制不透明网格(baseColorFactor.a == 1.0),把深度写入独立depthFBO。这份深度纹理随后交给 GaussiansPrepass 做"网格遮挡高斯"的剔除测试,可显著减少无效高斯数量;
  • MeshRenderPass.cpp:把网格的 PBR 属性(世界坐标、法线、Albedo、深度、Metallic-Roughness)写入 5 个 Color Attachment 的meshGBufferFBO,供最终 Pass 做分屏对比(左网格 / 右高斯)使用。

这两个 Pass 是可选的"增强项",它们不产生画面,而是为后续 Pass 提供深度数据与对比基准。

🔍 GaussiansPrepass:GPU 预筛选与屏幕空间投影

GaussiansPrepass.cpp 是一个 Compute Shader(每组 256 线程、近似正方形网格分发):

  1. 对每个高斯做视锥裁剪与深度遮挡测试(读取上面生成的meshDepthTexture);
  2. 把通过筛选的高斯投影到屏幕空间,计算每个高斯四边形的变换矩阵,写入perQuadTransformationsBuffer;
  3. 用原子计数器累加"可见高斯数"(validCount),这个计数值会一路传递给后续 Pass,避免全量遍历 700 万个高斯。

这一步是性能关键:排序与绘制阶段只处理真正可见的高斯子集。

🔢 RadixSortPass:三步走完成深度排序

高斯混合要求从远到近绘制,RadixSortPass.cpp 用经典三阶段完成 GPU 排序:

阶段函数作用
① 计算 KeycomputeKeyValuesPre把高斯深度编码成排序 Key,写入keysBuffer/valuesBuffer
② 基数排序sort调用 RadixSort.hpp 中的glu::RadixSort(LSB 基数排序,内部自动同步)
③ 收集结果gatherPost按排序后的索引重排四边形变换到perQuadTransformationBufferSorted,并把实例数写进drawIndirectBuffer

最后一步写好的间接绘制命令(instanceCount)正是下一个 Pass 一次 Draw Call 绘制百万高斯的秘密武器。

🎨 GaussianSplattingPass:实例化绘制与 Front-to-Back 混合

GaussianSplattingPass.cpp 是画面的"生产者":

  • 用一个全屏四边形 VAO + 逐实例属性(divisor = 1)+glDrawElementsIndirect,单次 Draw Call画完所有排序后的高斯四边形;
  • 采用 Front-to-Back 顺序配合混合函数GL_ONE_MINUS_DST_ALPHA, GL_ONE(预乘 Alpha),近处像素算完即可提前剔除远处像素;
  • 结果不直接输出颜色,而是写入 5 通道的gBufferFBO(位置/法线/Albedo/深度/Metallic-Roughness)——为延迟光照做准备;
  • 调试彩蛋:切到overdraw模式时混合函数变为GL_ONE, GL_ONE,可以直观看到重叠绘制次数。

💡 GaussianShadowPass + GaussianRelightingPass:实时光照与延迟着色

最后两个 Pass 让 3DGS 具备了传统渲染器才有的可重光照(Relightability):

1. GaussianShadowPass.cpp —— 360° 点光源阴影

  • 以点光源为中心构建 6 个glm::lookAt视角,配合 90° 透视投影;
  • 先用 Compute 预筛选出落入各立方体面视锥的高斯,再把每面高斯变换写入统一缓冲;
  • 循环 6 次间接绘制,生成 6×1024² 的深度阴影立方体贴图(shadow cubemap)。

2. GaussianRelightingPass.cpp —— 全屏延迟光照

  • 绘制全屏四边形,从gBufferFBO读取 PBR 属性,结合点光源参数与阴影立方体贴图,在片元着色器里完成 PBR 光照计算;
  • 开启分屏对比时,巧妙用Stencil 缓冲区分区:左半屏采样网格 GBuffer、右半屏采样高斯 GBuffer,再用 Scissor 画一条白色分割线,实现"网格 vs 高斯"的同屏 PBR 对比。

🔗 数据流总览:共享 Buffer 串起整条管线

8 个 Pass 并非孤立运行,它们通过 RenderContext.hpp 定义的一组共享 GPU 缓冲接力传递数据:

共享资源生产者 → 消费者说明
gaussianBuffer(SSBO)Conversion → Prepass/Shadow全部高斯的原始数据
keysBuffer/valuesBufferPrepass → RadixSort深度 Key 与索引 Value
perQuadTransformation…SortedRadixSort → Splatting排序后的逐实例变换
drawIndirectBufferRadixSort → Splatting间接绘制的实例数
atomicCounterBufferPrepass → RadixSort可见高斯计数(validCount)
meshDepthTextureDepthPrepass → Prepass网格遮挡测试
gBufferFBO/meshGBufferFBOSplatting/MeshRender → RelightingPBR 延迟光照输入
阴影立方体贴图Shadow → Relighting360° 阴影采样

可以看到一条清晰的主线:转换产出数据 → 预筛选缩小范围 → 排序确定顺序 → 一次绘制生成 GBuffer → 光照合成画面,每个 Pass 只做一件事,职责单一、边界清晰。

📁 关键源码文件速查

  • 管线调度:renderer.cpp、RenderPasses.hpp
  • 8 个 Pass 实现:src/renderer/renderPasses/
  • GPU 基数排序:RadixSort.hpp
  • 转换核心着色器:converterGS.glsl、converterPS.glsl
  • 高斯预筛选着色器:gaussianSplattingPrepassCS.glsl
  • 延迟光照着色器:gaussianSplattingDeferredPS.glsl
  • 排序着色器:radixSortPrepass.glsl、radixSortGather.glsl
  • 项目总览与数学原理:README.md

总结:Mesh2Splat 的渲染管线把"转换"和"渲染"两条链路统一在 8 个职责单一的 RenderPass 中——ConversionPass 用硬件插值器实现亚毫秒转换,Prepass + RadixSort 用"先筛选后排序"控制规模,Splatting Pass 用单次间接绘制 + Front-to-Back 混合保证帧率,最后的 Shadow + Relighting 两个 Pass 则赋予 3DGS 实时 PBR 光照能力。理解了这条管线,你也就掌握了现代 3D Gaussian Splatting 渲染器的通用设计范式。

【免费下载链接】mesh2splat

Fast mesh to 3D gaussian splat conversion

项目地址:https://gitcode.com/gh_mirrors/me/mesh2splat
点击查看免费下载
上一篇:Kanata终极配置指南:解锁复杂按键逻辑的10个高级技巧
下一篇:SFUD添加新Flash型号教程:以GD25Q64B为例

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进