【从UnityURP开始探索游戏渲染】专栏-直达
深度偏移(Slope Scale Depth Bias)的作用
- 几何体表面因浮点精度限制导致的深度冲突(Z-fighting)
- 解决 Z-fighting 问题,调整片元深度值。
- 阴影贴图中的深度精度问题
- 透明物体渲染时的深度排序问题
- 细小几何体(如电线、毛发)的渲染稳定性
深度冲突(Z-fighting)
- 是当两个或多个几何表面在深度缓冲中具有极其接近的深度值时,GPU 无法可靠判断渲染顺序导致的视觉瑕疵,表现为表面像素闪烁或随机交替显示。这是由于透视投影下非线性深度分布及有限的深度缓冲精度(通常 24 位)所致,尤其远距离平面精度更差
- 深度偏移(Slope Scale Depth Bias)是图形渲染中用于解决深度冲突(Z-fighting)问题的重要技术。在Unity URP中,它通过调整像素的深度值来避免几何体表面之间的深度测试冲突.
深度偏移(Slope Scale Depth Bias)解决原理
通过动态调整顶点深度值,人为制造深度间隙避免冲突。其核心参数组合为:
Units
Factor
- 基于表面斜率的动态偏移量(变量),计算公式为:
- 动态偏移量 = Factor × max(|∂z/∂x|, |∂z/∂y|)
- 倾斜表面(如斜坡、墙壁)斜率大,自动获得更大偏移
- 平坦表面偏移较小,避免过度分离
- 最终深度修正公式:
最终深度值 = 原始深度值 + (Units × 最小深度单位) + (动态偏移量)
- ZFightingFix.shader
- Shader "URP/ZFightingFix" {
- Properties {
- _MainTex ("Texture", 2D) = "white" {}
- _Units ("Units", Float) = 0 // 固定偏移
- _Factor ("Slope Factor", Float) = 0 // 坡度系数
- }
- SubShader {
- Tags { "RenderPipeline"="UniversalPipeline" }
- Pass {
- HLSLPROGRAM
- #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
-
- struct Attributes {
- float4 positionOS : POSITION;
- float3 normalOS : NORMAL;
- };
- struct Varyings {
- float4 positionCS : SV_POSITION;
- };
-
- float _Units, _Factor;
- Varyings vert(Attributes v) {
- Varyings o;
- // 转换到裁剪空间
- o.positionCS = TransformObjectToHClip(v.positionOS.xyz);
-
- // 计算表面斜率(视图空间法线Z分量)
- float3 normalVS = normalize(TransformWorldToViewDir(
- TransformObjectToWorldNormal(v.normalOS)
- ));
- float slope = abs(normalVS.z); // Z越小表面越陡峭
-
- // 应用深度偏移
- float bias = _Units * 0.0001 + _Factor * (1 - slope);
- o.positionCS.z -= bias * o.positionCS.w; // 按w缩放适配透视
- return o;
- }
- // ... 片元着色器省略
- ENDHLSL
- }
- }
- }
复制代码 具体使用方法
关键参数说明
- _DepthBias: 固定深度偏移量,正值使物体看起来更近
- _SlopeScale: 基于表面斜率的动态偏移量,解决陡峭表面的深度冲突
- output.positionCS.z += ...: 在裁剪空间直接修改深度值
- slope计算: 基于法线向量计算表面斜率
参数建议
- 对于阴影渲染,建议使用较小的_DepthBias值(0.001-0.01)
- 对于复杂地形,可增加_SlopeScale值(0.1-1.0)
- 在URP管线下,也可通过Renderer组件的ShadowCastingMode设置全局深度偏移
- 法线贴图会影响实际斜率计算,需在切线空间正确转换法线向量
- DepthBiasExample.shader
- Shader "Custom/DepthBiasExample"
- {
- Properties
- {
- _MainTex ("Texture", 2D) = "white" {}
- _DepthBias ("Depth Bias", Float) = 0
- _SlopeScale ("Slope Scale", Float) = 0
- }
-
- SubShader
- {
- Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalPipeline" }
-
- Pass
- {
- HLSLPROGRAM
- #pragma vertex vert
- #pragma fragment frag
-
- #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
-
- struct Attributes
- {
- float4 positionOS : POSITION;
- float2 uv : TEXCOORD0;
- };
-
- struct Varyings
- {
- float4 positionCS : SV_POSITION;
- float2 uv : TEXCOORD0;
- };
-
- CBUFFER_START(UnityPerMaterial)
- float _DepthBias;
- float _SlopeScale;
- CBUFFER_END
-
- TEXTURE2D(_MainTex);
- SAMPLER(sampler_MainTex);
-
- Varyings vert(Attributes input)
- {
- Varyings output;
- output.positionCS = TransformObjectToHClip(input.positionOS.xyz);
-
- // 应用深度偏移
- output.positionCS.z += _DepthBias * output.positionCS.w;
-
- // 基于斜率应用额外偏移
- float3 normalVS = TransformWorldToViewDir(float3(0,1,0)); // 示例法线
- float slope = 1.0 - abs(normalVS.z);
- output.positionCS.z += _SlopeScale * slope * output.positionCS.w;
-
- output.uv = input.uv;
- return output;
- }
-
- half4 frag(Varyings input) : SV_Target
- {
- return SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, input.uv);
- }
- ENDHLSL
- }
- }
- }
复制代码
【从UnityURP开始探索游戏渲染】专栏-直达
(欢迎点赞留言探讨,更多人加入进来能更加完善这个探索的过程,
来源:豆瓜网用户自行投稿发布,如果侵权,请联系站长删除 |