Unity Shader入门教程(五):Unity中实现漫反射光照模型

发表于2018-06-06
评论0 2.1k浏览
下面要跟大家介绍的是在Unity中实现漫反射光照模型,不清楚的可以学习下。

一、兰伯特逐顶点级光照
// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'
Shader "Custom/Edu/DiffuseVertexLevel" {
    Properties
    {
        _Diffuse("Diffuse",Color) = (1,1,1,1)
    }
    SubShader
    {
        Pass
        {
            Tags{"LightMode" = "ForwardBase"}
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "Lighting.cginc"
            fixed4 _Diffuse;
            struct a2v
            {
                float4 vertex :POSITION;
                float3 normal:NORMAL;
            };
            struct v2f
            {
                float4 pos:SV_POSITION;
                fixed3 color:COLOR;
            };
            v2f vert(a2v v)
            {
                v2f o;
                o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                fixed3 worldNormal = normalize(mul(v.normal,(float3x3)unity_WorldToObject));
                fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
                fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal,worldLight));
                o.color = ambient + diffuse;
                return o;
            }
            fixed4 frag(v2f i):SV_Target
            {
                return fixed4(i.color,1.0);
            }
            ENDCG
        }
    }
    Fallback "Diffuse"
}

saturate函数的参数x类型可以是float、float2、float3
该函数会将x截取到[0,1],如果有多组分量,则会对每一组分量进行此操作!

二、兰伯特逐片元级光照
Shader "Custom/Edu/DiffusePixelLevel" {
    Properties {
        _Diffuse("Diffuse",Color) = (1,1,1,1)
    }
    SubShader {
        Pass
        {
            Tags { "LightMode"="ForwardBase" }
            LOD 200
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "Lighting.cginc"
            #pragma target 3.0
            fixed4 _Diffuse;
            struct a2v
            {
                float4 vertex:POSITION;
                float3 normal:NORMAL;
            };
            struct v2f
            {
                float4 pos:SV_POSITION;
                float3 worldNormal:TEXCOORD0;
            };
            v2f vert(a2v v)
            {
                v2f o;
                o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
                o.worldNormal = mul(v.normal,(float3x3)_World2Object);
                return o;
            }
            fixed4 frag(v2f i):SV_Target
            {
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;
                fixed3 worldNormal = normalize(i.worldNormal);
                fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
                fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal,worldLightDir));
                fixed3 color = ambient + diffuse;
                return fixed4(color,1.0);
            }
            ENDCG
        }
    }
    FallBack "Diffuse"
}

通过前面的学习我们已经知道可以通过变换矩阵的逆转置矩阵来对法线进行变换。
o.worldNormal = mul(v.normal,(float3x3)_World2Object);

所以这里我们先取得模型空间到世界空间的变换矩阵的逆矩阵_World2Object,然后将其右乘到法线,得到其转置矩阵与其左乘的效果!

三、半兰伯特光照模型
Shader "Custom/Edu/DiffuseHalfLambert" {
    Properties {
        _Diffuse("Diffuse",Color) = (1,1,1,1)
    }
    SubShader {
        Pass
        {
            Tags {"LightMode"="ForwardBase"}
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "Lighting.cginc"
            fixed4 _Diffuse;
            struct a2v
            {
                float4 vertex:POSITION;
                float3 normal:NORMAL;
            };
            struct v2f
            {
                float4 pos:SV_POSITION;
                float3 worldNormal:TEXCOORD0;
            };
            v2f vert(a2v v)
            {
                v2f o;
                o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
                o.worldNormal = mul(v.normal,(float3x3)_World2Object);
                return o;
            }
            fixed4 frag(v2f i):SV_Target
            {
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;
                float3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
                float3 worldNormal = normalize(i.worldNormal);
                fixed halfLambert = dot(worldNormal,worldLightDir)*0.5 + 0.5;
                fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * halfLambert;
                fixed3 color = diffuse + ambient;
                return fixed4(color,1.0);
            }
            ENDCG
        }
    }
    FallBack "Diffuse"
}

半兰伯特公式:

半兰伯特的相对于此前的模型,并没有对n·I施加max操作,而是对n·I进行了α倍的缩放同时进了β大小的平移。

四、效果图

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引