【Unity Shader入门精要 第8章】透明效果(二)

1. 透明度测试

透明度测试的原理是将片元的 Alpha 值与某个指定的阈值进行比较,当 Alpha 超过阈值时,该片元正常显示,若 Alpha 值低于指定的阈值,则将该片元丢弃。准确来讲,透明度测试并不是为了渲染一种半透的效果,而是为了通过片元的 Alpha 值进行筛选,确定哪些像素需要渲染哪些像素不需要渲染,跟我们之前提到过的深度测试的效果是一样的,只不过筛选条件不同。

实际上,在透明度测试中,与阈值进行比较的并不一定必须是Alpha值,我们可以用采样得到的任意通道的值——甚至是某个计算得到的值,只要是我们通过某种方式可以掌控的值——来跟阈值进行比较。其重点是通过设定的阈值对像素进行筛选,以确定像素是否需要被丢弃。

因此,透明度测试的结果要么完全不显示,要么正常显示。

【Unity Shader入门精要 第2章】渲染流水线 中我们曾经提到过,存在透明度测试时无法开启Early-Z,正是因为如果开启了 Early-Z,那么在进入片元着色器之前就已经完成了深度测试,此时像素的深度值就会被写入到深度缓冲当中。接着进入片元着色器,发现当前片元的 Alpha 值没有达到阈值,于是该片元被舍弃不会进行渲染,但已经写入深度缓冲中的深度值又不会被撤回,结果就导致深度缓存出错。

2. 示例

  • 创建 Chapter_8_AlphaTest_Mat 作为测试材质
  • 创建 Chapter_8_AlphaTest_Shader 作为测试shader,并赋给 Chapter_8_AlphaTest_Mat 材质
  • 场景中创建一个用于测试的立方体,将 Chapter_8_AlphaTest_Mat 材质赋给立方体
  • 场景中添加一盏平行光,并调整平行光角度
  • 为了便于观察效果,在立方体下方创建一个Plane

使用的测试纹理如下:
在这里插入图片描述
在Shader中增加 _AlphaTest 属性,用于控制进行透明度测试的阈值

在SubShader中设置标签

Tags {"Queue" = "AlphaTest" "IgnoreProjector" = "True" "RenderType" = "TransparentCutout"}

在片元着色器中,使用了clip 方法进行裁剪,该方法的参数可以传入float

void clip(float _checkValue);

此时若 _checkValue 小于0,则会舍弃当前片元的颜色输出,否则正常输出。
也可以传入float2、float3等矢量

void clip(float3 _checkValue);

此时,若 _checkValue 中的任意一个分量小于0,均会舍弃当前片元的颜色输出,否则正常输出。

在 Inpector 面板中改变 AlphaTest属性的值,即可看到效果。
在这里插入图片描述

最终Shader如下:

Shader "MyShader/Chapter_8/Chapter_8_AlphaTest_Shader"
{
    Properties
    {
        _MainTex("MainTex", 2D) = "white"{}
        _AlphaTest("AlphaTest", range(0, 1)) = 0
    }
    
    SubShader
    {
    	Tags {"Queue" = "AlphaTest" "IgnoreProjector" = "True" "RenderType" = "TransparentCurout"}
    	
        Pass
        {
            Tags {"LightMode" = "ForwardBase"}
        
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #include "Lighting.cginc"
            
            struct a2v
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
                float2 uv : TEXCOORD0;
            };
            
            struct v2f
            {
                float4 vertex : SV_POSITION;
                float2 uv : TEXCOORD0;
                float3 worldNormal : TEXCOORD1;
            };
            
            sampler2D _MainTex;
            float4 _MainTex_ST;
            fixed _AlphaTest;
            
            v2f vert(a2v i)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(i.vertex);
                o.worldNormal = mul(i.normal, (float3x3)unity_WorldToObject);
                o.uv = TRANSFORM_TEX(i.uv, _MainTex);
                return o;
            }
            
            fixed4 frag(v2f i) : SV_Target
            {
                fixed3 _ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;
                float3 _worldNormal = normalize(i.worldNormal);
                float3 _worldLight = normalize(_WorldSpaceLightPos0.xyz);
                fixed4 _sampledColor = tex2D(_MainTex, i.uv);
                clip(_sampledColor.w - _AlphaTest);
                fixed3 _diffuse = _LightColor0.rgb * _sampledColor.xyz * (0.5 * dot(_worldLight, _worldNormal) + 0.5);
                return fixed4(_ambient + _diffuse, 1);
            }
            
            ENDCG
        }
    
    }

}

效果如下:
在这里插入图片描述

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值