UnityShader入門マスターノート(7)——透明効果


透明効果


一、透明効果を実現する二つの方法

  • 透明度テスト(真の半透明効果は得られない):「覇道極端」のメカニズムを採用し、1枚の円の透明度が条件を満たさない限り、捨てられる.すなわち、深さテスト、深さ書き込みなどが行われている(したがって、透明度テストでは深さ書き込みを閉じる必要はない).そのため、透明度テストの効果も極端で、見えるか見えないかです.
  • 透明度ブレンド(真の半透明効果が得られる):現在のシートの透明度をブレンド係数として使用し、カラーバッファに格納されているカラー値とブレンドして、新しいカラーを得る.深度ライトをオフにする必要があります.これにより、オブジェクトのレンダリング順序に非常に注意する必要があります.なお、透明度ブレンドは深さ書き込みのみをオフにしますが、深さテストはオフにしていません.これは、透明度ブレンドを使用して1つのスライスをレンダリングする場合でも、その深度値と現在の深度バッファ内の深度値が比較され、その深度値がカメラから遠く離れている場合、ブレンド操作は行われないことを意味します.このことは、不透明な物体が透明な物体の前に現れ、私たちが先に不透明な物体をレンダリングすると、透明な物体を正常に遮断することができることを決定します.すなわち、透明度ブレンドの場合、深度バッファは読み取り専用です.

  • 二、エンジンのよく使うレンダリング方法ステップ(一般的には物体を並べ替えてからレンダリングする)

  • 不透明な物体をすべてレンダーし、深度テストと深度書き込みをオンにします.
  • 半透明物体をカメラからの遠近で並べ替え、後から順にこれらの半透明物体をレンダリングし、深さテストをオンにしますが、深さ書き込みをオフにします.

  • なお、Unityは、上記の方法でレンダリングを行っても問題(たとえば、ループが重なる場合)が発生するため、レンダリング順序の問題を解決するためにキューをレンダリングする方法を提供している。


    三、UnityShaderのレンダリング順序


    1、レンダリングキュー


    SubShaderのQueueラベルを使用して、モデルがどのレンダリングキューに属するかを決定します.Unity内部では、各レンダリングキューを表す一連の整数インデックスが使用され、インデックス番号が小さいほどレンダリングが早くなります.
    名前
    キューインデックス番号
    説明
    Background
    1000
    このレンダリングキューは、他のキューよりも前にレンダリングされます.通常、バックグラウンドに描画する必要があるオブジェクトをレンダリングするために使用されます.
    Geometry
    2000
    デフォルトのレンダリングキューでは、ほとんどのオブジェクトがこのキューを使用します.不透明な物体はこのキューを使用します
    AlphaTest
    2450
    透明度テストが必要な物体はこのキューを使用します.Unity 5では、すべての不透明なオブジェクトをレンダリングした後にレンダリングするとより効率的になるため、Geometryキューから個別に分離されます.
    Transparent
    3000
    このキュー内のオブジェクトは、すべてのGeometryオブジェクトとAlphaTestオブジェクトがレンダリングされた後、後から順にレンダリングされます.透明度ブレンド(深さ書き込みを閉じたshaderなど)を使用したオブジェクトは、キューを使用する必要があります.
    Overlay
    4000
    このキューは、いくつかのオーバーラップ効果を実現するために使用されます.最後にレンダリングする必要があるオブジェクトは、キューを使用する必要があります.

    2、実現コード

  • 透明度テストで透明効果を実現
  • SubShader{
        Tags{ "Queue"="AlphaTest"}
        Pass{
            ···
        }
    }
    
  • 透明度混合による透明効果
  • SubShader{
        Tags{ "Queue"="Transparent"}
        Pass{
            ···
        }
    }
    
  • ZWrite Offはクローズ深さ書き込みで、一般的にPassに書かれていますが、もちろんSubShaderにも書くことができます(これはSubshaderの下のすべてのPassがクローズ深さ書き込みをすることを意味します).

  • 四、透明度テスト


    1、説明


    透明度テストは、シェーダでclip関数を使用して行います.

    2、コード

    // Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
    
    Shader "Unlit/AlphaTest"
    {
        Properties{
            _Color("Main Tint",Color) = (1,1,1,1)
            _MainTex("Main Tex",2D) = "white"{}
            _Cutoff("Alpha Cutoff",Range(0,1)) = 0.5
        }
        SubShader{
            Tags{ "Queue"="AlphaTest"  "IgnoreProject"="True" "RenderType"="TransparentCutout" }
            Pass{
                Tags{"LightModel"="ForwardBase"}
    
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                #include "Lighting.cginc"
                #include "UnityCG.cginc"
    
                fixed4 _Color;
                sampler2D _MainTex;
                float4 _MainTex_ST;
                fixed _Cutoff;
    
                struct a2v{
                    float4 vertex:POSITION;
                    float3 normal:NORMAL;
                    float4 texcoord:TEXCOORD0;
                };
                struct v2f{
                    float4 pos:SV_POSITION;
                    float3 worldNormal:TEXCOORD0;
                    float3 worldPos:TEXCOORD1;
                    float2 uv:TEXCOORD2;
                };
                v2f vert(a2v v){
                    v2f o;
                    o.pos = UnityObjectToClipPos(v.vertex);
                    o.worldNormal = UnityObjectToWorldNormal(v.normal);
                    o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;
                    o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);
                    return o;
                }
                fixed4 frag(v2f i):SV_TARGET{
                    fixed3 worldNormal = normalize(i.worldNormal);
                    fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
                    fixed4 texColor = tex2D(_MainTex,i.uv);
                    clip(texColor.a - _Cutoff);
                    // Equal to
                    // if(texColor.a - _Cutoff < 0.0){
                    //      discard;   // 
                    //}
                    fixed3 albedo = texColor.rgb * _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
            }
        }
    }
    
    

    五、透明度混合


    1、unity提供の混合コマンド:Blend


    意味
    説明
    Blend Off
    ブレンドを閉じる
    Blend SrcFactor DstFactor
    ブレンドをオンにし、ブレンド係数を設定します.ソースカラー(セルで生成された色)にSrcFactorを乗算し、ターゲットカラー(すでにカラーキャッシュに存在する色)にDstFactorを乗算し、両者を加算してカラーバッファに格納します.
    Blend SrcFactor DSTFactor,SrcFactorA DstFactorA
    上とほぼ同じですが、透明なチャネルをブレンドするには異なる因子を使用します.
    BlendOp BlendOperation
    ソースカラーとターゲットカラーを単純に加算してブレンドするのではなく、BlendOpentionを使用して他の操作を行います.

    注意:

  • 混合がオンになってからのみ、チップの透明な通路を設けることに意味があるので、Blendコマンドを使用すると自動的に混合モードがオンになる
  • ソース色の混合因子SrcFactorをSrcAlpha、ターゲット色の混合因子をOneMinusSrcAlphaとするのが一般的なので、混合後の新しい色は、DstColornew=SrcAlhap*SrcColor+(1-SrcAlpha)*DstColorold
  • 2、コード(以下、深度書き込みをオフにしたため、エラーのソート)

    Shader "Unlit/AlphaBlend"
    {
       Properties{
             _Color("Main Tint",Color) = (1,1,1,1)
            _MainTex("Main Tex",2D) = "white"{}
            _AlphaScale("Alpha Scale",Range(0,1)) = 0.5
        }
        SubShader{
            Tags{ "Queue"="Transparent"  "IgnoreProject"="True" "RenderType"="Transparent" }
            Pass{
                Tags{"LightModel"="ForwardBase"}
                ZWrite Off
                Blend SrcAlpha OneMinusSrcAlpha
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                #include "Lighting.cginc"
                #include "UnityCG.cginc"
    
                fixed4 _Color;
                sampler2D _MainTex;
                float4 _MainTex_ST;
                fixed _AlphaScale;
    
                struct a2v{
                    float4 vertex:POSITION;
                    float3 normal:NORMAL;
                    float4 texcoord:TEXCOORD0;
                };
                struct v2f{
                    float4 pos:SV_POSITION;
                    float3 worldNormal:TEXCOORD0;
                    float3 worldPos:TEXCOORD1;
                    float2 uv:TEXCOORD2;
                };
                v2f vert(a2v v){
                    v2f o;
                    o.pos = UnityObjectToClipPos(v.vertex);
                    o.worldNormal = UnityObjectToWorldNormal(v.normal);
                    o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;
                    o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);
                    return o;
                }
                fixed4 frag(v2f i):SV_TARGET{
                    fixed3 worldNormal = normalize(i.worldNormal);
                    fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
                    fixed4 texColor = tex2D(_MainTex,i.uv);
                    fixed3 albedo = texColor.rgb * _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
            }
        }
    }
    

    六、深さ書き込みの半透明効果をオンにする


    深度書き込みをオフにすることによるエラーのソートには、次のような解決策があります.

    1、2つのPassでモデルをレンダリングする

  • 原理:2つのPassを使用してモデルをレンダリングする:最初のPassは深度書き込みをオンにするが、色を出力せず、そのモデルの深度値を深度バッファに吸い込むことを目的とする.2番目のpassは通常の透明度ブレンドを行います.前のpassはピクセル単位の正確な深さ情報を得たため、このPassはピクセルレベルの深さソート効果に従って透明レンダリングを行うことができます.
  • 短所:性能低下
  • コード(前の混合度のコードと同じで、Passが1つ増えただけ):
  • Shader ""
    {
        Properties{
            ···
        }
        SubShader{
            ···
            Pass{
                ZWrite On
                //ColorMask , 
                //ColorMask RGB | A | 0 |  R、G、B、A 
                // 
                ColorMask 0  
            }
            Pass{
                ···
            }
        }
        ···
    }
    
    

    七、ShaderLabの混合命令


    1、混合の実現方式

  • パッチシェーダで色(ソース色、Sで示す)が発生した場合、カラーキャッシュの色(ターゲット色、Dで示す)とブレンドして色(Oで示す)を出力することができます.
  • RGBチャネルだけでなく、RGBAの4つのチャネルの値を含む混合色であることに注意してください.

  • 2、ShaderLabで混合因子を設定するコマンド


    ブレンド状態を設定する場合は、ブレンド式の操作と係数の設定に相当します.
    コマンド#コマンド#
    説明
    Blend SrcFactor DstFactor
    ブレンドをオンにし、ブレンド係数を設定します.ソースカラー(セルで生成された色)にSrcFactorを乗算し、ターゲットカラー(すでにカラーキャッシュに存在する色)にDstFactorを乗算し、両者を加算してカラーバッファに格納します.
    Blend SrcFactor DstFactor,SrcFactorA DstFactorA
    上とほぼ同じように、透明なチャネルをブレンドするために不要な因子を使用するだけです
  • 混合式:RGBチャネルの混合、AチャネルOrgb=SrcFactor*Srgb+DstFactor*Drgb Oa=SrcFactor*Sa+DstFactorA*Da
  • 3、ShaderLab中の混合因子


    パラメータ
    説明
    One
    ファクタ1
    Zero
    ファクタ0
    SrcColor
    ファクタはソースカラーの値です.RGBを混合するための混合式の場合、SrcColorのRGB成分を混合因子として用いる.混合Aに用いる混合式の場合、混合因子としてSrcColorのA成分を用いる
    SrcAlpha
    係数がソースカラーの透明度値A(Aチャネル)
    DstColor
    ファクタはソースカラーの値です.RGBチャネルを混合するための混合式の場合、DstColorのRGB成分を混合因子として使用する.混合Aチャネルに使用する場合、混合因子としてDstColorのA成分が使用される.
    DstAlpha
    係数がターゲットカラーの透明度(Aチャネル)
    OneMinusSrcColor
    係数は(1-ソースカラー)です.RGBを混合するための混合式の場合、結果のRGB成分を混合因子として用いる.混合Aに用いる混合式の場合、結果としてA成分を混合因子として用いる
    OneMinusSrcAlpha
    係数(1-ソースカラーの透明度)
    OneMinusDstColor
    係数は(1-ターゲットカラー)です.RGBを混合するための混合式の場合、結果のRGB成分を混合因子として用いる.混合Aに用いる混合式の場合、結果としてA成分を混合因子として用いる
    OneMinusDstAlpha
    係数(1-ターゲットカラーの透明度)

    4、コマンド


    異なるパラメータを使用してAチャネルをブレンドしたい場合は、Blend SrcFactor DstFactorを使用します.SrcFactorA DstFactorAの例:(出力色の透明度値はソース色の透明度値です)
    Blend SrcAlpha OneMinusSrcAlpha,One Zero
    

    5、混合操作


    ブレンド操作コマンド
    操作
    説明
    Add
    ブレンドしたソースカラーと目的のカラーを加算します.既定のブレンド操作.使用する混合式は、Orbg=SrcFactor*Srgb+DstFactor*DrgbOa=SrcFactorA*Sa+DstFactorA*Da
    Sub
    混合後のソース色から混合後の目的色を減算し、使用する混合式は、Orbg=SrcFactor*Srgb-DstFactor*DrgbOa=SrcFactorA*Sa-DstFactorA*Da
    RevSub
    混合後の目的色から混合後のソース色を減算し、使用する混合式は、Orbg=DstFactor*Drgb-SrcFactor*SrgbOa=DstFactorA*Da-SrcFactorA*Sa
    Min
    ソースカラーと目的のカラーの小さい値を使用して、成分ごとに比較します.使用した混合式は,Orgba=(min(Sr,Dr),min(Sg,Dg),min(Sb,Db),min(Sa,Da)である.
    Max
    ソースカラーとターゲットカラーの大きな値を使用して、成分ごとに比較します.使用した混合式は,Orgba=(max(Sr,Dr),max(Sg,Dg),max(Sb,Db),max(Sa,Da)である.

    なお、MinまたはMaxブレンド操作を使用する場合、ブレンド係数は実際には機能せず、元のソース色と目的色との比較結果のみを判断します。


    6、一般的な混合操作

    Blend SrcAlpha OneMinusSrcAlpha  // (normal), 
    
    Blend OneMinusDstColor One  // (Soft Additive)
    
    Blend DstColor Zero // (Multiply) ,  
    
    // (Darken)
    BlendOp Min 
    Blend One One 
    
    // (Lighten)
    BlendOp Max
    Blend One One 
    
    Blend OneMinusDstColor One  // (Screen)
    Blend One OneMinusSrcColor  // (Screen)
    
    Blend One One // (Linear Dodge)
    

    7、両面レンダリング

    Cull Back | Front | Off  //