实现漫反射光照模型

发布时间 2023-12-15 07:38:44作者: kingBook

漫反射光照符合兰伯特定律(Lambert's law),基本光照模型中漫反射计算公式:
\(C_{diffuse}=(C_{light} \cdot M_{diffuse})max(0,\hat{N} \cdot \hat{I} )\)
其中,\(C_{light}\) 是光源的颜色,\(M_{diffuse}\) 是材质的漫反射颜色,\(\hat{N}\) 是单位化的表面法线,\(\hat{I}\) 是指向光源的单位向量。需要注意的是,需要防止法线和光源方向点乘的结果为负值,为此,使用取最大值函数来将其截取到0,这可以防止物体被从后面的光源照亮。

CG: https://github.com/ding-yan-qing/Unity_Shaders_Book/blob/master/Assets/Shaders/Chapter6/Chapter6-DiffuseVertexLevel.shader

HLSL:

Shader "Unity Shaders Book/Chapter 6/Diffuse Vertex-Level" {
    Properties {
        _BaseColor ("BaseColor", Color) = (1, 1, 1, 1)
    }

    SubShader {
        Tags {
            "RenderType"="Opaque"
            "RenderPipeline"="UniversalPipeline"
        }

        Pass {
            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"

            CBUFFER_START(UnityPerMaterial)

            half4 _BaseColor;
            CBUFFER_END

            struct Attributes
            {
                float4 positionOS : POSITION;
                half3 normal:NORMAL;
            };

            struct Varyings
            {
                float4 positionCS : SV_POSITION;
                half3 color:COLOR;
            };

            Varyings vert(Attributes input)
            {
                Varyings output;

                output.positionCS = TransformObjectToHClip(input.positionOS.xyz);

                half3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;

                float3 worldNormal = TransformObjectToWorldNormal(input.normal);
                Light mainLight = GetMainLight();

                half3 diffuse = mainLight.color * _BaseColor.rgb * saturate(dot(worldNormal, mainLight.direction));
                // 也可以直接使用LightingLambert方法
                //half3 diffuse = _BaseColor.rgb * LightingLambert(mainLight.color, mainLight.direction, worldNormal);

                output.color = ambient + diffuse;
                return output;
            }

            half4 frag(Varyings input): SV_Target
            {
                return half4(input.color, 1.0);
            }
            ENDHLSL
        }
    }
}