LoginSignup
15
12

More than 3 years have passed since last update.

【Unity】【Shader】影を描画する、影を受け取る

Last updated at Posted at 2020-01-15

はじめに

例えばDiffuseのShaderを自作すると、それだけでは影が描画されない。影の実装も自分で行う必要があるので、それをやってみる。

Screen Shot 2020-01-15 at 18.17.38.png

周りのオブジェクトに影を描画する

まずは、自身が周りのオブジェクトから影を受けるようにする。

Passが二つ

今回の方法では、Pass{}を二つ記述する必要がある。一つ目のPassでオブジェクトの色を描画、二つ目のPassで影を描画することになる。

"LightMode"="ShadowCaster"

LightModeタグはそのPassが光を描画する中で、どんな役割を担うかを定義する。

LightMode tag defines Pass’ role in the lighting pipeline.

影を描画する場合は、Tags{ "LightMode"="ShadowCaster" }とする。これによって、周りのオブジェクトに影を描画するようになる。

ShadowCaster: Renders object depth into the shadowmap or a depth texture.

ShaderLab: Pass Tags

multi_compile_shadowcasterを追加

#pragma multi_compile_shadowcasterを追加する。これでコンパイラに影を描画したいって伝えるらしい?*要確認

マクロを使用する

実際の描画処理はマクロを呼び出すだけで完了する。使うのは以下の3つ。

V2F_SHADOW_CASTER
TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)
SHADOW_CASTER_FRAGMENT(i)

結果

無事に影が描画されるようになりました。

Screen Shot 2020-01-15 at 18.24.40.png

ここまでのコード

Pass
{
    // 一つ目のパス。オブジェクト自身を描画する。
}
Pass
 {
     Tags{ "LightMode"="ShadowCaster" }

     CGPROGRAM
     #pragma vertex vert
     #pragma fragment frag
     #pragma multi_compile_shadowcaster

     #include "UnityCG.cginc"

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

     struct v2f
     {
         V2F_SHADOW_CASTER;
     };

     v2f vert (appdata v)
     {
         v2f o;
         TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)
         return o;
     }

     fixed4 frag (v2f i) : SV_Target
     {
         SHADOW_CASTER_FRAGMENT(i)
     }
     ENDCG
 }

影を受け取る

ここまでの方法では自身が他のオブジェクトの影を受け取ることが出来ない。次にそこを改善してみる。

ひとつめのPassを変更する

他オブジェクトに影を落とすために二つ目のPassを記述したが、自身が影を受け取る場合は、ひとつめのPassを変更する。

pragmaを追加

もうなんの事か分からないけど、これを追加するらしい

#pragma multi_compile_fwdbase nolightmap nodirlightmap nodynlightmap novertexlight

includeも追加

これも何の事か分かってないけど追加する

#include "Lighting.cginc" 
#include "AutoLight.cginc"

Vertex and fragment shader examples

マクロを追加

SHADOW_COORDS, TRANSFER_SHADOW, SHADOW_ATTENUATIONを使用して影を計算する。
TRANSFER_SHADOWにv2fを渡す際はvertexという名前を受け付けないので、posに変更する。
以下のコードにコメントしてある箇所。

結果

無事に影を受け取ることができた。

Screen Shot 2020-01-16 at 8.35.08.png

今回のコード

Shader "Unlit/ShadowVF"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Pass
        {
            Tags { "LightMode"="ForwardBase" }

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_fwdbase nolightmap nodirlightmap nodynlightmap novertexlight
            #include "UnityCG.cginc" 
            #include "UnityLightingCommon.cginc"
            #include "Lighting.cginc" 
            #include "AutoLight.cginc"

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

            struct v2f
            {
                float2 uv : TEXCOORD0;
                fixed4 diff : COLOR0;
                float4 pos : SV_POSITION; // posに変更する!!TRANSFER_SHADOWがposとうい名前でないと受け付けない。
                SHADOW_COORDS(1)
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            v2f vert (appdata v)
            {
                v2f o;
                // ここの左辺もposに変更
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv = v.texcoord;
                half3 worldNormal = UnityObjectToWorldNormal(v.normal);
                half NdotL = saturate(dot(worldNormal, _WorldSpaceLightPos0.xyz));
                o.diff = NdotL * _LightColor0;
                TRANSFER_SHADOW(o)

                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2D(_MainTex, i.uv);
                // 影を計算
                fixed4 shadow = SHADOW_ATTENUATION(i);
                col *= i.diff * shadow;
                return col;
            }
            ENDCG
        }

        Pass
        {
            Tags{ "LightMode"="ShadowCaster" }

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_shadowcaster

            #include "UnityCG.cginc"

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

            struct v2f
            {
                V2F_SHADOW_CASTER;
            };

            v2f vert (appdata v)
            {
                v2f o;
                TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                SHADOW_CASTER_FRAGMENT(i)
            }
            ENDCG
        }

    }
}

15
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
12