ノーマルマップ - saitocastel1900/UnityShader GitHub Wiki

  • 法線の向きを書き込んだテクスチャをモデルにマッピングすることで、凹凸感を再現する方法のことらしい
  • ノーマルマップを実現する上で重要なのが接線の概念
  • 接線とは、1ピクセル(テクセル)に接する平面を基準とした座標空間のことらしい
    Tangentialvektor svg
    wikiより引用:https://ja.wikipedia.org/wiki/%E6%8E%A5%E3%83%99%E3%82%AF%E3%83%88%E3%83%AB%E7%A9%BA%E9%96%93
  • ノーマルマップは法線を接線空間で書き込んだものなので、まず接線空間基準で色々する必要があるみたい
  • コードだと「TANGENT_SPACE_ROTATION;」で接線空間で変換している
Shader "Unlit/NormalMapUnlitShader"
{
    Properties
    {
        _MainColor ("MainColor", Color) = (1,1,1,1)
        _Reflection ("Reflection", Range(0,1)) = 0.5
        _Specular ("Specular", Range(0,1)) = 0.5
        _NormalMap ("NormalMap", 2D) = "bump" {}
    }
    SubShader
    {
        Tags
        {
            "Queue"="Geometry"
            "RenderType"="Opaque"
            "LightMode"="UniversalForward"
        }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"
            #include "Lighting.cginc"

            float4 _MainColor;
            float _Reflection;
            float _Specular;
            sampler2D _NormalMap;

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                float3 normal:NORMAL;
                float4 tangent:TANGENT;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
                float3 lightDir:TEXCOORD1;
                float3 viewDir:TEXCOORD2;
            };

            v2f vert(appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;

                //接線空間に変換
                TANGENT_SPACE_ROTATION;

                o.lightDir = normalize(mul(rotation, ObjSpaceLightDir(v.vertex)));

                o.viewDir = normalize(mul(rotation, ObjSpaceViewDir(v.vertex)));

                return o;
            }

            fixed4 frag(v2f i) : SV_Target
            {
                //ノーマルマップから法線を取得
                float3 normal = UnpackNormal(tex2D(_NormalMap, i.uv));

                //反射ベクトルを計算
                float3 refVec = reflect(-i.lightDir, normal);

                //内積を求めて
                float dotVR = dot(refVec, i.viewDir);

                //0以下の内積を扱わないようにして
                dotVR = max(0,dotVR);
                dotVR = pow(dotVR,_Reflection);
                float3 specular = _LightColor0.xyz * _Specular;

                //内積を使って色を計算
                return lerp(_MainColor,float4(specular,1),dotVR);
            }
            ENDCG
        }
    }
}