【URP】什么是[深度偏移](Slope Scale Depth Bias)‌

【从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

    c 复制代码
    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

    c 复制代码
    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开始探索游戏渲染】专栏-直达

(欢迎点赞留言探讨,更多人加入进来能更加完善这个探索的过程,🙏)

相关推荐
天人合一peng1 天前
unity 生成标记根据背景色标记变色
unity·游戏引擎
天人合一peng2 天前
unity 生成标记根据背景色变色为明显的颜色
unity·游戏引擎
魔士于安2 天前
Unity 超市总动员 超市收银台 超市货架 超市购物手推车 超市常见商品
游戏·unity·游戏引擎·贴图·模型
CandyU22 天前
Unity —— 数据持久化
unity·游戏引擎
zh路西法2 天前
【Unity实现Oneshot胶卷显形】游戏窗口化与Win32API的使用
游戏·unity·游戏引擎
凡情2 天前
android隐私合规检测
android·unity
小贺儿开发2 天前
Unity3D 本地 Stable Diffusion 文生图效果演示
人工智能·unity·stable diffusion·文生图·ai绘画·本地化
mxwin3 天前
Unity Shader 半透明物体为什么不能写入深度缓冲?
unity·游戏引擎·shader
晚枫歌F3 天前
三层时间轮的实现
网络·unity·游戏引擎
咸鱼永不翻身3 天前
Lua脚本事件检查工具
unity·lua·工具