kingBook

导航

实现高光反射光照模型

Phong高光反射模型
\(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]。同样,需要max函数防止 \(\hat{V} \cdot \hat{R}\) 点积的结果为负值。

逐顶点光照:
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
        }
    }
}

逐像素光照:
CG:https://github.com/ding-yan-qing/Unity_Shaders_Book/blob/master/Assets/Shaders/Chapter6/Chapter6-SpecularPixelLevel.shader
HLSL:

Shader "Unity Shaders Book/Chapter 6/Specular Pixel-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;
                float3 worldNormal : TEXCOORD0;
                float3 worldPos : TEXCOORD1;
            };

            Varyings vert(Attributes input)
            {
                Varyings output;

                output.positionCS = TransformObjectToHClip(input.positionOS.xyz);
                output.worldNormal = TransformObjectToWorldNormal(input.normal);
                output.worldPos = TransformObjectToWorld(input.positionOS.xyz);
                return output;
            }

            half4 frag(Varyings input): SV_Target
            {
                half3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                half3 worldNormal = input.worldNormal;
                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() - input.worldPos.xyz);

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

                half3 color = ambient + diffuse + specular;
                return half4(color, 1.0);
            }
            ENDHLSL
        }
    }
}

Blinn-Phong高光反射模型:
Blinn模型引入了一个新的向量\(\hat{H}\)
\(\hat{H}=\frac{\hat{V}+I}{|\hat{V}+I|}\)
然后,使用\(\hat{N}\)\(\hat{H}\)之间的夹角进行计算,而非\(\hat{V}\)\(\hat{R}\)之间的夹角。

\(C_{specular}=(C_{light} \cdot M_{specular})max(0,\hat{N} \cdot \hat{H})^{M_{gloss}}\)
其中,\(C_{light}\) 是光源的颜色,\(M_{specular}\) 是材质的高光反射颜色,\(\hat{N}\) 是顶点的单位化法线向量,\(M_{gloss}\) 是材质的光泽度(gloss),下例的取值范围[8,256]。同样,需要max函数防止 \(\hat{N} \cdot \hat{H}\) 点积的结果为负值。
CG:https://github.com/ding-yan-qing/Unity_Shaders_Book/blob/master/Assets/Shaders/Chapter6/Chapter6-BlinnPhong.shader
HLSL:

Shader "Unity Shaders Book/Chapter 6/Blinn Phong" {
    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;
                float3 worldNormal : TEXCOORD0;
                float3 worldPos : TEXCOORD1;
            };

            Varyings vert(Attributes input)
            {
                Varyings output;

                output.positionCS = TransformObjectToHClip(input.positionOS.xyz);
                output.worldNormal = TransformObjectToWorldNormal(input.normal);
                output.worldPos = TransformObjectToWorld(input.positionOS.xyz);
                return output;
            }

            half4 frag(Varyings input): SV_Target
            {
                half3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                half3 worldNormal = input.worldNormal;
                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() - input.worldPos.xyz);
                half3 halfDir = normalize(mainLight.direction + viewDir);

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

                half3 color = ambient + diffuse + specular;
                return half4(color, 1.0);
            }
            ENDHLSL
        }
    }
}

posted on 2023-12-16 04:54  kingBook  阅读(17)  评论(0编辑  收藏  举报