news 2026/8/19 19:29:05

volsample RayMarchCore.cginc 精读:结构化光线步进的起点偏移与步长计算

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
volsample RayMarchCore.cginc 精读:结构化光线步进的起点偏移与步长计算

volsample RayMarchCore.cginc 精读:结构化光线步进的起点偏移与步长计算

【免费下载链接】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

volsample 是一个开源的结构化体积采样(Structured Volume Sampling)项目,专门解决"相机位于体积内部"时实时体渲染的严重混叠问题。它的核心思想写在 RayMarchCore.cginc 里:不再让采样层跟着相机跑,而是把采样点钉在世界空间的一组平行平面上。本文带你精读这份文件,重点拆解结构化光线步进(structured raymarching)中最关键的两个参数——起点偏移 t_0 与步长 dt——是如何一步步计算出来的,读完你就能自己读懂并复用这套思路。🎯

为什么要做结构化采样?先看混叠从哪来

实时体渲染里采样次数很少(例如云场景只有 32 次,见 SceneClouds.cginc),当相机在体积内部移动时,采样点如何放置直接决定画面是否稳定。

RayMarchCore.cginc 里实现了三种方案,正好构成一条演进脉络:

采样方案采样层如何放置相机平移时相机旋转时对应函数
固定 Z 采样垂直于视线、跟随相机采样层横扫体积,混叠严重 😵相对稳定RayMarchFixedZ
固定 Z 固定采样只补偿前向平移前向移动稳定视锥横扫侧面采样层RayMarchFixedZPinned
结构化采样世界空间固定平面族采样只在平面内滑动,几乎无混叠 ✅多射线混合补偿RaymarchStructured

结构化采样的妙处在于:相机平移时,采样点只在自己所在的平面内"平行滑动",而平面本身在空间中是密集采样的,滑动不会引入可见的走样。这也是标题里"起点偏移与步长计算"的用武之地。

IntersectPlanes 精读:两个公式搞定采样布局

结构化采样把体积剖成一组间距固定的世界空间平面族(间距为SAMPLE_PERIOD),平面法线 n 来自十二面体五边形面的朝向。光线ro + t * rd与这些平面的交点,就是采样点。计算这些交点,只需要 IntersectPlanes 这个十几行的函数:

void IntersectPlanes( in float3 n, in float3 ro, in float3 rd, out float t_0, out float dt ) { float ndotrd = dot( rd, n ); dt = SAMPLE_PERIOD / abs( ndotrd ); // 步长 t_0 = -fmod( dot( ro, n ), SAMPLE_PERIOD ) / ndotrd; // 起点偏移 if( t_0 < 0. ) t_0 += dt; // 保证首样本在视线前方 }

步长 dt:入射角的自动补偿 📐

第一个公式dt = SAMPLE_PERIOD / |dot(rd, n)|。光线垂直射向平面族时,ndotrd = ±1,步长正好等于SAMPLE_PERIOD;当视线倾斜(掠射)时,|ndotrd| < 1,dt 自动变大。

这是因为光线参数 t 是"沿光线的距离",而平面族是"世界空间等距"的,两者之间隔着夹角。除以|ndotrd|后,无论视线从哪个方向穿过体积,采样点在世界空间都严格等间距——这就是"结构化"三个字的含义:采样密度由世界空间决定,与视角无关。

起点偏移 t_0:把第一条射线对齐到分层 🎯

第二个公式t_0 = -fmod(dot(ro, n), SAMPLE_PERIOD) / ndotrd稍显晦涩,拆开看就清楚了:

  • dot(ro, n)是相机到"过原点参考平面"的带符号距离;
  • fmod(..., SAMPLE_PERIOD)取余数,得到相机与上一片采样平面之间的"残余距离";
  • 再除以ndotrd,把这段空间距离换算成光线参数 t;
  • 负号把它翻转为"到下一片平面的参数距离"。

最后一行if(t_0 < 0.) t_0 += dt处理了一个隐蔽的坑:GPU 的fmod对负数参数行为不一,这行代码统一了行为,并保证第一个采样点永远落在视点前方,不会出现"背后采样"的鬼影。

RaymarchStructured:把三条光线缝合成一帧

单个平面法线只在部分像素上成立。倒角十二面体把屏幕分成三种区域:五边形面(1 条射线)、倒角棱(2 条射线混合)、倒角顶点(3 条射线混合),分别对应 VolumeRender.shader 的三个 Pass。真正的整合在 RaymarchStructured 中完成:

  1. 首样本淡入淡出firstWt = t / dt给第一片采样加权。注释里说得很直白——不做这步,会在画面里看到恼人的五边形伪影;
  2. 隐形墙zbuf = min(depth, dt * SAMPLE_COUNT)在体积尽头假设一堵不可见墙,让采样在远处平滑淡出;
  3. 权重混合:最终结果sum = wt.x*sum0 + wt.y*sum1 + wt.z*sum2,三个权重恰好对应十二面体网格顶点色里的 RGB,见 PlatonicSolidBlend.cs。

数据从哪来:一整套闭环的调用链

法线 n 与权重 wt 不是硬编码在着色器里的,而是由 PlatonicSolidBlend.cs 实时构造的倒角十二面体网格携带:法线编码进三组 UV,权重写进顶点色;VolumeRender.shader 的顶点着色器再用 Spheremap Transform 解码还原。整个流程由 StructuredVolumeSampling.cs 的OnRenderImage驱动,三 Pass 依次绘制网格的三个子网格。想验证每一步,可以打开 sponza.unity 或 clouds.unity 场景,在 Inspector 里调PlatonicSolidBlend的 bevel 值,或切换 VolumeRender.shader 里的DEBUG_BEVELZ_PLANES_ONLY宏观察分层效果。

小结

回到开头的问题:为什么结构化采样能消除体渲染混叠?答案就藏在这两个公式里——dt保证世界空间采样间距恒定,t_0保证每条光线都从正确的分层起点出发。这两行代码,加上十二面体提供的多方向平面族和权重混合,构成了 volsample 全部魔法的基础。如果你正在做实时体积渲染、体积云或体雾,不妨从 RayMarchCore.cginc 开始读起,它不到 220 行,却是理解体渲染抗锯齿的一条捷径。💡

【免费下载链接】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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/19 19:28:07

NuvioMobile 插件安装完整实战指南:半小时从空壳到装满影视资源

NuvioMobile 插件安装完整实战指南&#xff1a;半小时从空壳到装满影视资源 【免费下载链接】NuvioMobile Official Nuvio Mobile Repository 项目地址: https://gitcode.com/gh_mirrors/nu/NuvioMobile NuvioMobile 是一款基于 Kotlin Multiplatform 打造的跨平台媒体中…

作者头像 李华
网站建设 2026/8/19 19:23:21

OnionOS 定制系统从零到一安装教程:Miyoo Mini 掌机升级上手指南

OnionOS 定制系统从零到一安装教程&#xff1a;Miyoo Mini 掌机升级上手指南 【免费下载链接】Onion OS overhaul for Miyoo Mini and Mini 项目地址: https://gitcode.com/gh_mirrors/on/Onion 刚把 Miyoo Mini 从包装盒里拿出来那天&#xff0c;我对着原厂界面发了好一…

作者头像 李华
网站建设 2026/8/19 19:20:41

SceneJS光照与材质详解:3步让3D场景呈现真实质感

SceneJS光照与材质详解&#xff1a;3步让3D场景呈现真实质感 【免费下载链接】scenejs An extensible WebGL-based 3D engine. This is an archived project. 项目地址: https://gitcode.com/gh_mirrors/sce/scenejs SceneJS 是一款基于 WebGL 的可扩展 3D 引擎&#xf…

作者头像 李华
网站建设 2026/8/19 19:20:18

scrcpy 安卓投屏新手完整指南:10 分钟完成安装、连接与画质调优

scrcpy 安卓投屏新手完整指南&#xff1a;10 分钟完成安装、连接与画质调优 【免费下载链接】scrcpy Display and control your Android device 项目地址: https://gitcode.com/GitHub_Trending/sc/scrcpy scrcpy 是一款免费开源的安卓投屏工具&#xff0c;它能将安卓手…

作者头像 李华