未来を創る、テックコミュニティー

代表技術通信~Shader、シェーダー、勉強する②

草場代表
2020/11/19

こんばんわ。代表の草場です。

Shaderを本格的に勉強する必要あるので、7日間でマスターするUnityシェーダ入門にて、学び中です。

【Unityシェーダ入門】透明なシェーダを作るに関してです。

シェーダを使って3Dオブジェクトの見た目を半透明にします。ガラスのような表現が可能となります。
3Dモデルを半透明で描画するためのシェーダプログラムは以下です。前回同様、プロジェクトビューで新規のシェーダファイルを作ります。

Shader "Custom/sample" {
                                    SubShader {
                                           Tags { "Queue" = "Transparent" }
                                           LOD 200
                                           CGPROGRAM
                                           #pragma surface surf Standard alpha:fade
                                           #pragma target 3.0
                                           struct Input {
                                                      float2 uv_MainTex;
                                                      };
                                           void surf (Input IN, inout SurfaceOutputStandard o) {
                                                           o.Albedo = fixed4(0.6f, 0.7f, 0.4f, 1);
                                                           o.Alpha = 0.6;
                                                            }
                                           ENDCG
                                     }
                         FallBack "Diffuse"
  }

Tagブロックの中のQueueには描画の優先度を指定します。通常は、カメラからみて奥にあるものから順番に描画されるため、Queueの指定は必要ないですが、半透明のものを描画するには、不透明オブジェクトの後に描画する必要があるため、指定が必要です。
Queueでは、「Background」→「Geometry」→「AlphaTest」→「Transparent」→「Overlay」の順で描画されます。
今の場合、QueueにTransparentを指定することで、BackgroundやGeometryなどの不透明オブジェクトを全て描画してから半透明オブエジェクトが描画されるようになります。

#pragma surface surf Standard に続けて「alpha:fade」が指定されています。これを指定することで、オブジェクトを半透明で描くことが出来るようになります。これ以外に指定できるパラメタは、


alpha:auto
alpha:fadeとalpha:premulのあわせ技
alpha:blend アルファブレンディングを可能にします
alpha:fade 従来の透過性のフェードイン/アウトを可能にします
alpha:premul プレマルチプライドアルファ透明度を可能にします

透明度を指定する場合、SurfaceOutputStandardのAlphaに値を設定します。結果が以下です。

写真は後程

 

次は【Unityシェーダ入門】氷のような半透明シェーダを作るについて。
オブジェクトを半透明にするには次の3点をを設定が必要でした。
Queue
alpha:fade
SurfaceOutputStandard

氷シェーダのプログラムが以下です。

Shader "Custom/sample" {
                 SubShader {
                         Tags { "Queue"="Transparent" }
                         LOD 200
                         CGPROGRAM
                        #pragma surface surf Standard alpha:fade
                        #pragma target 3.0
                        struct Input {
                              float3 worldNormal;
                              float3 viewDir;
                                  };
                        void surf (Input IN, inout SurfaceOutputStandard o) {
                                 o.Albedo = fixed4(1, 1, 1, 1);
                                 float alpha = 1 - (abs(dot(IN.viewDir, IN.worldNormal)));
                                 o.Alpha =  alpha*1.5f;
                                }
                     ENDCG
               }
            FallBack "Diffuse"
}

以下の二点が注目です。

サーフェイスシェーダに、法線ベクトルと視線ベクトルを入力している
透明度の求めるために、ベクトル計算をしている

サーフェイスシェーダにworldNormal(オブジェクトの法線ベクトル)とviewDir(視線ベクトル)が入力されています。
法線ベクトルはオブジェクトの表面に対して垂直方向のベクトル、視線ベクトルはカメラが向いている方向のベクトルです。
氷を考えると、輪郭部分の透明度が低く、中央部分の透明度が高いです。worldNormalとviewDIrを使って輪郭部分では1、中央部分では0になるような計算式を考えます。輪郭部分では視線ベクトルと法線ベクトルが垂直に近く、中央部分ではほぼ平行です。

この2つのベクトルが交わる角度を透明度に変換します

以下の数式であらわされます。

worldNormal * viewDir = |worldNormal| * |viewDir| * cosθ = cosθ

今回は垂直に交わる場合には透明度を1、並行の場合は透明度を0にするために絶対値をとって1から引いています。

alpha = 1 – abs( cosθ );

最後に1.5を掛けて、見た目の調整をします。

 

この記事を書いた人
草場代表
エディター