UnityShader基础(一)——基础光照

        在入门系列最后一节中可以看到输出结果,尽管模型是一个立方体,但我们看到的就是一坨,为了丰富细节,会模拟光照使模型表面更加明显,就如同在现实生活中我们看到物体时是借助光线,在Shader也是同样。

1.1 自发光:

        在上一篇文章中已经指明,向外暴露的_Color属性即是物体的自发光。

1.2 环境光:

        绝大多数物体都是没有自发光特性的,因此光照模型计算一般不会让自发光参与,想要计算自发光也可以,只需在最后将自发光颜色与环境光颜色相加后输出。        

Shader "Custom/Test0"
{
    Properties
    {
    }
    SubShader
    {
        
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            fixed4 _Color;
            float4 vert(float4 vertex:POSITION):SV_POSITION
            {
                //坐标转换
                return UnityObjectToClipPos(vertex);                
            }

            fixed4 frag():SV_Target
            {
                //使用内置宏来得到Unity的环境光颜色并返回                
                return fixed4(UNITY_LIGHTMODEL_AMBIENT.rgb,1);
            }
            
            ENDCG
        }
    }
}

1.3 环境光+漫反射:

        注意环境光不应为白色附近,否则无法得到正确光照结果,建议为环境光为黑色,场景中的平行光为白色。

        漫反射光照公式:gif.latex?c_%7Bdiffuse%7D%3D%28c_%7Blight%7D*m_%7Bdiffuse%7D%29max%280%2Cn%5Ccdot%20l%20%29

        gif.latex?c_%7Blight%7D是光源颜色,gif.latex?m_%7Bdiffuse%7D是材质的漫反射颜色,gif.latex?n为表面法线的方向,gif.latex?l为指向光源的方向,注意本系列除特外说明,所用到的方向全是单位矢量。

       1.3.1 逐顶点光照:

Shader "Custom/Test1"
{
    Properties
    {
        _Diffuse("漫反射系数",Color)=(1,1,1,1)
    }
    SubShader
    {
        
        Pass
        {
            Tags{"LightMode"="ForwardBase"}
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #include "UnityLightingCommon.cginc"
            fixed4 _Diffuse;

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

            struct v2f
            {
                float4 vertex:SV_POSITION;
                fixed3 color :COLOR;             
            };
            
            v2f vert(a2v i)
            {
                v2f o;
                o.vertex=UnityObjectToClipPos(i.vertex);

                fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.rgb;

                fixed3 worldNormal = UnityObjectToWorldNormal(i.normal);

                fixed3 worldLight=normalize(_WorldSpaceLightPos0.xyz);
                //向量在同一空间下,计算才有意义
                fixed3 diffuse=_LightColor0.rgb*_Diffuse.rgb*
                               saturate(dot(worldLight,worldNormal));

                o.color=ambient+diffuse;

                return o;
                
            }

            fixed4 frag(v2f i):SV_Target
            {
                //将已经插值过的颜色输出                            
                return fixed4(i.color,1);
            }
            
            ENDCG
        }
    }
}

       1.3.2 逐像素光照:

Shader "Custom/Test2"
{
    Properties
    {
        _Diffuse("漫反射系数",Color)=(1,1,1,1)
    }
    SubShader
    {
        
        Pass
        {
            Tags{"LightMode"="ForwardBase"}
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #include "UnityLightingCommon.cginc"
            fixed4 _Diffuse;

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

            struct v2f
            {
                float4 vertex:SV_POSITION;
                float3 worldNormal :COLOR;             
            };
            
            v2f vert(a2v v)
            {
                v2f o;

                o.vertex=UnityObjectToClipPos(v.vertex);
               
                o.worldNormal = UnityObjectToWorldNormal(v.normal);

                return o;
                
            }

            fixed4 frag(v2f i):SV_Target
            {
                fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.rgb;
        
                fixed3 worldNormal=normalize(i.worldNormal);

                fixed3 worldLight=normalize(_WorldSpaceLightPos0.xyz);

                fixed3 diffuse=_LightColor0.rgb*_Diffuse.rgb*
                             saturate(dot(worldLight,worldNormal));
                return fixed4(ambient+diffuse,1);
            }
            
            ENDCG
        }
    }
}

      1.3.3  半兰伯特模型:

Shader "Custom/Test2"
{
    Properties
    {
        _Diffuse("漫反射系数",Color)=(1,1,1,1)
    }
    SubShader
    {
        
        Pass
        {
            Tags{"LightMode"="ForwardBase"}
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #include "UnityLightingCommon.cginc"
            fixed4 _Diffuse;

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

            struct v2f
            {
                float4 pos:SV_POSITION;
                float3 worldNormal :COLOR;             
            };
            
            v2f vert(a2v v)
            {
                v2f o;

                o.pos=UnityObjectToClipPos(v.vertex);
               
                o.worldNormal = UnityObjectToWorldNormal(v.normal);

                return o;
                
            }

            fixed4 frag(v2f i):SV_Target
            {
                fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.rgb;
        
                fixed3 worldNormal=normalize(i.worldNormal);

                fixed3 worldLight=normalize(_WorldSpaceLightPos0.xyz);

                fixed3 diffuse=_LightColor0.rgb*_Diffuse.rgb*
                             (dot(worldLight,worldNormal)*0.5+0.5);
                return fixed4(ambient+diffuse,1);
            }
            
            ENDCG
        }
    }
}

c6a496467f484ab79dffec91d7797e6c.png

 左一侧为逐顶点,左二为逐像素,左三为半兰伯特。

        区别:逐像素的光照因为计算频率更高,得到的效果也普遍更好。

1.4 环境光+漫反射+高光反射:

        1.4.1 逐顶点:

Shader "Custom/Test1"
{
    Properties
    {
        _Diffuse("漫反射系数",Color)=(1,1,1,1)
        _Specular("高光反射系数",Color)=(1,1,1,1)
        _Gloss("光泽度",Range(0,256))=20
    }
    SubShader
    {
        
        Pass
        {
            Tags{"LightMode"="ForwardBase"}
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #include "UnityLightingCommon.cginc"
            fixed4 _Diffuse;
            fixed4 _Specular;
            fixed _Gloss;
            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=UnityObjectToClipPos(v.vertex);

                fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.rgb;
                //漫反射计算
                fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);

                fixed3 worldLight=normalize(_WorldSpaceLightPos0.xyz);

                fixed3 diffuse=_LightColor0.rgb*_Diffuse.rgb*
                            saturate(dot(worldLight,worldNormal));
                //高光反射计算
                fixed3 reflectDir=normalize(reflect(-worldLight,v.normal));

                fixed3 viewDir=normalize(WorldSpaceViewDir(v.vertex));
                
                fixed3 specular=_LightColor0*_Specular*
                            pow(saturate(dot(viewDir,reflectDir)),_Gloss);
                
                o.color=ambient+diffuse+specular;

                return o;
                
            }

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

        1.4.2 常规逐像素:

Shader "Custom/Test2"
{
    Properties
    {
        _Diffuse("漫反射系数",Color)=(1,1,1,1)
        _Specular("高光反射系数",Color)=(1,1,1,1)
        _Gloss("光泽度",Range(0,256))=20
    }
    SubShader
    {
        
        Pass
        {
            Tags{"LightMode"="ForwardBase"}
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #include "UnityLightingCommon.cginc"
            fixed4 _Diffuse;
            fixed4 _Specular;
            fixed _Gloss;

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

            struct v2f
            {
                float4 vertex:SV_POSITION;
                float3 worldNormal :TEXCOORD0;                
                float3 worldPos:TEXCOORD1;
          
            };
            
            v2f vert(a2v v)
            {
                v2f o;
                o.vertex=UnityObjectToClipPos(v.vertex);               
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
                //unity有一个内置API,只能负责向量变化,顶点不能使用
                o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;   
                return o;
                
            }

            fixed4 frag(v2f i):SV_Target
            {
                fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.rgb;

                fixed3 worldNormal=normalize(i.worldNormal);

                fixed3 worldLight=normalize(_WorldSpaceLightPos0.xyz);

                fixed3 diffuse=_LightColor0.rgb*_Diffuse.rgb
                            *saturate(dot(worldLight,worldNormal));

                //高光反射计算
                fixed3 reflectDir=normalize(reflect(-worldLight,i.worldNormal));

                fixed3 viewDir=normalize(_WorldSpaceCameraPos-i.worldPos);
  
                fixed3 specular=_LightColor0.rgb*_Specular
                            *pow(saturate(dot(viewDir,reflectDir)),_Gloss);
                
                return fixed4(ambient+diffuse+specular,1);
            }
            
            ENDCG
        }
    }
}

        1.4.3 Blinn-Phong逐像素:

Shader "Custom/Test2"
{
    Properties
    {
        _Diffuse("漫反射系数",Color)=(1,1,1,1)
        _Specular("高光反射系数",Color)=(1,1,1,1)
        _Gloss("光泽度",Range(0,256))=20
    }
    SubShader
    {
        
        Pass
        {
            Tags{"LightMode"="ForwardBase"}
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #include "UnityLightingCommon.cginc"
            fixed4 _Diffuse;
            fixed4 _Specular;
            fixed _Gloss;

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

            struct v2f
            {
                float4 vertex:SV_POSITION;
                float3 worldNormal :TEXCOORD0;                
                float3 worldPos:TEXCOORD1;
          
            };
            
            v2f vert(a2v v)
            {
                v2f o;
                o.vertex=UnityObjectToClipPos(v.vertex);               
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
                //unity有一个内置API,只能负责向量变化,顶点不能使用
                o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;   
                return o;
                
            }

            fixed4 frag(v2f i):SV_Target
            {
                fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.rgb;

                fixed3 worldNormal=normalize(i.worldNormal);

                fixed3 worldLight=normalize(_WorldSpaceLightPos0.xyz);

                fixed3 diffuse=_LightColor0.rgb*_Diffuse.rgb
                            *saturate(dot(worldLight,worldNormal));
               
                //高光反射计算
                fixed3 viewDir=normalize(_WorldSpaceCameraPos-i.worldPos);
                
                fixed3 halfDir=normalize(viewDir+worldLight);
                
                fixed3 specular=_LightColor0.rgb*_Specular
                            *pow(saturate(dot(worldNormal,halfDir)),_Gloss);
                
                return fixed4(ambient+diffuse+specular,1);
            }
            
            ENDCG
        }
    }
}

546dda175e594c43b5ffbdffc166d286.png

        左一侧为逐顶点,左二为常规逐像素,左三为Blinn-Phong。

        一般使用Blinn-Phong光照模型的更多。逐顶点的高光部分表现并不好,主要是高光计算是非线性的,而插值过程是线性的,非线性的计算会破坏线性的插值,使得线性的结果变的非线性,也就导致高光不平滑。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值