Unity Shader 入门(六)镜面高光

简介

之前在讲自定义光照模型时,提到Lambert漫反射光照模型,这是一个用来模拟粗糙表面对光线的漫反射现象的经验模型,对于纸张、粗糙墙壁等等来说,这个模型或许够用,但对于金属这样的光滑表面来说,我们就需要使用Phong模型来模拟光滑表面对光线的镜面反射现象。同Lambert一样,这个模型也是经验模型,而且在程序中,我们经常同时使用Lambert和Phong两个模型,因为在现实世界中,任何表面都会同时发生漫反射和镜面反射两种现象,因此我们就要使用两种模型分别计算两种反射后的光强(也就是顶点颜色值),是渲染的效果看起来真实一些。但要注意,这样做并不会带来真正真实的渲染效果,毕竟这两种模型都是经验模型,考虑的都是理想情况下。而Blinn-phong光照模型是基于Phong的修正模型,因此本文一并归纳。

Phong模型

在理想状况下,镜面反射后的光之集中在一条线上,因此我们的视线离这条线的距离越近,射入我们眼中的光线就越多,我们看到的光强也就越强。同时,镜面反射也与物体表面的高光指数(物体表面光泽程度)有关,其数值越大,反射后的光线越集中,反之则越分散,可能会有人想:如果将高光指数设置的很大,也就是光线极其分散,Phong是否可以用来代替Lambert?答案肯定是不行的,原因是漫反射是将光线反射到各个角度,而镜面反射即使反射光线再分散,它们依旧被限制在一个90度的区域中,因此与漫反射的效果是不一样的。
代码

Shader "Demo/Specular/Phong Texture"{
    Properties{
        _MainTex("MainTex",2D) = ""{}
    }
    SubShader{
        Tags{"RenderType"="Opaque"}
        LOD 200
        CGPROGRAM
        #pragma surface surf CustomSpecular
        sampler2D _MainTex;
        struct Input {
            float2 uv_MainTex;
        };
        void surf(Input IN, inout SurfaceOutput o) {
            half4 c = tex2D(_MainTex, IN.uv_MainTex);
            o.Albedo = c.rgb;
            o.Alpha = c.a;
        }
        inline float4 LightingCustomSpecular(SurfaceOutput s, fixed3 lightDir, half3 viewDir, fixed atten) {
            float diff = max(0, dot(lightDir, s.Normal));
            float3 diffuseColor = s.Albedo * _LightColor0.rgb * diff;
            float3 r = reflect(lightDir, s.Normal);
            float spec = pow(max(0, dot(r, viewDir)), s.Gloss);
            float3 specularColor = s.Specular * _LightColor0.rgb * spec;
            float4 col;
            col.rgb = (diffuseColor + specularColor) * atten * 2;
            col.a = s.Alpha;
            return col;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

效果图

Unity Shader 入门(六)镜面高光_第1张图片
图6-1 左边Lambert,右边Phong

Blinn-phong光照模型

相比较Phong模型,Blinn-phong模型能提供比Phong更柔和、更平滑的高光,而且速度上也更快,因此成为很多CG软件中默认的光照渲染方法,同时也被集成到大多数的图形芯片中,而且在OpenGL和DirectX 3D的渲染管线中,它也是默认的光照模型。计算方法是使用入射光线和视线的中间平均值,即半角向量,和法线计算出一个和视角相关的高光。

代码

Shader "Demo/Specular/BlinnPhong Texture"{
    Properties{
        _MainTex("MainTex", 2D) = ""{}
    }
    SubShader{
        Tags{"RenderType"="Opaque"}
        LOD 200
        CGPROGRAM
        #pragma surface surf CustomSpecular
        sampler2D _MainTex;
        struct Input{
            float2 uv_MainTex;
        };
        void surf(Input IN, inout SurfaceOutput o) {
            half4 c = tex2D(_MainTex, IN.uv_MainTex);
            o.Albedo = c.rgb;
            o.Alpha = c.a;
        }
        inline fixed4 LightingCustomSpecular(SurfaceOutput s, fixed3 lightDir, half3 viewDir, fixed atten) {
            half3 h = normalize(lightDir + viewDir);
            fixed diff = max(0, dot(s.Normal, lightDir));
            fixed nh = max(0, dot(s.Normal, h));
            fixed spec = pow(nh, s.Specular * 128.0) * s.Gloss;
            fixed4 col;
            col.rgb = (s.Albedo * _LightColor0.rgb * diff + _LightColor0.rgb * spec) * (atten * 2);
            col.a = s.Alpha;
            return col;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

效果图

Unity Shader 入门(六)镜面高光_第2张图片
图6-2 左边Lambert,中间Phong,右边BlinnPhong

你可能感兴趣的:(Unity Shader 入门(六)镜面高光)