Depth Test 深度测试

在这里插入图片描述
深度测试在模板测试之后,透明度混合之前,如果开启了深度测试,GPU会把该片元的深度值和已经存在于深度缓冲区(Depth Buffer 或者叫 Z-Buffer)中的深度值进行比较,这个比较函数可由开发者设置的,例如片元的深度值大于缓冲区深度值时舍弃该片元

从逻辑上理解

if(ZWrite On && (currentDepthValue ComparisonFunction DepthBufferValue))
	写入深度
else
	丢弃像素
if(currentDepthValue ComparisonFunction DepthBufferValue)
	写入颜色缓冲
else
	不写入颜色缓冲

深度缓冲中,对于每一个像素都存储一个深度值,注意这个深度值是非线性的,近处的精度高,远处的精度低。ZTest分为通过和不通过两种情况,ZWrite分为开启和关闭两种情况,一共四种情况

  1. 深度测试通过,深度写入开启,写入深度缓冲区,写入颜色缓冲区
  2. 深度测试通过,深度写入关闭,不写深度缓冲区,写入颜色缓冲区
  3. 深度测试失败,深度写入开启,不写深度缓冲区,不写颜色缓冲区
  4. 深度测试失败,深度写入关闭,不写深度缓冲区,不写颜色缓冲区

深度测试的比较方法 ComparisonFunction ,和模板测试差不多

比较方法描述
Greater深度大于当前缓冲则通过
GEqual深度大于等于当前缓存则通过
Less深度小于当前缓存则通过
LEqual深度小于等于当前缓存则通过
Equal深度等于当前缓存则通过
NotEqual深度不等于当前缓存则通过
Always深度不论如何都通过
Never深度不论如何都不通过

默认是ZWrite On和ZTest LEqual

  • 不透明物体的渲染顺序:从前往后
  • 透明物体的渲染顺序:从后往前

下面几种情况显示,ZTest,ZWrite和渲染队列如何影响渲染,蓝色立方体离摄像机最近,红色离的最远
在这里插入图片描述
这是默认设置,从近到远,先渲染蓝色,深度缓冲区默认是无穷大,蓝色深度小于无穷大,深度测试通过,写入深度,写入颜色缓冲,再渲染绿色,在蓝色和绿色相交的部分,绿色的深度大于蓝色,深度测试不通过,其他部分正常写入深度,最后渲染红色同理
在这里插入图片描述
渲染蓝色,深度测试通过,但是它关闭的深度写入,不写入深度值,写入颜色缓冲,渲染绿色,深度测试通过,写入深度值和颜色,替换掉之前的蓝色
在这里插入图片描述
渲染蓝色,和第一张图情况一样,绿色的ZTest设置为Always,不管深度值如何都通过深度测试,写入深度和颜色,重叠部分覆盖蓝色深度值
在这里插入图片描述
红色ZTest也改成Always,原理和绿色覆盖蓝色是一样的
在这里插入图片描述
绿色的渲染队列调整为Geometry+1,越大越后渲染,渲染顺序是:蓝,红,绿,先按照渲染队列排序,同一个队列,不透明物体按照从近到远排列
在这里插入图片描述
绿色ZTest选择Greater,表示当前深度大于深度缓冲区深度才能通过,蓝绿重叠部分,绿色深度大于蓝色深度,深度测试通过,其他部分绿色深度小于无穷大,深度测试不通过

可以使用下面的Shader验证

Shader "MyCustom/ZTestZWrite"
{
    Properties
    {
        _Color ("_Color", Color) = (1, 0, 0, 1)
        //自定义枚举
        [Enum(Off, 0, On, 1)]_ZWriteMode ("ZWriteMode", Float) = 1
        [Enum(UnityEngine.Rendering.CompareFunction)]_ZTestComp ("ZTestComp", Int) = 4
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" "Queue"="Geometry" }
        ZWrite [_ZWriteMode]
        ZTest [_ZTestComp]

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
            };

            float4 _Color;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                return _Color;
            }
            ENDCG
        }
    }
}

XRay效果

在这里插入图片描述
使用深度测试,实现角色在墙后显示描边的效果,这里用2个Pass实现
第一个Pass渲染描边,角色的深度大于墙的深度,为了让角色通过深度测试需要设置 ZTest Greater,并且需要保持正常的遮挡关系,所以渲染描边时不能写入深度,实现这种半透明效果还要设置混合因子
第二个Pass就是正常的渲染

Shader "MyCustom/XRay"
{
    Properties
    {
        _MainTex("Base 2D", 2D) = "white" {}
        _XRayColor ("XRay Color", Color) = (1, 0, 0, 1)
    }
    SubShader
    {
        CGINCLUDE
        #include "UnityCG.cginc"

        float4 _XRayColor;
        
        struct v2f
        {
            float4 pos : SV_POSITION;
            float3 normal : NORMAL;
            float3 viewDir : TEXCOORD0;
            fixed4 color : COLOR;
        };

        v2f vertXRay(appdata_base v)
        {
            v2f o;
            o.pos = UnityObjectToClipPos(v.vertex);
            //模型顶点到相机方向(模型空间)
            o.viewDir = ObjSpaceViewDir(v.vertex);
            o.normal = v.normal;

            float3 normal = normalize(v.normal);
            float3 viewDir = normalize(o.viewDir);
            float rim = 1 - dot(normal, viewDir);
            o.color = _XRayColor * rim;
            return o;
        }

        fixed4 fragXRay(v2f i) : SV_Target
        {
            return i.color;
        }

        sampler2D _MainTex;
        float4 _MainTex_ST;

        struct v2f2
        {
            float4 pos : SV_POSITION;
            float2 uv : TEXCOORD0;
        };

        v2f2 vertNormal(appdata_base v)
        {
            v2f2 o;
            o.pos = UnityObjectToClipPos(v.vertex);
            o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
            return o;
        }

        fixed4 fragNormal(v2f2 i) : SV_Target
        {
            return tex2D(_MainTex, i.uv);
        }
        ENDCG

        //XRay
        Pass
        {
            Tags { "RenderType"="Transparent" "Queue"="Transparent" }
            ZWrite Off
            ZTest Greater
            Blend SrcAlpha One
            
            CGPROGRAM
            #pragma vertex vertXRay
            #pragma fragment fragXRay
            ENDCG
        }
        
        //正常绘制
        Pass
        {
            Tags { "RenderType"="Opaque" "Queue"="Geometry" }
            ZWrite On
            ZTest LEqual
            
            CGPROGRAM
            #pragma vertex vertNormal
            #pragma fragment fragNormal
            ENDCG
        }
    }
}

在这里插入图片描述
对于多Pass渲染,Unity会从多个Pass里选择渲染队列最靠前的,把物体放在这个队列渲染,这里第一个Pass是Transparent,第二个Pass是Geometry,Geometry靠前渲染就放在了Geometry队列,然后会根据Pass顺序执行

参考

【技术美术百人计划】图形 3.1 深度与模板测试 传送门效果示例

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值