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

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

草場代表
2020/11/20

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

Shaderを本格的に勉強する必要あるので、7日間でマスターするUnityシェーダ入門にて、学び中です。【Unityシェーダ入門】リムライティングのシェーダを作るに関してです。
前回作った氷のシェーダを利用して、背後から光が当たったようなリムライティングと呼ばれるシェーダを作ります。
リムライティングは、3Dモデルの後ろからライトが当たっている演出のことです。

リムライティングシェーダのプログラムは以下です、

Shader "Custom/sample" {
               SubShader {
                          Tags { "RenderType"="Opaque" }
                          LOD 200
                          CGPROGRAM
                         #pragma surface surf Standard
                         #pragma target 3.0
                         struct Input {
                               float2 uv_MainTex;
                               float3 worldNormal;
                               float3 viewDir;
                            };
                        void surf (Input IN, inout SurfaceOutputStandard o) {
                                 fixed4 baseColor = fixed4(0.05, 0.1, 0, 1);
                                 fixed4 rimColor  = fixed4(0.5,0.7,0.5,1);
                                 o.Albedo = baseColor;
                                 float rim = 1 - saturate(dot(IN.viewDir, o.Normal));
                                 o.Emission = rimColor * pow(rim, 2.5);
                                 }
                    ENDCG
                  }
          FallBack "Diffuse"
}

オブジェクトの輪郭部分のエミッションを高くして、背後から光が当たっているような演出にします。輪郭部分では視線ベクトルと法線ベクトルが垂直に近い角度で交わるのに対して、中央部分ではほぼ平行に近い角度で交わるので、リムライティングでは視線ベクトルと法線ベクトルが垂直に近い場合だけ、エミッションの値を高くすれば良いことになります。
視線ベクトルと法線ベクトルの交わる角度を求めるため、worldNormalとviewDirの内積をとります。

worldNormal * viewDir = |worldNormal| * |viewDir| * cosθ = cosθ
rim = 1 – abs( cosθ );

rimの値は 0 < rim < 1なので、このrim係数をrimColorに乗算し、SurfaceOutputStandardのEmissionに代入します。

o.Emission = rimColor * rim;

これにより、周辺部分のエミッションは高いままで、中央部分に行くに従ってエミッションが低くなります。結果。

写真は後程

この状態では、中央部分に光が回り込んでおり、シャープな輪郭になりません。rim変数の減衰がcos関数に従うため、中央付近まで光が減衰しないからです。これを解消してシャープに光を減衰させるために、例えばrimを3乗したものをrimColorに乗算してからEmissionに代入する方法があります

o.Emission = rimColor *  pow(rim, 3);;

写真は後程

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