高光反射

这里的高光反射是一种经验模型,并不完全符合真实世界中的高光反射现象,用于计算那些沿着完全镜面反射方向被反射的光线,可以让物体看起来有光泽,比如金属材质。

计算高光反射需要知道 表面法线,视角方向,光源方向,反射方向等。

我们使用Phong模型 来计算高光反射,公式如下:

_{Cspecular}=(_{Clight} * _{Mspecular})max(0,\hat{v}\cdot\hat{r})^{_{Mgloss}}

其中^{_{Mgloss}}:指的是 材质的光泽度--gloss即反光度。控制高光部分区域,^{_{Mgloss}}越大,亮点就越小。

_{Mspecular} :材质的高光反射系数,控制该材质对于高光反射的强度和颜色。

_{Clight}:入射光源的颜色和强度。

\hat{v}:视角方向。  \hat{r}: 反射方向。

max函数:防止\hat{v}\cdot\hat{r}点积为负数。

CG中提供了计算反射方向的函数 reflect(i,n);

i:入射方向;n:法线方向

扫描二维码关注公众号,回复: 9312855 查看本文章

1.逐顶点光照

Shader "Custom/SpecularVert"
{
    
    Properties
    {
        _DiffuseColor("DiffuseColor",Color)=(1,1,1,1)
        _SpecularColor("SpecularColor",Color)=(1,1,1,1)
        _Gloss("Gloss",Range(8,256))=20
    }

    SubShader
    {
        pass
        {
            Tags{"LightMode"="ForwardBase"}

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "Lighting.cginc"
            fixed4 _DiffuseColor;
            fixed4 _SpecularColor;
            float _Gloss;


            struct a2v
            {
                float4 vertPos:POSITION;
                float3 normal:NORMAL;
            };

            struct v2f
            {
                float4 pos:SV_POSITION;
                float3 color:COLOR;
            };

            v2f vert(a2v v)
            {
                v2f o;
                o.pos=UnityObjectToClipPos(v.vertPos);
                fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.xyz;
                fixed3 worldNormal=normalize(mul(v.normal,(float3x3)unity_WorldToObject));
                fixed3 worldLightDir=normalize(_WorldSpaceLightPos0.xyz);
                fixed3 diffuse=_LightColor0.rgb*_DiffuseColor.rgb*saturate(dot(worldNormal,worldLightDir));
                fixed3 reflectDir=normalize(reflect(-worldLightDir,worldNormal));
                fixed3 viewDir=normalize(_WorldSpaceCameraPos.xyz-mul(unity_ObjectToWorld,v.vertPos).xyz);
                fixed3 specular=_LightColor0.rgb*_SpecularColor.rgb*pow(saturate(dot(reflectDir,viewDir)),_Gloss);
                o.color=ambient+diffuse+specular;
                return o;
            }

            fixed4 frag(v2f i):SV_Target
            {
                return fixed4(i.color,1);
            }

            ENDCG
        }

    }

    FallBack "Specular"
}

可以看出 高光部分 不是那么平滑,这是因为高光反射部分的计算是非线性的,在顶点着色器中计算光照在进行插值是线性的,破坏了原计算的非线性关系。下面采用逐像素方法来计算高光反射部分。

2.逐像素光照

Shader "Custom/SpecularFragment"
{
    Properties
    {
        _DiffuseColor("DiffuseColor",Color)=(1,1,1,1)
        _SpecularColor("SpecularColor",Color)=(1,1,1,1)
        _Gloss("Gloss",Range(8,256))=20
    }

    SubShader
    {
        pass
        {
            Tags{"LightMode"="ForwardBase"}

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "Lighting.cginc"
            fixed4 _DiffuseColor;
            fixed4 _SpecularColor;
            float _Gloss;


            struct a2v
            {
                float4 vertPos:POSITION;
                float3 normal:NORMAL;

            };

            struct v2f
            {
                float4 pos:SV_POSITION;
                float3 worldNormal:TEXCOORD0;
                float3 worldPos:TEXCOORD1;
            };

            v2f vert(a2v v)
            {
                v2f o;
                o.pos=UnityObjectToClipPos(v.vertPos);
                o.worldNormal=mul(v.normal,(float3x3)unity_WorldToObject);
                o.worldPos=mul(unity_ObjectToWorld,v.vertPos).xyz;
                return o;
               
            }

            fixed4 frag(v2f i):SV_Target
            {
                fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.xyz;
                fixed3 worldNormal=normalize(i.worldNormal);
                fixed3 worldLightDir=normalize(_WorldSpaceLightPos0.xyz);
                fixed3 diffuse=_LightColor0.rgb*_DiffuseColor.rgb*saturate(dot(worldNormal,worldLightDir));
                fixed3 reflectDir=normalize(reflect(-worldLightDir,worldNormal));
                fixed3 viewDir=normalize(_WorldSpaceCameraPos.xyz-i.worldPos.xyz);
                fixed3 specular=_LightColor0.rgb*_SpecularColor.rgb*pow(saturate(dot(reflectDir,viewDir)),_Gloss);
                fixed3 scolor=ambient+diffuse+specular;
                return fixed4(scolor,1);
            }

            ENDCG
        }

    }
    FallBack "Diffuse"
}

高光效果会好很多,看起来平滑许多。

发布了76 篇原创文章 · 获赞 43 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/hnzmdlhc/article/details/104402712