揭开 volsample 核心算法面纱:为何采样点要放在十二面体对应的世界空间平面上?
揭开 volsample 核心算法面纱为何采样点要放在十二面体对应的世界空间平面上【免费下载链接】volsampleStructured Volume Sampling - sample placement algorithm for real-time volume rendering with low aliasing, for camera-in-volume case.项目地址: https://gitcode.com/gh_mirrors/vo/volsample体积渲染Volume Rendering是云、雾、体积光等实时特效的基础但相机进入体积内部时采样点随相机穿层会造成严重闪烁。本文基于开源项目volsampleStructured Volume Sampling结构化体积采样用最通俗的语言拆解它最核心、也最反直觉的设计为什么要把采样点放在十二面体对应的世界空间平面上。实时体积渲染的最大痛点采样点为什么会穿层闪烁先看一个大家都会遇到的场景你在云层、雾海或烟尘中飞行视线前方是体积数据。实时体积渲染通常用光线步进Ray Marching沿视线取 3264 个采样点叠加颜色与透明度。问题出在采样点的坐标系上。如果采样点放在跟随相机的视空间里例如垂直于视线的平面层那么相机一动这些采样层就会像梳子一样扫过整个体积。扫描过程中某个体素一会儿被采到、一会儿被漏掉屏幕上就表现为强烈的闪烁、噪点和走样Aliasing。这就是相机在体积内camera-in-volume场景下最著名的渲染难题之一。上图左侧是 volsample 的核心几何示意围绕相机光栅化一个种子多面体绿色区域只用 1 条射线、黄色区域混合 2 条、红色区域混合 3 条右侧是对应的实际渲染结果颜色标记了每条像素实际混合的射线数量。传统方案为何治标不治本固定 Z 平面与 Pinned 采样在 volsample 项目里也内置了两种传统采样方案用于对比源码都在 RayMarchCore.cginc 中方案采样点位置问题固定 Z 平面Fixed-Z垂直于视线、随相机移动相机一动采样层横扫体积严重锯齿固定 Z PinnedRayMarchFixedZPinned补偿相机前进运动让采样点尽量静止只能补偿前后平移旋转与侧移时边缘像素依然扫得厉害结论很明确只要采样布局跟着相机走就永远会有穿层闪烁。要根治就得让采样点在世界空间里不动。核心答案把采样点钉在世界空间平面上volsample 的破局思路只有一句话让采样点位于世界空间中静止的平面族上而不是视空间平面。当相机平移或旋转时世界空间平面本身不动视线与平面族的交点只会沿着平面滑动。由于这些平面在二维方向上是密集、连续的采样密度极高滑动不会造成采样空洞闪烁和走样自然就消失了。这个思想在项目入口脚本 StructuredVolumeSampling.cs 的注释里写得非常直白体积渲染通过三次绘制Pass光栅化倒角十二面体几何分别执行 1 次、2 次、3 次光线步进并混合结果。为什么偏偏是十二面体全方向覆盖的秘密有人会问随便选一组世界平面不行吗不行关键在于方向覆盖。十二面体有12 个五边形面它们的法线近似均匀地分布在球面上几乎覆盖所有朝向无论相机看向哪个方向总有一组五边形面法线接近正对视线保证采样间距合理、步长不会失控每 5 个面共享一个顶点、每 2 个面共享一条边正好天然地划分出单射线区 / 双射线混合区 / 三射线混合区三种区域。这个倒角十二面体的顶点数据12 个五边形面 20 条倒角边矩形 20 个倒角顶点三角形由 PlatonicSolidBlend.cs 在运行时动态生成面法线被编码进 UV 通道混合权重存在顶点颜色里然后用三个子网格分别驱动三种 Pass。光线与平面求交步长与起点是如何计算的为了让每个像素的光线都能对齐到平面族上核心函数IntersectPlanes只做了两件小事见 RayMarchCore.cginc步长dt SAMPLE_PERIOD / abs(dot(rd, n))即沿法线方向每经过一个采样周期在视线方向上对应的距离。视线越掠射步长越长正好补偿透视缩短效应起点t_0 -fmod(dot(ro, n), SAMPLE_PERIOD) / ndotrd把相机位置到第一层平面的零头跳过让首个采样点精确落在平面族上。你可以在 diagram_BufA.shader 中看到这个算法的 2D 可视化版本动画演示了视锥内的多条射线如何同时与非对角 对角两组世界空间线族求交并观察条纹状采样图案随相机平移而不闪烁。三种混合权重五边形、倒角边与倒角顶点直接在世界空间平面采样有一个副作用视线在平面族交界处会跳层产生十二面体形状的接缝伪影。volsample 用倒角Bevel 权重混合解决五边形面只与 1 组平面求交权重为 1直接步进倒角边矩形同时与相邻 2 组平面求交、步进再按顶点颜色里的双权重混合倒角顶点三角形同时与 3 组平面求交、步进三重权重混合平滑过渡。这套流程在 VolumeRender.shader 中以三个 Passfrag1/frag2/frag3实现仅在平面上开启STRUCTURED_SAMPLING关键字时激活和普通采样完全隔离方便对比。如何快速体验与验证Unity 场景与交互式演示打开 sponza.unity 或 clouds.unity点击运行即可在屏幕左上角用 GUI 开关切换 Structured Sampling 开/关亲眼对比穿层闪烁的消失想看采样图案动画参考 diagram_BufA.shader 与 diagram_Image.shader想看真实云层渲染效果可运行 clouds.shader点击鼠标切换到朴素光线步进做对照项目还附带了一段渲染录屏 volrender_800x450_30fps.mp4以及更详细的原理幻灯片 volsample.pptx。小结把坐标系的选择变成算法的胜负手回到开篇的问题——为什么采样点要放在十二面体对应的世界空间平面上答案可以浓缩为三句话世界空间平面静止相机运动时采样点只做平行滑动沿面方向采样密集从根源上消除穿层闪烁十二面体 12 个五边形面法线近似均匀覆盖全方向任意视线角度都能找到接近垂直的平面族保证步长与精度可控倒角几何 1/2/3 条射线加权混合把方向过渡处的接缝伪影也一并抹平。volsample 用极少的几何开销一个围绕相机的倒角十二面体 每像素最多 3 次步进就解决了实时体积渲染中最棘手的相机内走样问题思路之巧妙值得每一位做体积渲染的开发者细细品味。【免费下载链接】volsampleStructured Volume Sampling - sample placement algorithm for real-time volume rendering with low aliasing, for camera-in-volume case.项目地址: https://gitcode.com/gh_mirrors/vo/volsample创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考