读书笔记12《Unity Shader入门精要》

铁名_IronName Lv4

第 13 章 使用深度和法线纹理

Unity 中的获取方法

在 Unity 中获取深度纹理:

1
camera.depthTextureMdoe = DepthTextureMode.Depth;

在 Shader 中通过_CameraDepthTexture访问。

获取 深度+法线纹理:

1
camera.depthTextureMode = DepthTextureMode.DpethNormals;

在 Shader 中通过_CameraDepthNormalsTexture访问。

让一个摄像机同时产生一张深度纹理 和 一张深度+法线纹理

1
2
camera.depthTextureMdoe |= DepthTextureMode.Depth;
camera.depthTextureMode |= DepthTextureMode.DpethNormals;

Unity 有统一宏 SAMPLE_DEPTH_TEXTURE 对深度纹理采样。

1
float d = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv);

深度纹理的值是非线性的,需要变换。zviewz_{view} 是负数,z01z_{01} 是范围在 [0, 1] 的线性深度值。

zview=1FarNearNearFard1Nearz_{view}=\frac{1}{\frac{Far-Near}{Near\cdot Far}d-\frac{1}{Near}} z01=1NearFarNeard+FarNearz_{01}=\frac{1}{\frac{Near-Far}{Near}d+\frac{Far}{Near}}

当然,Unity 中有辅助函数来进行上述计算。

查看方法

如果摄像机需要生成深度和法线纹理,那么在 Frame Debugger 中就能看到。看到的深度纹理是非线性的,而深度+法线纹理是由 Unity 编码后的结果。
想要看到线性的深度值:

1
2
3
float depth = SMAPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv);
float linearDepth = Linear01Depth(depth);
return fixed4(linearDepth, linearDepth, linearDepth, 1.0);

法线方向:

1
2
fixed3 normal = DecodeViewNormalStereo(tex2D(_CameraDepthNormalsTexture, i.uv).xy);
return fixed4(normal * 0.5 + 0.5, 1.0);

基于速度映射的运动模糊

实践

实现使用速度映射图的运动模糊。

本节实现的运动模糊适用与场景静止、摄像机快速运动的情况。若摄像机静止,对快速运动的物体不会产生效果。

全局雾效

重建世界坐标

只需要知道摄像机在世界空间下的位置,以及世界空间下该像素相对于摄像机的偏移量,把它们相加就可以得到该像素的世界坐标。

1
float4 worldPos = _WorldSpaceCameraPos + linearDepth * interpolatedRay;

interpolatedRay 来源于对近裁切平面的 4 个角的某个特定向量的插值。

雾的计算

1
float3 afterFog = f * fogColor + (1 - f) * origColor;

雾效系数 f 有多种算法。Unity 内置的雾效实现有三种:
线性(Linear),dmaxd_{max}dmind_{min} 分别表示受雾影响的最大距离和最小距离

f=dmaxzdmaxdminf=\frac{d_{max}-|z|}{d_{max}-d_{min}}

指数(Exponential),dd 是控制雾的浓度的参数

f=edzf=e^{-d\cdot|z|}

指数的平方(Exponential Squared),dd 是控制雾的浓度的参数

f=e(dz)2f=e^{-(d\cdot|z|)^2}

实践

基于高度的雾效

f=HendyHendHstartf=\frac{H_{end}-y}{H_{end}-H_{start}}
实践

在 Unity 中实现基于屏幕后处理的雾效。

  • UnityCG.cginc 里包含 appdata_img 结构体。小心重复。

改进的边缘检测

实践

在 Unity 中实现基于深度和法线纹理的描边效果。

  • 在 OnRenderImage 函数前添加 [ImageEffectOpaque] 属性,这样这个函数就会在不透明物体渲染完成之后(半透明物体渲染之前),调用。也就是不会给半透明物体描边。

拓展:神奇的深度图:复杂的效果,不复杂的原理

  • 标题: 读书笔记12《Unity Shader入门精要》
  • 作者: 铁名_IronName
  • 创建于 : 2026-01-28 09:43:54
  • 更新于 : 2026-02-15 15:21:03
  • 链接: https://blog.ironname.top/2026/01/28/读书笔记12《Unity-Shader入门精要》/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论