Shader入门精要学习记录4

在Unity中,使用两种方法实现透明效果:
1.透明度测试(Alpha Test)
2.透明度混合(Alpha Blending)

透明度测试:

它采用的机制是只要有个片元的透明度不满足条件,那么它对应的片元就会被舍弃。被舍弃的片元不会再进行任何处理,也不会对颜色缓冲产生影响;否则,就会按普通的不透明物体的处理方式处理。即进行深度测试,深度写入等。透明度测试是不需要关闭深度写入的,它和其它不透明物体最大的不同就是它会根据透明度舍弃一些片元。虽然简单,但是产生的效果也很极端,要么完全透明,即看不到,要么完全不透明,就像不透明物体那样。

透明度混合

这种方法可以得到真正的半透明效果,它会使用当前片元的透明度作为混合因子,与已经储存在颜色缓冲中的颜色值进行混合,得到新的颜色。但是,透明度混合需要关闭深度写入,这样我们要非常小心物体的渲染顺序。需要注意的是,透明度混合只关闭了深度写入,但没有关闭深度测试。这意味着,当使用透明度混合渲染一个片元时,还是会比较它的深度值与当前深度缓冲中的深度值,如果它的深度值距离摄像机更远,那么就不会进行混合操作。这一点决定了,当一个不透明物体出现在一个透明物体的前面,而我们先渲染了不透明物体,它仍然可以正常地遮挡住透明物体。也就是说,对于透明度混合来说,深度缓冲是只读的。

半透明物体之间也是要符合一定的渲染顺序的,渲染引擎一本都会对物体进行排序,再渲染,常用方法是:
1.先渲染所有不透明物体,并开启它们的深度测试和深度写入。
2.把半透明物体按照它们距离摄像机的远近进行排序,然后按照从后往前的顺序渲染这些半透明物体,并开启它们的深度测试,但关闭深度写入。

这里写图片描述

透明度测试

透明度测试卷:只要一个片元的透明度不满足条件,那么它对应的片元就会被舍弃。被舍弃的片元不会再进行任何处理,也不会对颜色缓冲产生任何影响;否则就会按照普通的不透明物体的处理方式来处理它。
通常,我们会在片元着色器中使用clip函数来进行透明度测试。clip是CG中的一个函数。
函数: void Clip(float4 x);void Clip(float3 x);void Clip(float2 x);void Clip(float1 x);void Clip(float x);
参数:裁剪时使用的标量或矢量条件。
描述:如果给定参数的任何一个分量是负数,就会舍弃当前像素的输出颜色,它等同于下面的代码:
这里写图片描述
通常使用了透明度测试的shader都应该在subshader中设置这三个标签。
这里写图片描述

“Queue”=”AliphaTest” 透明度测试使用的渲染队列。
“RenderType”=”TransparentCutout” RenderType标签可以让Unity把这个shader提前归入定义的组中。
“IgnoreProjector”=”True” 这意味着这个shader不会受到投影器的影响。

Shader "Practice/AlphaTest"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _CutOff("CutOff",Range(0,1))=0.5
    }
    SubShader
    {
        Tags { "Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _CutOff;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2D(_MainTex, i.uv);
                clip(col.w-_CutOff);
                return col;
            }
            ENDCG
        }
    }
}

注意Tag三个的配套使用

透明度混合

透明度混合的实现比透明度测试复杂一些,这是因为在处理透明度测试时,实际上跟对待普通的不透明物体几乎一样。只是在片元着色器中添加了对透明度判断并裁剪片元的代码。

透明度混合:这种方法可以得到真正的半透明效果。它会使用当前片元的透明度作为混合因子,与已经储存在颜色缓冲中的颜色值进行混合,得到新的颜色。但是,透明度混合需要关闭深度写入,这使得我们要非常小心物体的渲染顺序。

为了进行混合我们需要使用Unity提供的混合命令-Blend。Blend是Unity提供的混合模式的命令。想要实现半透明的效果就是要把当前自身的颜色和已经存在于颜色缓冲中的颜色值进行混合,混合时使用的函数就是由该指令决定的。

Blend Off 关闭混合

Blend SrcFactor DsFactor 开启混合并设置混合因子。源颜色(改片元产生的颜色)会乘以SrcFactor,而目标颜色(已经存在于颜色缓存的颜色)会乘以DstFactor,然后把两者相加后再存入颜色缓冲中。

Blend SrcFactor DsFactor, SrcFactorA DstFactorA 和上面几乎一样,只是使用不同的因子来混合透明通道。

BlendOp BelendOperation 并非是把源颜色和目标颜色简单相加后混合,而是使用BlendOperation对它们进行其他操作。

Shader "Practice/AplphaBlend"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="TransparentCutout" }
        Pass
        {
            ZWrite Off
            Blend SrcAlpha OneMinusSrcAlpha
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _CutOff;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2D(_MainTex, i.uv);
                return col;
            }
            ENDCG
        }
    }
}

当模型本身又复杂的遮挡关系或是包含了复杂的非凸网格的时候。就会有各种各样因为排序错误而产生的错误的透明效果。这就时候就需要 开启深度写入的半透明效果
这里写图片描述

开启深度写入的半透明效果

解决方法: 使用两个Pass来渲染模型: 第一个pass开启深度写入,但不输出颜色,它的目的仅仅是为了把该模型的深度值写入深度缓冲中;
第二个pass进行正常的透明度混合,由于上一个Pass已经得到了逐像素的正确的深度信息,该pass就可以按照像素级别的深度排序结果进行透明渲染。但这种方法的缺点在于,多使用一个pass会对性能造成一定的影响。
这里写图片描述

Shader "Practice/AplphaBlend"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="TransparentCutout" }
        Pass{
           ZWrite On
           ColorMask 0
        }
        Pass
        {
            ZWrite Off
            Blend SrcAlpha OneMinusSrcAlpha
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _CutOff;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2D(_MainTex, i.uv);
                return col;
            }
            ENDCG
        }
    }
}

ShaderLab 的混合命令

混合就和两个操作数有关: 源颜色 (Source Color) 目标颜色(Destination Color).
源颜色,我们用S表示:指的是由片元着色器产生的颜色值;
目标颜色,我们用D表示,指的是从颜色缓冲中读取到的颜色值;
对它们进行混合后得到的输出颜色,我们用O表示,它会重新写入到颜色缓冲中。
我们需要注意的是,当我们谈及混合中的源颜色,目标颜色和输出颜色时,它们都包含了RGBA四个通道的值,而并非仅仅是RGB通道。
想要使用混合,我们必须首先得开启它。在Unity中当我们使用Blend (Blend Off除外) 命令时,除了设置混合状态也开启了混合。但是在其他图形API中我们需要手动开启的。但在Unity中,它他已经在背后我们做这些工作。

混合等式和参数

混合是一个逐片元的操作,而且它不是可编程的,但确实高度配置的.也就是说,我们设置混合时使用的运算操作、混合因子等来影响混合,那么这些配置是如何实现的呢?
现在我们已知两个操作数:源颜色S和目标颜色D,想要得到输出颜色O 就必须使用一个等式来计算。我们把这个等式称为混合等式(blend equation)。当进行混合时,我们需要使用两个混合等式:一个用于混合RGB通道,一个用于混合A通道,到设置混合状态时,我们实际上设置的就是混合等式中的操作和因子。在默认情况下,混合等式使用的操作都是加操作,我们只需要再设置一下混合因子即可。由于需要两个等式,每个等式有两个因子因此共需要4个因子。
这里写图片描述

这里写图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值