2DLookupLighting(FakeBRDF)

環境

Unity2021.2.18f1

概要

Lookupテクスチャを使用したライティングです。

以下のページの画像に対応するようにしています。 BRDF - Wakapon http://wiki.nuaj.net/images/0/0e/MERL100Slices.jpg

Shader "Unlit/2DLookupLighting"
{
    Properties
    {
        _NormalTex("Normal Texture", 2D) = "white" {}
        _Lookup("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            Tags { "LightMode" = "ForwardBase" }
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

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

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

            struct v2f
            {
                float4 positionCS : SV_POSITION;
                float2 uv     : TEXCOORD0;
                fixed3 TSToWS0 : TEXCOORD1;
                fixed3 TSToWS1 : TEXCOORD2;
                fixed3 TSToWS2 : TEXCOORD3;
                half3 viewDirWS: TEXCOORD4;
                half3 lightDirWS: TEXCOORD5;
            };

            sampler2D _NormalTex;
            float4 _NormalTex_ST;
            sampler2D _Lookup;

            v2f vert(appdata v)
            {
                v2f o;
                o.positionCS = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _NormalTex);
                fixed3 normalWS = UnityObjectToWorldNormal(v.normal);
                fixed3 tangentWS = UnityObjectToWorldDir(v.tangent.xyz);
                fixed3 binormalWS = cross(normalWS, tangentWS) * v.tangent.w;
                o.TSToWS0 = fixed3(tangentWS.x, binormalWS.x, normalWS.x);
                o.TSToWS1 = fixed3(tangentWS.y, binormalWS.y, normalWS.y);
                o.TSToWS2 = fixed3(tangentWS.z, binormalWS.z, normalWS.z);
                o.viewDirWS = WorldSpaceViewDir(v.vertex);
                o.lightDirWS = WorldSpaceLightDir(v.vertex);
                return o;
            }

            fixed3 LightingLookup(half3 lightDir, half3 viewDir, half3 normal)
            {
#define HALF_VEC 1
#if HALF_VEC
                half3 HalfDir = normalize(lightDir + viewDir);
                float NdotL = dot(normal, HalfDir);
#else
                float NdotL = dot(normal, viewDir);
#endif
                float NdotV = dot(normal, viewDir);

                float2 lookupUV = float2(1.0 - (NdotL * 0.5 + 0.5), 1.0 - saturate(NdotV));
                fixed3 exitRadiance = tex2D(_Lookup, lookupUV).rgb;
                float atten = 1;
                return _LightColor0.rgb * (exitRadiance * atten * 2);
            }

            fixed4 frag(v2f i) : SV_Target
            {
                half3 normalTS = UnpackNormal(tex2D(_NormalTex, i.uv));
                half3 normalWS;
                normalWS.x = dot(i.TSToWS0.xyz, normalTS);
                normalWS.y = dot(i.TSToWS1.xyz, normalTS);
                normalWS.z = dot(i.TSToWS2.xyz, normalTS);
                normalWS = normalize(normalWS);

                half3 lightDirWS = normalize(i.lightDirWS);
                half3 viewDirWS = normalize(i.viewDirWS);
                fixed3 diffuse = LightingLookup(lightDirWS, viewDirWS, normalWS);

                return fixed4(diffuse, 1);
            }
            ENDCG
        }
    }
}

参考

Problem with BRDF Shader - Unity Forum

Writing Surface Shaders in Unity3D: BRDF Fake - YouTube

Index of /datahoarder/Walt Disney Animation Studios/BRDF Explorer

Dropbox - BRDFDatabase - Simplify your life