C++幼女先輩

プログラミング成分多め

UNITYで影を受け取る

前回は影を落としましたがまだこのシェーダでは影を受け取れません
地面(Plane)メッシュのシェーダーを 今使ってる yUnitに変えると影はおちないし、セルフシャドウもありません
今回は影を受け取るようにします

https://github.com/YukiMiyatake/UnityLesson/tree/Shadow_2github.com

仕組み

UNITYではシャドウマップを使っています
シャドウマップの具体的な説明は他のサイトにお願いして
ライトからみたデプス値を事前に別のテクスチャに書き込んでおきます
レンダリング時に、ライトからみたデプス値と比較をして、ライトのほうが近い場合は、そのポイントは影になる
という仕組みです
その ライトからみたデプステクスチャを作るパスが、前回つくった ShadowCasterパスになります

今度は、そのデプステクスチャを参照して影を作るのですが
以前のUNITYではShadowReceiveパスで影を処理していたようですが、今は通常のカラーパスにて行うことができます
具体的には、SHADOW_ATTENUATIONマクロを使えば、影は0、表は1で、その間を補完した値が手に入ります
ので そのままカラーに乗算すれば影は黒くなります

pragma

今回は ShadowのON/OFFがあるので、その両方のシェーダをコンパイルする必要があるので下記のpragmaが必要です
本当は 各種ライトに対するシェーダも必要なので もっとたくさん必要ですが、今回は最低限

#pragma multi_compile_fwdbase

構造体

フラグメントシェーダにて SHADOW_ATTENUATIONマクロを使いますが、そのために必要な入力値があるので追加
v2fにSHADOW_COORDS(n) を追加し、影用のテクスチャを追加します。今回はテクスチャ2番まで使ったので3を割り当て
あと、私が少しハマったのが、ポジションを posという名前にしなければ計算できないようです・・・
ので 以前 vertexとしていたメンバ名を posに変える

影の取得

SHADOW_ATTENUATIONに、入力構造体の中身を渡せば 0.0~1.0の範囲で取得できます
今回は単純にそれをdiffuseに乗算します

             float3 diffuse = (NdotL*0.5 + 0.5) * lightCol * SHADOW_ATTENUATION(i);

完成コード(ForwardBaseパスのみ)

     Pass{
            Tags{
                "LightMode" = "ForwardBase"
            }

            Cull Back

            CGPROGRAM
           #pragma vertex vert
           #pragma fragment frag

           #include "UnityCG.cginc"
           #include "Lighting.cginc"
           #include "AutoLight.cginc"
                         #pragma multi_compile_fwdbase

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

            struct v2f
            {
                float4 pos : SV_POSITION;
                float4 vertexW: TEXCOORD0;
                float2 uv     : TEXCOORD1;
                float3 normalWorld : TEXCOORD2;
                SHADOW_COORDS(3)
            };

            uniform sampler2D _MainTex; uniform float4 _MainTex_ST;
            uniform float _Spec1Power;
            uniform float4 _Spec1Color;


            v2f vert(appdata_full v){
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.vertexW = mul(unity_ObjectToWorld, v.vertex);

                o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
                o.normalWorld = UnityObjectToWorldNormal(v.normal);

                half3 eyeVec = normalize(o.vertexW.xyz - _WorldSpaceCameraPos);

                TRANSFER_SHADOW(o);

                return o;
            }

            float4 frag(v2f i) : SV_Target{
                float3 L = normalize(_WorldSpaceLightPos0.xyz);
                float3 V = normalize(_WorldSpaceCameraPos - i.vertexW.xyz);
                float3 N = i.normalWorld;
                float3 H = normalize(L + V);


                //LightColor
                float3 lightCol = _LightColor0.rgb * LIGHT_ATTENUATION(i);

                //Ambient
                float3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;
                
                // texture albedo
                float4 tex = tex2D(_MainTex, i.uv);

                // Diffuse(HalfLambert)
                float3 NdotL = dot(N, L);
                float3 diffuse = (NdotL*0.5 + 0.5) * lightCol * SHADOW_ATTENUATION(i);
                // Speculer
            // float3 specular = pow(max(0.0, dot(reflect(-L, N), V)), _Spec1Power) * _Spec1Color.xyz;  // reflection
                float3 specular = pow(max(0.0, dot(H, N)), _Spec1Power) * _Spec1Color.xyz * lightCol;  // Half vector

                return float4( (ambient + diffuse) * tex + specular, 1.0);
            }
            ENDCG
        }

f:id:murasame-labo:20180919185417p:plain

影ができた(でもアクネがあるね)