返回作品索引WORK / CASE STUDY
Shader / 工具

URP - RendererFeature :局部体积雾(可交互)

局部体积雾

独立作品

内容分类URP - RendererFeature

让周围轻一点,文字近一点。
作品演示点击播放,可全屏观看
ENGINE
Unity · URP
TECH
Shader · rendering · unity · URP · RenderFeature · 后处理
ROLE
Shader · 工具
YEAR
2026
案例目录14 小节

射线的表示

包围盒

AABB

AABB — Axis-Aligned Bounding Box,轴对齐包围盒。这里我实现的是AABB,后续在添加旋转控制** “轴对齐”意思是盒子的六个面永远平行于世界坐标系的XYZ轴,不能旋转。这就是为什么代码里能用简单的min/max做求交——每个面都垂直于某一个轴,数学极其简单。

OBB

OBB — Oriented Bounding Box,有向包围盒。 允许任意旋转,盒子可以斜着放,贴合物体形状更紧密。

两者对比:

AABBOBB
旋转不能旋转,永远轴对齐任意旋转
求交复杂度极简单(就是你现在的代码)复杂(需要分离轴定理SAT)
贴合度差(斜放物体会有大量空白)好
用途体积雾、碰撞粗检测、BVH精确碰撞、物理引擎

射线与AABB求交集

因为公式是射线的表达式是:

r(t)=o+t⋅dr(t) = o + t·d

这里就直接求解:

o+t0⋅d=boundsMino + t_0·d = boundsMin o+t1⋅d=boundsMaxo + t_1·d = boundsMax

因为保证交点在box内部,所以射线到box最近点是tmin取最大,最远点tmax则取最小

基础框架搭建

这里我设想的是随意挂在空物体上构建一个局部体积雾,所以需要单独对局部体积雾制作一个类,然后由feature进行全局管理一次性跑完,交互类则是定为一个点可以挂在其他物体上,同理也需要单独一个类

CustomFogVolume

FogVolume类这里给了很多参数控制每个局部体积雾有不同效果,OnDrawGizmosSelected方便编辑器实时调整

CustomFogDisturber

Disturber扰动类,结构比较简单

CustomLocalVolumetricFogFeature

整体管理的Feature,代码和之前的全局体积雾是差不多的没什么区别,主要是传参方面,因为需要编辑器支持,所以需要在Feature中实时检索场景内的体积组件,不过这样数量会限制,不能过多。如果单独设置一个静态管理类的话比如CustomFogDisturberManager,应该可以省去检索的部分开销,但是缺点是没办法实时调整,必须在运行模式下看效果 这里添加存储的数据结构

然后在AddRenderPasses进行数据采集

剩下就是传值了,就是预先处理一下传数组就行,尽量把通道塞满了

CustomLocalVolumetricFogShader

其实和全局雾内容差不多,不过需要跑多次,所以放到循环中,起点和终点换成AABB的min和max

物体交互

交互扰动,这里使用球形的范围渐变来削减密度

添加CurlNoise

原始的CurlNoise公式如下

因为当前是标量场没有方向,所以直接求偏导,也就是采样6次

∂N/∂x ≈ (N(x+e) - N(x-e)) / (2e) //标准公式

这里没有除2e减少开销,而且normalize已经舍弃长度,所以不用除了

整体交互部分代码

这里可以看到边界处有涡流旋转的效果

边界衰减

这里可以得到弱化边界的效果

最终效果

这里把散射强度和扰动强度调的很高方便观察,要是实现非常精确的交互雾的话还是得用粒子雾,局部雾更适合场景摆放,因为光照步进它其实更加精确,不过基于屏幕占比开销会增加很多

URP - RendererFeature :体积雾