【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开始探索游戏渲染】专栏-直达

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

相关推荐
NRatel16 小时前
GooglePlay支付接入记录
android·游戏·unity·支付·googleplay
向宇it18 小时前
网站加载慢,linux服务器接口请求响应变慢,怎么排查,一般是什么原因
linux·运维·服务器·unity·游戏引擎·交互
新手小新18 小时前
unity学习——视觉小说开发(二)
学习·unity·游戏引擎
NRatel2 天前
Unity游戏打包——iOS打包pod的重装和使用
游戏·unity·ios·打包
SmalBox2 天前
【渲染管线】UnityURP[渲染顺序]与[层级]
unity·渲染
NRatel2 天前
Unity游戏打包——打包常见报错(含Android、iOS)
游戏·unity·游戏引擎
SmalBox3 天前
【渲染管线】UnityURP中[渲染路径]选择‌
unity·渲染
Glunn3 天前
记住密码管理器
unity
17岁的勇气4 天前
Unity Shader unity文档学习笔记(二十一):几种草体的实现方式(透明度剔除,GPU Instaning, 曲面细分+几何着色器实现)
笔记·学习·unity