实现高光反射光照模型

发布时间 2023-12-16 04:56:28作者: kingBook

\(C_{specular}=(C_{light} \cdot M_{specular})max(0,\hat{V} \cdot \hat{R})^{M_{gloss}}\)
其中,\(C_{light}\) 是光源的颜色,\(M_{specular}\) 是材质的高光反射颜色,\(\hat{V}\) 是由顶点指向相机的单位向量,\(\hat{R}\) 是光源通过顶点的反射单位向量,\(M_{gloss}\) 是材质的光泽度(gloss),下例的取值范围[8,256]。

逐顶点光照:
CG:https://github.com/ding-yan-qing/Unity_Shaders_Book/blob/master/Assets/Shaders/Chapter6/Chapter6-SpecularVertexLevel.shader
HLSL:

Shader "Unity Shaders Book/Chapter 6/Specular Vertex-Level" {
    Properties {
        _Diffuse ("Diffuse", Color) = (1, 1, 1, 1)
        _Specular ("Specular", Color) = (1, 1, 1, 1)
        _Gloss ("Gloss", Range(8.0, 256)) = 20
    }

    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 _Diffuse;
            half4 _Specular;
            float _Gloss;
            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;
                half3 worldNormal = TransformObjectToWorldNormal(input.normal);
                Light mainLight = GetMainLight();

                half3 diffuse = mainLight.color * _Diffuse.rgb * saturate(dot(worldNormal, mainLight.direction));
                 // 注意此处的光源方向默认是由顶点指向光源,因此需要取反
                half3 reflectDir = normalize(reflect(-mainLight.direction, worldNormal));
                half3 viewDir = normalize(GetCameraPositionWS() - TransformObjectToWorld(input.positionOS.xyz));

                half3 specular = mainLight.color * _Specular.rgb * pow(saturate(dot(reflectDir, viewDir)), _Gloss);

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

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