※170607 補足記事をアップしました うにばな スクリーンスペース系のシェーダに関するTips

 

 

今回は”エフェクト用のシェーダに関するアイデア”の補足でGrabTextureを使用する場合のパーティクルのカラー合成をしてみます。

GrabTextureは背景からテクスチャにキャプチャした画像をカラー合成の対象にできる命令で スクリーンサイズのスナップショットをテクスチャに展開します。

GrabTexture命令で 取り込んだテクスチャにシェーダでモデルのカラーを合成をしてやれば ”エフェクト用のシェーダに関するアイデア”で使用したシェーダと同じような効果がねらえます。カラーを合成する式は

これも以前掲載した フォトショップの合成式を使用することが出来るため フォトショップ上の見た目と同等の表現が期待出来て デザイナーにとっては非常にありがたい機能です。 ただしGrabTexture命令は処理負荷が高く現在のモバイルやスマホで動作させるには重ためなので気をつけてください。

 

【fig1】

grabtest

 

 

今回作成したサンプルシェーダコードは以下の通りです

■ 『BlendTest(GrabTex) . shader" 』

Shader "Custom/Particles/BlendTest(GrabTex)" {

    Properties {

        _TintColor ( "Tint Color", Color ) = ( 0.5, 0.5, 0.5, 0.5 )
        _MainTex ( "Particle Texture", 2D ) = "white" {}
  
    }

    Category {

        Tags { "Queue"="Transparent" "RenderType"="Opaque" }
       
          Blend One OneMinusSrcAlpha
         Alphatest Greater 0.1
         ZWrite On
        
        SubShader {

            GrabPass { 
                                                 
                Name "BASE"
                Tags { "LightMode" = "Always" }
  
            }


            Pass {
                Name "BASE"
                Tags { "LightMode" = "Always" }

                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                #pragma multi_compile_particles
                #include "UnityCG.cginc"
                #pragma target 3.0

                struct appdata_t {
                    float4 vertex : POSITION;
                    float2 texcoord: TEXCOORD0;
                };

                struct v2f {
                    float4 vertex : POSITION;
                    float4 uvgrab : TEXCOORD0;     
                    float2 uvmain : TEXCOORD2;
                };
   
                sampler2D _GrabTexture;
                float4 _GrabTexture_TexelSize;

                sampler2D _MainTex;
                float4 _MainTex_ST;
               
                fixed4 _TintColor;
              

                v2f vert ( appdata_t v ) {

                    v2f o;

                    o.vertex = mul( UNITY_MATRIX_MVP, v.vertex );
                    #if UNITY_UV_STARTS_AT_TOP
                    float scale = -1.0;
                    #else
                    float scale = 1.0;
                    #endif
                    o.uvgrab.xy = ( float2( o.vertex.x, ( o.vertex.y * scale ) ) + o.vertex.w ) * 0.5;
                    o.uvgrab.zw = o.vertex.zw;           
                    o.uvmain = TRANSFORM_TEX( v.texcoord, _MainTex );

                    return o;

                }


                half4 frag( v2f i ) : COLOR {
            
                   half4 col = tex2Dproj( _GrabTexture, UNITY_PROJ_COORD( i.uvgrab ) );
                   
                   col.a = 0;
                 
                   half4 base = tex2D( _MainTex, i.uvmain);      
                  // このようなブレンド式を使用してもよいです
                 //  return float4( (base.rgb < 0.5 ? (2.0 * base.rgb * col.rgb) : (1.0 - 2.0 * (1.0 - base.rgb) * (1.0 - col).rgb)).rgb , base.a);

                    return float4(base.rgb + _TintColor * pow(base.rgb,2.0 )* col.rgb , base.a);
            

                }
                ENDCG
            }
           
          
        }

    }

}

 

■ GrabTextureの取得は GrabPassをk術するだけです samplerの指定とセットなので記述漏れしないようにしてください

GrabPass
                                                 
                Name "BASE"
                Tags { "LightMode" = "Always" }
  
            }

・・・・・・・・・・・・・・・・・・・・・・・

sampler2D _GrabTexture;

・・・・・・・・・・・・・・・・・・・・・・・

o.uvgrab.xy = ( float2( o.vertex.x, ( o.vertex.y * scale ) ) + o.vertex.w ) * 0.5;
o.uvgrab.zw = o.vertex.zw;
      

 

half4 col = tex2Dproj( _GrabTexture, UNITY_PROJ_COORD( i.uvgrab ) );

Unityのマクロ関数 UNITY_PROJ_COORD にワールド頂点座標を与えることによってカメラのプロジェクション方向から見たスクリーン座標のUV値に変換されます。

Tags { "Queue"="Transparent" "RenderType"="Opaque" } タグはレンダーキュー(Queue)に透明(Transparent)が指定してあればアルファを考慮したソートが行われるため RenderTypeは無視しても構いません。

■Blend One OneMinusSrcAlpha は <背景 1 :前景 1-alpha値> で合成を指定します。アルファ抜きの場合はこれを使用。

ZWriteをOnにするのを忘れないように depthバッファの書き込みが行われないと正確なソートが行われません。

Alphatest Greater 0.1 はしきい値(例の場合0.1)を境界にして透明部分の抜け具合を決定します。


Blend One OneMinusSrcAlpha
        Alphatest Greater 0.1
         ZWrite On


 

■ライブラリの種類によっては取り込んだテクスチャのUV座標のV方向(スクリーン座標のY軸方向)が上下逆になることがあるので

UNITY_UV_STARTS_AT_TOP の変数を監視してテクスチャUVのV方向に−1を掛けてフリップする必要があります


#if UNITY_UV_STARTS_AT_TOP
                    float scale = -1.0;
                    #else
                    float scale = 1.0;
                    #endif

 

■カラー合成式に関してはどのような書き方してももちろん構いません 見た目でより良い結果になるようにしてください。

 

フォトショップのブレンド式 を使用する場合   

return float4( ( base.rgb < 0.5 ? (2.0 * base.rgb * col.rgb) : (1.0 - 2.0 * (1.0 - base.rgb) * (1.0 - col.rgb).rgb)).rgb , base.a );
              

● 加算と乗算を組み合わせる場合

return float4( base.rgb + _TintColor * pow(base.rgb,2.0 )* col.rgb , base.a );

テクスチャはアルファ抜きしたものを使用しますが、 カラーの明度からアルファマスクを計算して取得することも出来ます

【Example】

float alpha =Luminance(color.rgb) ;

たとえばUnityのマクロ関数Luminanceを使用します RGB値カラーを輝度値 に変換する関数で "UnityCG.cginc"ファイルに記述されています

Luminance( ) の代入はfloat3型ですので float4型のカラーを渡すときは 「color.rgb」というようにSwizzleで記述します。

inline fixed Luminance( fixed3 c )
{
    return dot( c, fixed3(0.22, 0.707, 0.071) );
}

 


【追記】

リファレンスには下のように GrabPassにオプションパラメータとしてテクスチャのスケールが指定できると書いてありますが コンパイルが通ったことがありません Unity公式フォーラムでもバグ扱いされていてだれも使い方をわかってないようなんですが、どうやって使用するんでしょう? ご存じの方がいればコメント頂きたいのです。

GrabPass {

    TextureScale 0.5 

   TextureSize 256

    BorderScale 0.3

// following are regular pass commands

    Tags { "LightMode" = "VertexLit" }

    Name "BASE"

}

 

今回は以上です 次回はなるべくはために更新するつもりですが 少しレベルを上げるかもしれませんので頑張って読解してみてください。

質問がある方はコメント欄にどうぞ

 

それではまた