基本光照模型简单实现

Lambert光照模型,根据光照向量与顶点法线的夹角来确定光照强度:

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader "James/Lambert"
{
    Properties
    {
        _MainTex("MainTex", 2D) = "white" {}
    }
        SubShader
    {
        Pass
        {
            Tags { "LightMode" = "ForwardBase" }
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            fixed4 _LightColor0;
            sampler2D _MainTex;
            float4 _MainTex_ST;
            struct v2f
            {
                float4 pos : SV_POSITION;
                float2 uv : TEXCOORD0;
                float3 lightDir : TEXCOORD1;
                float3 normal : TEXCOORD2;
            };

            v2f vert(appdata_full v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
                // 从顶点位置到Light的局部向量
                o.lightDir = ObjSpaceLightDir(v.vertex);
                o.normal = v.normal;
                return o;
            }

            float4 frag(v2f i) : COLOR
            {
                i.lightDir = normalize(i.lightDir);
                i.normal = normalize(i.normal);
                // 纹理采样
                float4 c = tex2D(_MainTex, i.uv);
                // 光强度,法向和光照方向的cos值
                float diffuse = max(0, dot(i.normal, i.lightDir));
                // 纹理色 * 光源色 * 强度参数
                c = c * _LightColor0 * diffuse;
                return c;
            }
            ENDCG
        }
    }
        FallBack "Diffuse"
}

Phong光照模型,根据光照向量的反射向量与视线的夹角来计算镜面高光的强度,另外再加上漫射光的成分:

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader "James/Phong"
{
    Properties
    {
        _MainTex("MainTex", 2D) = "white" {}
        _Gloss("Gloss", Float) = 1
        _Shininess("Shininess", Float) = 10
        _SpecColor("Specular Color", Color) = (1,1,1,1)
    }
    SubShader
    {
        Pass
        {
            Tags { "LightMode" = "ForwardBase" }
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            fixed4 _LightColor0;
            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _Gloss;
            float _Shininess;
            fixed4 _SpecColor;

            struct v2f
            {
                float4 pos : SV_POSITION;
                float2 uv : TEXCOORD0;
                float3 normal : TEXCOORD1;
                float3 lightDir : TEXCOORD2;                // 光照方向
                float3 reflectLightDir : TEXCOORD3;            // 光照反射方向
                float3 viewDir : TEXCOORD4;                    // 视线方向
            };

            v2f vert(appdata_full v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
                o.normal = v.normal;
                // 从顶点位置到light的局部向量
                o.lightDir = ObjSpaceLightDir(v.vertex);
                // 反射向量,注意需要使用-o.lightDir
                o.reflectLightDir = reflect(-o.lightDir, v.normal);
                // 视线,顶点到camera的局部变量
                o.viewDir = ObjSpaceViewDir(v.vertex);
                return o;
            }

            float4 frag(v2f i) : COLOR
            {
                i.lightDir = normalize(i.lightDir);
                i.normal = normalize(i.normal);
                i.reflectLightDir = normalize(i.reflectLightDir);
                i.viewDir = normalize(i.viewDir);

                // 纹理采样
                float4 c = tex2D(_MainTex, i.uv);
                // 漫射光强度
                float diffuse = max(0, dot(i.normal, i.lightDir));

                // 镜面光强度
                float specular = max(0, dot(i.reflectLightDir, i.viewDir));
                specular = pow(specular, _Shininess) * _Gloss;
                // 纹理色 * 光源色 * 强度参数
                c = (c * diffuse + _SpecColor * specular) * _LightColor0;

                return c;
            }
            ENDCG
        }
    }
    FallBack "Diffuse"
}

BlinnPhong光照模型,根据光照向量和视线的半角向量,与顶点法线的夹角来计算镜面高光的强度,另外再加上漫射光的成分:

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader "James/BlinnPhong"
{
    Properties
    {
        _MainTex("MainTex", 2D) = "white" {}
        _Gloss("Gloss", Float) = 5
        _Shininess("Shininess", Float) = 10
        _SpecColor("Specular Color", Color) = (1,1,1,1)
    }
        SubShader
        {
            Pass
            {
                Tags { "LightMode" = "ForwardBase" }
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                #include "UnityCG.cginc"

                fixed4 _LightColor0;
                sampler2D _MainTex;
                float4 _MainTex_ST;
                float _Gloss;
                float _Shininess;
                fixed4 _SpecColor;

                struct v2f
                {
                    float4 pos : SV_POSITION;
                    float2 uv : TEXCOORD0;
                    float3 normal : TEXCOORD1;
                    float3 lightDir : TEXCOORD2;        // 光照方向
                    float3 viewDir : TEXCOORD3;                // 视线方向
                };

                v2f vert(appdata_full v)
                {
                    v2f o;
                    o.pos = UnityObjectToClipPos(v.vertex);
                    o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
                    o.normal = v.normal;
                    // 顶点->light的局部向量
                    o.lightDir = ObjSpaceLightDir(v.vertex);
                    // 顶点->camera的局部向量
                    float3 viewDir = ObjSpaceViewDir(v.vertex);
                    // 视线,顶点到camera的局部变量
                    o.viewDir = ObjSpaceViewDir(v.vertex);
                    return o;
                }

                float4 frag(v2f i) : COLOR
                {
                    i.lightDir = normalize(i.lightDir);
                    i.normal = normalize(i.normal);
                    i.viewDir = normalize(i.viewDir);
                    // 半角向量,光照方向和视线的中间值
                    float3 halfDir = (i.lightDir + i.viewDir) * 0.5;
                    halfDir = normalize(halfDir);

                    // 纹理采样
                    float4 c = tex2D(_MainTex, i.uv);
                    // 漫射光强度
                    float diffuse = max(0, dot(i.normal, i.lightDir));

                    // 镜面光强度
                    float specular = max(0, dot(i.normal, halfDir));
                    specular = pow(specular, _Shininess) * _Gloss;

                    // 纹理色 * 光源色 * 强度参数
                    c = (c * diffuse + _SpecColor * specular) * _LightColor0;
                    return c;
                }
                ENDCG
            }
        }
            FallBack "Diffuse"
}

BinnPhong比Phong少计算一次反射向量,会更简洁和高效。

 

带光源衰减的计算方式:

Shader "James/Direct2"
{
    Properties
    {
        _Color("Color",Color) = (1,1,1,1)
        _SpecularColor("Specular",Color) = (1,1,1,1)
        _Gloss("Gloss",Range(8.0,256)) = 20
    }

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

            CGPROGRAM
            #pragma multi_compile_fwdbase
            #pragma vertex vert
            #pragma fragment frag

            #include "Lighting.cginc"
            #include "AutoLight.cginc" 
            //计算阴影所用的宏包含在AutoLight.cginc文件中

            fixed4 _Color;
            fixed4 _SpecularColor;
            float _Gloss;

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

            struct v2f 
            {
                float4 pos:SV_POSITION;
                float3 worldPos:TEXCOORD0;
                float3 worldNormal:TEXCOORD1;
                SHADOW_COORDS(2)
                //该宏的作用是声明一个用于对阴影纹理采样的坐标
                //这个宏的参数是下一个可用的插值寄存器的索引值,上述中为2
            };

            v2f vert(a2v v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;
                o.worldNormal = UnityObjectToWorldNormal(v.normal);

                TRANSFER_SHADOW(o);
                //该宏用于计算上一步声明的阴影纹理采样坐标

                return o;
            }

            fixed4 frag(v2f i) :SV_Target
            {
                float3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
                float3 worldNormal = normalize(i.worldNormal);
                float3 worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));

                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                fixed3 diffuse = _LightColor0.rgb*_Color.rgb*max(0,dot(worldLightDir,worldNormal));
                fixed3 halfDir = normalize(worldLightDir + worldViewDir);
                fixed3 specularColor = _LightColor0.rgb*_SpecularColor.rgb*pow(saturate(dot(halfDir,worldNormal)),_Gloss);

                fixed shadow = SHADOW_ATTENUATION(i);
                //片元着色器中计算阴影值

                fixed atten = 1.0;
                return fixed4(ambient + (diffuse + specularColor)*atten*shadow,1.0);
            }
            ENDCG
        }

        Pass
        {
            Tags{"LightMode" = "ForwardAdd"}
            Blend One One
            CGPROGRAM
            #pragma multi_compile_fwdadd
            #pragma vertex vert
            #pragma fragment frag

            #include "Lighting.cginc"
            #include "AutoLight.cginc"

            fixed4 _Color;
            fixed4 _SpecularColor;
            float   _Gloss;

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

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

            v2f vert(a2v v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;
                o.worldNormal = UnityObjectToWorldNormal(v.normal);

                return o;
            }

            fixed4 frag(v2f i) :SV_Target
            {
                #ifdef USING_DIRECTIONAL_LIGHT
                    fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
                    fixed atten = 1.0;
                #else
                    fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz - i.worldPos.xyz);
                    float3 lightCoord = mul(unity_WorldToLight,float4(i.worldPos,1.0)).xyz;
                    fixed atten = tex2D(_LightTexture0,dot(lightCoord,lightCoord).rr).UNITY_ATTEN_CHANNEL;
                #endif
                float3 worldNormal = normalize(i.worldNormal);
                float3 worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));

                fixed3 diffuse = _LightColor0.rgb*_Color.rgb*max(0,dot(worldLightDir,worldNormal));
                fixed3 halfDir = normalize(worldLightDir + worldViewDir);
                fixed3 specularColor = _LightColor0.rgb*_SpecularColor.rgb*pow(saturate(dot(halfDir,worldNormal)),_Gloss);


                return fixed4((diffuse + specularColor)*atten,1.0);
            }
            ENDCG
        }
    }
    FallBack "Specular"
}

参考:https://blog.csdn.net/u013477973/article/details/80639969

 

posted @ 2015-08-31 17:45  斯芬克斯  阅读(1561)  评论(0编辑  收藏  举报