国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

《Unity 入門精要》第8章 透明效果

這篇具有很好參考價值的文章主要介紹了《Unity 入門精要》第8章 透明效果。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報違法"按鈕提交疑問。

第8章 透明效果

在 Unity 中,我們通常使用兩種方法來實現(xiàn)透明效果:透明度測試(Alpha Test)透明度混合(Alpha Blending)。
當(dāng)我們渲染不透明物體時,我們不需要特別考慮渲染順序的問題,因為有深度緩沖(depth buffer,也稱 z-buffer)的存在,它的基本思想是:根據(jù)深度緩存中的來判斷該片元距離攝像機(jī)的距離,當(dāng)渲染一個片元是,需要把它的深度值和已經(jīng)存在于深度緩存中的值來做對比,如果它的值距離攝像機(jī)更遠(yuǎn),那么說明這個片元不應(yīng)該被渲染到屏幕上;否則,這個片元應(yīng)該覆蓋掉此時顏色緩沖中的像素值,并把它的深度值更新到深度緩沖中。
但如果想要實現(xiàn)透明效果,事情就不那么簡單了,這是因為,當(dāng)使用透明度混合時,我們關(guān)閉了深度寫入(Write)。
簡單來說,透明度測試和透明度混合的基本原理如下:

  • 透明度測試:它采用一種“霸道極端”的機(jī)制,只要一個片元的透明度不滿足條件(通常是小于某個閾值),那么它對應(yīng)的片元就會被舍棄。被舍棄的片元將不會再進(jìn)行任何處理,也不會對顏色緩沖產(chǎn)生任何影響;否則,就會按照普通的不透明物體的處理方式來處理它,即進(jìn)行深度測試、深度寫入等。也就是說,透明度測試是不需要關(guān)閉深度寫入的,它和其他不透明物體最大的不同就是它會根據(jù)透明度來舍棄一些片元。雖然簡單,但是它產(chǎn)生的效果也很極端,要么完全透明,要么完全不透明。
  • 透明度混合:這種方法可以得到真正的半透明效果。它會使用當(dāng)前片元的透明度作為混合因子,與已經(jīng)存儲在顏色緩沖中的顏色值進(jìn)行混合,得到新的顏色。但是,透明度混合需要關(guān)閉深度寫入,這使得我們要非常小心物體的渲染順序。需要注意的是,透明度混合只關(guān)閉了深度寫入,但沒有關(guān)閉深度測試。這意味著,當(dāng)使用透明度混合渲染一個片元時,還是會比較它的深度值與當(dāng)前深度緩沖中的深度值,如果它的深度值距離攝像機(jī)更遠(yuǎn),那么就不會再進(jìn)行混合操作。這一點(diǎn)決定了,當(dāng)一個不透明物體出現(xiàn)在一個透明物體的前面,而我們先渲染了不透明物體,它仍然可以正常地遮擋住透明物體。也就是說,對于透明度混合來說,深度緩沖是只讀的。

8.1 為什么渲染順序很重要

在使用透明度混合時,需要關(guān)閉深度寫入,此時渲染順序?qū)⒆兊梅浅V匾N覀兛梢运伎家幌乱韵聨追N渲染情況。

半透明物體 A + 不透明物體 B,A 在 B 前

《Unity 入門精要》第8章 透明效果
此種情況有兩種渲染順序:

  • 先渲染 B 再渲染 A, B 會正常寫入顏色緩沖,然后 A 會和顏色緩沖中的 B 顏色進(jìn)行混合,得到正確的半透明效果
  • 先渲染 A 再渲染 B,A 會正常寫入顏色緩沖,但是因為半透明物體關(guān)閉了深度寫入,因此 A 不會修改深度緩沖。接著渲染 B,B會進(jìn)行深度測試,它發(fā)現(xiàn),“咦,深度緩存中還沒有人來過,那我就放心地寫入顏色緩沖了!”,結(jié)果就是 B 會直接覆蓋 A 的顏色,從視覺上來看,B就出現(xiàn)在了A的前面,而這是錯誤的。

由此可知,我們應(yīng)該在渲染完不透明物體后再渲染半透明物體。

A B 均為半透明,A 在 B 前

《Unity 入門精要》第8章 透明效果
此種情況有兩種渲染順序:

  • 先渲染 B 再渲染 A, B 會正常寫入顏色緩沖,然后 A 會和顏色緩沖中的 B 顏色進(jìn)行混合,得到正確的半透明效果
  • 先渲染 A 再渲染 B,A 會正常寫入顏色緩沖,然后 B 會和顏色緩沖中的 A 顏色進(jìn)行混合,這樣混合結(jié)果會完全反過來,看起來就好像 B 在 A 前面一樣,得到錯誤的半透明結(jié)構(gòu)。

可以看出,半透明物體之間應(yīng)該先渲染離攝像機(jī)遠(yuǎn)的物體再渲染近的,才能得到正確的效果。

循環(huán)重疊的半透明物體

基于前面兩點(diǎn),渲染引擎通常會對物體的渲染順序做一下兩點(diǎn)優(yōu)化:

  1. 先渲染所有不透明物體,并開啟它們的深度測試和深度寫入。
  2. 把半透明物體按它們距離攝像機(jī)的遠(yuǎn)近進(jìn)行排序,然后按照從后往前的順序渲染這些半透明物體,并開啟它們的深度測試,但關(guān)閉深度寫入。

但就算做了這兩點(diǎn)優(yōu)化,有些時候還是會出現(xiàn)錯誤的透明效果,比如存在循環(huán)重疊的物體:
《Unity 入門精要》第8章 透明效果
這是因為深度緩沖中的值其實是像素級別的,即每個像素有一個深度值,但是現(xiàn)在我們對單個物體級別進(jìn)行排序,這意味著排序結(jié)果是,要么物體 A 全部在 B 前面渲染,要么 A 全部在 B 后面渲染。但如果存在循環(huán)重疊的情況,我們永遠(yuǎn)不可能得到一個正確的排序順序。這種時候,我們可以選擇把物體拆分成兩個部分,然后再進(jìn)行正確的排序。但即便我們通過分割的方法解決了循環(huán)覆蓋的問題,還是會有其他的錯誤情況。

無法判定物體排序規(guī)則的情況

《Unity 入門精要》第8章 透明效果
這里的問題是:如何排序?我們知道,一個物體的網(wǎng)格結(jié)構(gòu)往往占據(jù)了空間中的某一塊區(qū)域,也就是說,這個網(wǎng)格上每一個點(diǎn)的深度值可能都是不一樣的,我們選擇哪個深度值來作為整個物體的深度值和其他物體進(jìn)行排序呢?是網(wǎng)格中點(diǎn)嗎?還是最遠(yuǎn)的點(diǎn)?還是最近的點(diǎn)?不幸的是,對于上圖中的情況,選擇哪個深度值都會得到錯誤的結(jié)果,我們的排序結(jié)果總是 A 在 B 的前面,但實際上 A 有一部分被 B 遮擋了。這也意味著,一旦選定了一種判斷方式后,在某些情況下半透明物體之間一定會出現(xiàn)錯誤的遮擋問題。這種問題的解決方法通常也是分割網(wǎng)格。
盡管總是會有一些情況打亂我們的陣腳,但由于上述方法足夠有效并且容易實現(xiàn),因此大多數(shù)游戲引擎都使用了這樣的方法。為了減少錯誤排序的情況,我們可以盡可能讓模型是凸面體,并且考慮將復(fù)雜的模型拆分成可以獨(dú)立排序的多個子模型等

8.2 Unity Shader 中的渲染順序

Unity 為了解決渲染順序的問題設(shè)計了渲染隊列(render queue),我們可以使用 SubShader 的 Queue 標(biāo)簽來決定我們的模型將歸于哪個渲染隊列。Unity 在內(nèi)部使用一系列整數(shù)索引來表示每個渲染隊列,且索引號越小表示越早被渲染,并且Unity提前定義了5個渲染隊列:
《Unity 入門精要》第8章 透明效果
要設(shè)置 Shader 的渲染隊列,可以通過在 SubShader 中指定相應(yīng)標(biāo)簽:

SubShader {
	// 指定渲染隊列為 AlphaTest
    Tags { "Queue"="AlphaTest" }
    Pass {
        ...
    }
}

也可以直接在編輯器中直接指定 Shader 的渲染隊列:
《Unity 入門精要》第8章 透明效果

8.3 透明度測試

透明度測試原理:只要一個片元的透明度不滿足條件(通常是小于某個閾值),那么它對應(yīng)的片元就會被舍棄。被舍棄的片元將不會再進(jìn)行任何處理,也不會對顏色緩沖產(chǎn)生任何影響;否則,就會按照普通的不透明物體的處理方式來處理它。
通常我們在片元著色器中使用 clip 函數(shù)來進(jìn)行透明度測試,它是 Cg 中的一個函數(shù)。
下面我們實現(xiàn)一個包含透明度測試的 Shader :

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'

Shader "Chaptor 8/SHA_AlphaTest"
{
    Properties
    {
        _Color ("Color Tint", Color) = (1, 1, 1, 1)
        _MainTex ("Main Tex", 2D) = "white" {}
        // 用于控制透明度測試的邊界值
        _CutOff ("Alpha CutOff", Range(0, 1.0)) = 0.5
    }
    SubShader
    {
        // 通過標(biāo)簽 Queue 指定渲染隊列為 AlphaTest
        // RenderType 標(biāo)簽可以讓Unity把這個Shader歸入到提前定義的組中,以指明該 Shader 是一個使用了透明度測試的Shader。
        // RenderType標(biāo)簽通常被用于著色器替換功能
        // IgnoreProjector 設(shè)置為 true 意味著這個 Shader 不會受投影器影響
        // 通常,一個透明度測試 Shader 都需要設(shè)置這三個標(biāo)簽
        Tags {"Queue"="AlphaTest" "IgnoreProjector"="true" "RenderType"="TransparentCutout"}
        Pass
        {
            Tags {"LightMode" = "ForwardBase"}
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"
            #include "Lighting.cginc"

            fixed4 _Color;
            sampler2D _MainTex;
            float4 _MainTex_ST;
            fixed _CutOff;

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

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float3 worldNormal : TEXCOORD0;
                float3 worldPos : TEXCOORD1;
                float2 uv : TEXCOORD2;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
                o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                float3 worldNormal = normalize(i.worldNormal);
                float3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));

                fixed4 texColor = tex2D(_MainTex, i.uv);
                // 使用 clip 函數(shù)進(jìn)行透明度測試,等價于代碼
                // if((texColor.a - _CutOff) < 0.0){
                //     discard
                // }
                clip(texColor.a - _CutOff);

                fixed3 albedo = texColor * _Color.rgb;
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
                fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(worldNormal, worldLightDir));
                return fixed4(ambient + diffuse, 1.0);
            }
            ENDCG
        }
    }
    Fallback "Specular"
}

效果如下,左側(cè)為正常方塊,右側(cè)為開啟了透明度測試的方塊:
《Unity 入門精要》第8章 透明效果

可以在編輯器中通過參數(shù) CutOff 參數(shù)來設(shè)置透明度效果。
可以看出,透明度測試得到的透明效果很“極端”——要么完全透明,要么完全不透明,它的效果往往像在一個不透明物體上挖了一個空洞。而且,得到的透明效果在邊緣處往往參差不齊,有鋸齒,這是因為在邊界處紋理的透明度的變化精度問題。為了得到更加柔滑的透明效果,就可以使用透明度混合。

8.4 透明度混合

透明度混合:使用當(dāng)前片元的透明度作為混合因子,與已經(jīng)存儲在顏色緩沖中的顏色值進(jìn)行混合,得到新的顏色。但是,透明度混合需要關(guān)閉深度寫入,這使得我們要非常小心物體的渲染順序。
為了進(jìn)行混合,我們需要使用 Unity 提供的混合命令Blend。Blend 是 Unity 提供的設(shè)置混合模式的命令。想要實現(xiàn)半透明的效果就需要把當(dāng)前自身的顏色和已經(jīng)存在于顏色緩沖中的顏色值進(jìn)行混合,混合時使用的函數(shù)就是由該指令決定的。
《Unity 入門精要》第8章 透明效果
只有開啟了混合,設(shè)置片元的透明通道才有意義。
下面是一個透明度混合的例子,其中采用Blend SrcFactor DstFactor語義,并設(shè)置 SrcFactorSrcAlpha,DstFactorOneMinusSrcAlpha,這樣講采用如下的混合算法:
《Unity 入門精要》第8章 透明效果
更多混合語義的說明可查看官方文檔。下面是 Shader 代碼:

Shader "Chaptor 8/SHA_AlphaBlend"
{
    Properties
    {
        _Color ("Color Tint", Color) = (1, 1, 1, 1)
        _MainTex ("Main Tex", 2D) = "white" {}
        // 用于控制整體的透明度
        _AlphaScale ("Alpha Scale", Range(0, 1.0)) = 1
    }
    SubShader
    {
        // 通過標(biāo)簽 Queue 指定渲染隊列為 Transparent
        Tags {"Queue"="Transparent" "IgnoreProjector"="true" "RenderType"="Transparent"}
        Pass
        {
            Tags {"LightMode" = "ForwardBase"}
            // 深度寫入設(shè)置為關(guān)閉狀態(tài)
            ZWrite off
            // 開啟混合,并設(shè)置相應(yīng)混合因子
            Blend SrcAlpha OneMinusSrcAlpha

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"
            #include "Lighting.cginc"

            fixed4 _Color;
            sampler2D _MainTex;
            float4 _MainTex_ST;
            fixed _AlphaScale;

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

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float3 worldNormal : TEXCOORD0;
                float3 worldPos : TEXCOORD1;
                float2 uv : TEXCOORD2;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
                o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                float3 worldNormal = normalize(i.worldNormal);
                float3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));

                fixed4 texColor = tex2D(_MainTex, i.uv);
                fixed3 albedo = texColor * _Color.rgb;
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
                fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(worldNormal, worldLightDir));
                return fixed4(ambient + diffuse, texColor.a * _AlphaScale);
            }
            ENDCG
        }
    }
    Fallback "Specular"
}

效果如下,左側(cè)為透明度測試效果,右側(cè)為透明度混合效果:
《Unity 入門精要》第8章 透明效果

8.5 開啟深度寫入的半透明效果

由于在進(jìn)行透明度混合時關(guān)閉了深度寫入,所以當(dāng)模型中有互相交叉的結(jié)構(gòu)時,往往會得到錯誤的半透明效果:
《Unity 入門精要》第8章 透明效果
為了解決這個問題,我們可以使用兩個 Pass 來渲染,第一個 Pass 開啟深度寫入,但不輸出顏色,它的目的僅僅是把模型的深度值寫入深度緩沖中;第二個 Pass 進(jìn)行正常的透明度混合,由于上一個 Pass 已經(jīng)得到逐像素的正確的深度信息,該 Pass 就可以按照像素級別的深度排序結(jié)果進(jìn)行透明渲染。但這種的方法的缺點(diǎn)在于多使用了一個 Pass,會對性能造成一定影響。
實現(xiàn)的 Shader 如下:

Shader "Chaptor 8/SHA_AlphaBlendZWrite"
{
    Properties
    {
        _Color ("Color Tint", Color) = (1, 1, 1, 1)
        _MainTex ("Main Tex", 2D) = "white" {}
        // 用于控制整體的透明度
        _AlphaScale ("Alpha Scale", Range(0, 1.0)) = 1
    }
    SubShader
    {
        // 通過標(biāo)簽 Queue 指定渲染隊列為 Transparent
        Tags {"Queue"="Transparent" "IgnoreProjector"="true" "RenderType"="Transparent"}

        Pass {
            // 第一個 Pass 開啟深度寫入
            ZWrite on
            // ColorMask 為渲染命令,用于設(shè)置顏色通道的寫掩碼
            // ColorMask 0 表示該 Pass 不寫入任何顏色通道,即不會輸出任何顏色
            ColorMask 0
        }

        Pass
        {
            Tags {"LightMode" = "ForwardBase"}
            // 深度寫入設(shè)置為關(guān)閉狀態(tài)
            ZWrite off
            // 開啟混合,并設(shè)置相應(yīng)混合因子
            Blend SrcAlpha OneMinusSrcAlpha

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"
            #include "Lighting.cginc"

            fixed4 _Color;
            sampler2D _MainTex;
            float4 _MainTex_ST;
            fixed _AlphaScale;

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

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float3 worldNormal : TEXCOORD0;
                float3 worldPos : TEXCOORD1;
                float2 uv : TEXCOORD2;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
                o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                float3 worldNormal = normalize(i.worldNormal);
                float3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));

                fixed4 texColor = tex2D(_MainTex, i.uv);
                fixed3 albedo = texColor * _Color.rgb;
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
                fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(worldNormal, worldLightDir));
                return fixed4(ambient + diffuse, texColor.a * _AlphaScale);
            }
            ENDCG
        }
    }
    Fallback "Specular"
}

效果如下:
《Unity 入門精要》第8章 透明效果

ShaderLab 的混合命令

混合就是通過混合等式(blend equation)源顏色(source color)目標(biāo)顏色(destination color)進(jìn)行相應(yīng)計算產(chǎn)生輸出顏色(output color)。

  • 源顏色,我們用 S 表示,指的是由片元著色器產(chǎn)生的顏色值
  • 目標(biāo)顏色,我們用 D 表示,指的是從顏色緩沖中讀取的顏色值
  • 輸出顏色,我們用 O 表示,指的是混合完成我們得到的結(jié)果顏色值
  • S、D、O 都是包含了 RGBA 四個通道的顏色值。
  • 混合等式就是用于操作計算 S 和 D 的函數(shù)。當(dāng)進(jìn)行混合時,通常我們需要使用兩個混合等式,一個用于混合 RGB 通道,一個用于混合 A 通道。當(dāng)設(shè)置混合狀態(tài)時,我們實際設(shè)置的就是混合等式中的操作和因子。

混合等式和混合因子

Unity ShaderLab 使用渲染命令 Blend 來設(shè)置混合等式的混合因子:
《Unity 入門精要》第8章 透明效果
ShaderLab 支持的常用混合因子如下:
《Unity 入門精要》第8章 透明效果
更詳細(xì)信息見Unity 官方手冊

混合操作

我們可以使用渲染命令BelndOp 來設(shè)置混合操作類型,默認(rèn)的操作類型為加法,支持的常見混合操作如下:
《Unity 入門精要》第8章 透明效果
更詳細(xì)信息見Unity 官方手冊

常見的混合類型

下面列出了常見的幾種混合類型:

// 正常(Normal),即透明度混合
Blend SrcAlpha OneMinusSrcAlpha

// 柔和相加(Soft Additive)
Blend OneMinusDstColor One

// 正片疊底(Multiply),即相乘
Blend DstColor Zero

// 兩倍相乘(2x Multiply)
Blend DstColor SrcColor

// 變暗(Darken)
BlendOp Min
Blend One One

// 變亮(Lighten)
BlendOp Max
Blend One One

// 濾色(Screen)
Blend OneMinusDstColor One
// 等同于
Blend One OneMinusSrcColor

// 線性減淡(Linear Dodge)
Blend One One

對應(yīng)的混合效果如下圖:
《Unity 入門精要》第8章 透明效果

雙面渲染的透明效果

在現(xiàn)實生活中,如果一個物體是透明的,意味著我們不僅可以透過它看到其他物體的樣子,也可以看到它內(nèi)部的結(jié)構(gòu)。但在前面實現(xiàn)的透明效果中,無論是透明度測試還是透明度混合,我們都無法觀察到正方體內(nèi)部及其背面的形狀,導(dǎo)致物體看起來就好像只有半個一樣。這是因為,**默認(rèn)情況下渲染引擎剔除了物體背面(相對于攝像機(jī)的方向)的渲染圖元,而只渲染了物體的正面。**如果我們想要得到雙面渲染的效果,可以使用 Cull 指令來控制需要剔除哪個面的渲染圖元。

Cull Back | Front | Off
  • Back:剔除背面,背對著攝像機(jī)的圖元不會被渲染,Shader 默認(rèn)使用此種剔除模式
  • Front:剔除正面,炒香攝像機(jī)的圖元不會被渲染
  • Off:關(guān)閉剔除,所有圖元都會被渲染,但圖元數(shù)會成倍增加,謹(jǐn)慎使用

透明度測試的雙面渲染

在 Pass 中關(guān)閉剔除即可:

Shader "Chaptor 8/SHA_AlphaTest"
{
    Properties
    {
        _Color ("Color Tint", Color) = (1, 1, 1, 1)
        _MainTex ("Main Tex", 2D) = "white" {}
        _CutOff ("Alpha CutOff", Range(0, 1.0)) = 0.5
    }
    SubShader
    {
        Tags {"Queue"="AlphaTest" "IgnoreProjector"="true" "RenderType"="TransparentCutout"}
        Pass
        {
            Tags {"LightMode" = "ForwardBase"}
            // 關(guān)閉剔除
            Cull off

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"
            #include "Lighting.cginc"

            fixed4 _Color;
            sampler2D _MainTex;
            float4 _MainTex_ST;
            fixed _CutOff;

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

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float3 worldNormal : TEXCOORD0;
                float3 worldPos : TEXCOORD1;
                float2 uv : TEXCOORD2;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
                o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                float3 worldNormal = normalize(i.worldNormal);
                float3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));

                fixed4 texColor = tex2D(_MainTex, i.uv);
                clip(texColor.a - _CutOff);

                fixed3 albedo = texColor * _Color.rgb;
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
                fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(worldNormal, worldLightDir));
                return fixed4(ambient + diffuse, 1.0);
            }
            ENDCG
        }
    }
    Fallback "Specular"
}

效果如下:
《Unity 入門精要》第8章 透明效果

透明度混合的雙面渲染

和透明度測試相比,想要讓透明度混合實現(xiàn)雙面渲染會更復(fù)雜一些,這是因為透明度混合需要關(guān)閉深度寫入,所以我們需要保證渲染順序的正確性。我們想要保證圖元是從后往前渲染的。為此,我們選擇把雙面渲染的工作分成兩個Pass,第一個Pass只渲染背面,第二個Pass只渲染正面,由于Unity會順序執(zhí)行SubShader中的各個Pass,因此我們可以保證背面總是在正面被渲染之前渲染,從而可以保證正確半透明效果:

Shader "Chaptor 8/SHA_AlphaBlend"
{
    Properties
    {
        _Color ("Color Tint", Color) = (1, 1, 1, 1)
        _MainTex ("Main Tex", 2D) = "white" {}
        _AlphaScale ("Alpha Scale", Range(0, 1.0)) = 1
    }
    SubShader
    {
        Tags {"Queue"="Transparent" "IgnoreProjector"="true" "RenderType"="Transparent"}

        Pass {
 Tags {"LightMode" = "ForwardBase"}
            // 先剔除正面渲染背面
            Cull Front
            ZWrite off
            Blend SrcAlpha OneMinusSrcAlpha

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"
            #include "Lighting.cginc"

            fixed4 _Color;
            sampler2D _MainTex;
            float4 _MainTex_ST;
            fixed _AlphaScale;

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

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float3 worldNormal : TEXCOORD0;
                float3 worldPos : TEXCOORD1;
                float2 uv : TEXCOORD2;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
                o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                float3 worldNormal = normalize(i.worldNormal);
                float3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));

                fixed4 texColor = tex2D(_MainTex, i.uv);
                fixed3 albedo = texColor * _Color.rgb;
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
                fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(worldNormal, worldLightDir));
                return fixed4(ambient + diffuse, texColor.a * _AlphaScale);
            }
            ENDCG
        }

        Pass
        {
            Tags {"LightMode" = "ForwardBase"}
            // 再剔除背面渲染正面
            Cull Back
            ZWrite off
            Blend SrcAlpha OneMinusSrcAlpha

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"
            #include "Lighting.cginc"

            fixed4 _Color;
            sampler2D _MainTex;
            float4 _MainTex_ST;
            fixed _AlphaScale;

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

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float3 worldNormal : TEXCOORD0;
                float3 worldPos : TEXCOORD1;
                float2 uv : TEXCOORD2;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
                o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                float3 worldNormal = normalize(i.worldNormal);
                float3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));

                fixed4 texColor = tex2D(_MainTex, i.uv);
                fixed3 albedo = texColor * _Color.rgb;
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
                fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(worldNormal, worldLightDir));
                return fixed4(ambient + diffuse, texColor.a * _AlphaScale);
            }
            ENDCG
        }
    }
    Fallback "Specular"
}

效果如下:
《Unity 入門精要》第8章 透明效果文章來源地址http://www.zghlxwxcb.cn/news/detail-496857.html

到了這里,關(guān)于《Unity 入門精要》第8章 透明效果的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點(diǎn)擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 《Unity Shader 入門精要》筆記07

    《Unity Shader 入門精要》筆記07

    Unity中通常使用兩種方法來實現(xiàn)透明效果:第一種是試用 透明度測試(Alpha Test) ,這種方法其實無法得到真正的半透明效果;另一種是 透明度混合(Alpha Blending) 。 由于深度緩沖的存在,可以讓不透明物體不考慮他們渲染順序也能得到正確的排序效果。但是實現(xiàn)透明效果需

    2024年02月07日
    瀏覽(25)
  • Unity Shader學(xué)習(xí)3:透明效果

    Unity Shader學(xué)習(xí)3:透明效果

    Unity中的透明效果由透明通道控制(RGBA中的A),其值為0是完全透明,為1時完全不透明。有兩種方法可以實現(xiàn)透明效果: 透明度測試(Alpha Test) 和 透明度混合(Alpha Blend) 。 透明度測試是指通過特定的條件(通常是Alpha通道的值是否超過某個閾值)來判斷片元是否透明,只

    2024年01月19日
    瀏覽(84)
  • Unity 設(shè)置貼圖黑色區(qū)域為透明效果

    Unity 設(shè)置貼圖黑色區(qū)域為透明效果

    TexstureType為默認(rèn)類型 勾選 Alpha from GrayScale 勾選 Alpha Is Transparent 材質(zhì)球使用默認(rèn)材質(zhì) Shader選為Standard 它的Rendering Mode選擇Transparent

    2024年02月15日
    瀏覽(25)
  • Unity入門精要04(0)-更復(fù)雜的光照

    Unity入門精要04(0)-更復(fù)雜的光照

    本書知識點(diǎn)是真的多( Unity中的渲染路徑有如下選項? 對某一Pass指定了渲染路徑后,Unity會在過程中自動填充系統(tǒng)的變量,便于使用。 ? ?前向渲染的偽代碼如下 一句話概括前向渲染就是:對于每個光源在其范圍能影響物體的都計算一次所有的Pass(除了Base Pass以外),計算

    2023年04月12日
    瀏覽(20)
  • [Unity Shader入門精要]初級篇 代碼拆解

    [Unity Shader入門精要]初級篇 代碼拆解

    簡介: 介紹了Unity Shader入門精要中初級篇包含的所有代碼, 通過詳細(xì)拆解代碼 ,一步一步揭曉Shader的原理。 5.2.1 頂點(diǎn)/片元著色器的基本結(jié)構(gòu) 說人話: ?第一行是著色器的名字,用大括號{} 包裹后續(xù)所有的Shader代碼, Shader。 ?緊接著是Shader的屬性,用大括號{} 包裹

    2024年02月03日
    瀏覽(24)
  • 學(xué)習(xí)100個Unity Shader (14) ---透明效果

    學(xué)習(xí)100個Unity Shader (14) ---透明效果

    由”Queue“ 標(biāo)簽決定,索引號越小越早被渲染: 名稱 隊列索引號 Background 1000 Geometry 2000 AlphaTest 2450 Transparent 3000 Overlay 4000 某一片元的透明度小于某個閾值,即被舍棄,反之,按非透明物體處理,進(jìn)行正常的深度測試和深度寫入【不需要關(guān)閉深度寫入】。 UnityObjectToClipPos 將頂

    2024年04月29日
    瀏覽(22)
  • Unity Shader入門精要 第六章——Unity中的基礎(chǔ)光照

    Unity Shader入門精要 第六章——Unity中的基礎(chǔ)光照

    目錄 一、標(biāo)準(zhǔn)光照模型(Phong光照模型) 1、環(huán)境光 ?2、自發(fā)光 3、漫反射 4、高光反射 (1)Phong模型 (2)Blinn模型 5、光照模型實現(xiàn)方法——逐頂點(diǎn)和逐像素 二、Unity Shader 漫反射光照模型的實現(xiàn) 1、實踐:逐頂點(diǎn) 2、實踐:逐像素 3、半蘭伯特模型 4、漫反射光照模型效果展

    2024年02月04日
    瀏覽(25)
  • Unity Shader學(xué)習(xí)記錄(11) ——透明效果的實現(xiàn)方式

    Unity Shader學(xué)習(xí)記錄(11) ——透明效果的實現(xiàn)方式

    1 透明效果的兩種方法 透明是游戲中經(jīng)常要使用的一種效果。在實時渲染中要實現(xiàn)透明效果,通常會在渲染模型時控制它的透明通道(Alpha Channel)。當(dāng)開啟透明混合后,當(dāng)一個物體被渲染到屏幕上時,每個片元除了顏色值和深度值之外,它還有另一個屬性一一透明度。 當(dāng)透明度

    2024年02月07日
    瀏覽(24)
  • Unity中的渲染優(yōu)化技術(shù) -- Shader入門精要學(xué)習(xí)(15)

    Unity中的渲染優(yōu)化技術(shù) -- Shader入門精要學(xué)習(xí)(15)

    本章中,我們將闡述一些 Unity 中常見的優(yōu)化技術(shù)。這些優(yōu)化技術(shù)都是和渲染相關(guān)的,例如,使用批處理、LOD 技術(shù)等。 游戲優(yōu)化不僅是程序員的工作,更需要美工人員在游戲的美術(shù)上進(jìn)行一定的權(quán)衡。例如,避免使用全屏的屏幕特效,避免使用計算復(fù)雜的 Shader,減少透明混合

    2024年01月18日
    瀏覽(22)
  • 【UnityShader入門精要學(xué)習(xí)筆記】第六章(1)Unity中的基礎(chǔ)光照

    【UnityShader入門精要學(xué)習(xí)筆記】第六章(1)Unity中的基礎(chǔ)光照

    本系列為作者學(xué)習(xí)UnityShader入門精要而作的筆記,內(nèi)容將包括: 書本中句子照抄 + 個人批注 項目源碼 一堆新手會犯的錯誤 潛在的太監(jiān)斷更,有始無終 總之適用于同樣開始學(xué)習(xí)Shader的同學(xué)們進(jìn)行有取舍的參考。 一個物體為什么看起來是紅色的?從物理上解釋是因為這個物體

    2024年03月22日
    瀏覽(34)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包