雾与简易体积光照
Fog & Simple Volumetric Lighting
这类"老派"技巧依赖经验模型,但至今仍然好用:深度雾、高度雾和局部雾体积用透射率混合雾色;光柱可用拉伸的面向相机粒子、单次散射的解析积分、平面切片,或屏幕空间径向模糊实现(RTR4 14.2 节)。
雾的作用
增加真实感和氛围;帮助判断距离的重要深度线索(《战场 1》用深度雾表现场景尺度,用高度雾表现从山谷升起的建筑);可作为遮挡剔除——完全没入雾中的远处物体可以跳过不画。
深度雾
用 表示透射率( 表示背景可见 10%),表面色 、雾色 :
| 形式 | 公式 | 说明 |
|---|---|---|
| 线性 | 、 为雾开始与完全浓雾处, 为到表面的线性深度 | |
| 指数 | 符合 Beer-Lambert 定律, 控制浓度,物理上更准确 |
- 这是旧版 OpenGL/DirectX 硬件雾的接口,移动设备等简单场合仍值得用。现代游戏多用后处理:深度缓冲是非线性的,可用逆投影矩阵还原线性深度,再在全屏 pass 中实现高度雾、水下着色等。
- 雾色可以是单色、按视线采样的立方体贴图,甚至带逐像素相位函数的大气散射结果;深度雾与高度雾可相乘 共存。
高度雾与局部雾
- 高度雾:一块有参数化高度和厚度的介质层,按视线穿过它的距离计算密度和散射;Wenzel 给出层内介质指数衰减时 的闭式解,边缘过渡平滑。
- 局部雾(洞穴、墓地):用椭球或盒子,按包围盒从后往前渲染,像素着色器求视线与形状的前交点 和后交点 ,体积深度 ( 为最近不透明表面线性深度),由此得 ,覆盖率 ,叠加散射光 。
- 任意网格形状:Oat 与 Scheuermann 单 pass 求最近入点和最远出点——一个通道存表面距离 ,另一个存 ,混合模式取最小值,渲染后第一通道是 、第二通道编码了 。
水
水也是参与介质。近岸海水每米透射率约 ,可反推 。用不透明面画深色水时,相机在水下开启雾逻辑、水上关闭。Wenzel 的更好做法:水下时积分到碰到实体或水面为止;水上时只积分水面到海底实体之间的距离。
简易体积光照
- 网格溅射:窗户、密林、聚光灯的光柱用带纹理的面向相机粒子,沿光柱方向拉伸并保持面向相机(圆柱约束)。缺点:大量透明网格累加耗带宽,面向相机的四边形有时会露馅。
- 解析单次散射:假设均匀介质和各向同性相位函数,可闭式积分沿路径的散射光(含正确透射率),作为后处理或用于每个带深度的粒子。书中给出 GLSL 片段(参数为光线起点、单位方向、光源位置和积分距离),核心是一个反正切表达式:
float inScattering(vec3 rayStart, vec3 rayDir, vec3 lightPos, float rayDistance) {
vec3 q = rayStart - lightPos;
float b = dot(rayDir, q);
float c = dot(q, q);
float s = 1.0f / sqrt(c - b*b);
float x = s * rayDistance;
float y = s * b;
return s * atan((x) / (1.0 + (x + y) * y));
}
Sun 等额外考虑 ,以及光在到达朗伯/Phong 表面前走了非直线路径对其漫反射和高光的影响;考虑透射率和相位函数的版本 ALU 更重。这些模型都不能处理深度图阴影或非均匀介质。
- 泛光近似:模糊帧缓冲并把一小部分加回,亮物体周围就会"漏光",在短距离、无遮挡散射的环境里效果不错。
- 平面切片:Dobashi 等用一系列垂直视线的平面从后往前采样体积渲染大尺度大气效果;Mitchell 用同法做聚光灯光柱,并用阴影贴图让不透明物体投下体积阴影。
- 屏幕空间光柱(Mitchell、Rohleder 与 Jamrozik):在清黑的缓冲中于远平面太阳周围画一个假的亮物体,深度测试只保留未遮挡像素;再做以太阳为中心的方向模糊把亮度向外"漏"(可分离两遍各 样本,得到 样本的效果);最后加到场景上。高效、视觉收益大,缺点是只有屏幕上可见的光源能产生光柱。
GPU Gems 的视角:体积光散射后处理 / 耶稣光(GPU Gems 3 第 13 章)
来源:Kenny Mitchell《Volumetric Light Scattering as a Post-Process》;摘录 Chapter 13. Volumetric Light Scattering as a Post-Process — Kenny Mitchell。对应上文「屏幕空间光柱」路线,把 Hoffman–Preetham 昼光解析模型接到遮挡估计上。
思路:在屏幕空间沿像素到光源的射线累加采样,用「击中发光区 vs 击中遮挡物」的比例估计 ,再对源照明做衰减。实现就是带 Weight / Decay / Density / Exposure 的径向模糊;衰减指数让光柱离开光源平滑收束。半透明遮挡无需特判;多光源就多趟加法合成。
纹理对比会拉出假条纹,可用遮挡预通道(遮挡物画成黑、无纹理)再合成,或模板标记天空,或靠雾/大气透视压对比。局限:近景物体前可能出现「本该被挡住的背景光柱」(有时被看成镜头散射);遮挡物出画会闪(可渲染超扫描区域);光源近乎垂直视线时屏幕位置趋于无穷(钳制或淡出)。Shader Model 3 可单 pass 循环;更老硬件用多遍帧缓冲加法。这与 froxel 体积光照不同:几乎零场景设置,但不是物理厚度积分。
出处
- realtime_rendering_4ed.pdf 第 14 章 Volumetric and Translucency Rendering
- Chapter 13. Volumetric Light Scattering as a Post-Process — Kenny Mitchell
- developer.nvidia.com/gpugems/gpugems3/part-ii-light-and-shadows/chapter-13-volumetric-light-scattering-post-process