Unity裏基礎光照(Lambert、Phong、BlinnPhong模型)的Shader代碼

//以下是各種光照模型(Lambert、Phong、BlinnPhong、Gourand)的Shader代碼,在Unity裏創建一個Material後可以選擇使用,各行代碼都有註釋,不再詳細解釋了。

Shader "MyShader/BaseShader"
{
//包含Lambert、Phone、Blin-Phong模型
    Properties
    {//定義屬性
        _Diffuse("Diffuse",Color) = (1,1,1,1)
        _Specular("Specular",Color) = (1,1,1,1)
        _Gloss("Gloss",Range(5,255)) = 5
        [Toggle(_Phong)] _Phong("Phong",float) = 1
        [Toggle(BlinnPhong)] _BlinnPhong("BlinnPhong",float) = 1
        _MainTex ("Texture", 2D) = "white" {}
    }

    SubShader
    {
        Tags { "RenderType"="Opaque" "LightMode"="ForwardBase"} //定義Tag
        //LOD 100

        Pass
        {
            CGPROGRAM
            #include "UnityCG.cginc"    //庫函數
            #include "Lighting.cginc"
            //定義觸發器,改變光照模型
            #pragma shader_feature _PHONG
            #pragma shader_feature _BLINNPHONG
            #pragma shader_feature _LAMBERT
            #pragma shader_feature _GOURAND
            
            #pragma vertex vert //頂點着色器名稱
            #pragma fragment frag   //片元着色器名稱
  
            float4 _Diffuse;    //全局參數,漫反射、高光顏色、高光參數
            float4 _Specular;
            float _Gloss;

            struct a2v
            {//應用傳入頂點着色器的變量
                float4 vertex : POSITION;
                float3 normal :NORMAL;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
                float3 worldNormal: NORMAL;
                float3 worldPos: TEXCOORD1;
                float3 color: TEXCOORD2;                
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            v2f vert (a2v v)
            {//頂點着色器
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);  //頂點空間到裁剪空間
                //o.worldNormal = normalize(mul(v.normal,(float 3x3) unity_worldTo));
                o.worldNormal = UnityObjectToWorldNormal(v.normal);   //法線轉換到世界空間
                o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;   //頂點位置轉換到世界空間

                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                #if defined(_GOURAND)
                    float3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * _Diffuse;    //環境光
                    float3 worldLight = normalize(_WorldSpaceLightPos0.xyz);    //歸一化光方向
                    float3 worldNormal = normalize(o.worldNormal);              //歸一化worldNormal
                    float NdotL = max(0, dot(worldLight, worldNormal));         //法線和光線的點積,即餘弦值
                    float3 diffuse = _LightColor0.rgb * _Diffuse.rgb * NdotL;    //計算漫反射Lambert
                    float3 viewDir = normalize(_WorldSpaceCameraPos.xyz - o.worldPos.xyz);  //視角方向
                    float3 reflectDir = normalize(reflect(-worldLight,worldNormal));  //計算反射方向,worldLight表示入射光方向
                    float VdotR = max(0, dot(reflectDir, viewDir));         //反射光方向與觀察方向的夾角,點積結果爲夾角的餘弦值
                    float3 specular = _LightColor0.rgb * _Specular.rgb * pow(VdotR, _Gloss);    //高光值
                    o.color = diffuse + ambient + specular;     //Gourand模型最後輸出的顏色值
                #endif
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {//片元着色器
                // sample the texture
                //fixed4 col = tex2D(_MainTex, i.uv);
                float3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * _Diffuse;     //環境光
                float3 worldLight = normalize(_WorldSpaceLightPos0.xyz);       //歸一化光方向
                float3 worldNormal = normalize(i.worldNormal);                //歸一化worldNormal
                float NdotL = max(0, dot(worldNormal,worldLight));             //計算漫反射Lambert公式
                fixed4 renderTex = tex2D(_MainTex, i.uv);  

                float3 diffuse = _LightColor0.rgb * _Diffuse.rgb * NdotL;         //計算Diffuse光
                float3 specular;    //存儲高光值
                float3 color;       //存儲最終顏色值

                float3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);  //歸一化視方向
                #if defined(_LAMBERT)
                    color = diffuse;    //Lambert模型
                #endif
                
                //#if defined(_PHONG)
                  //Phong模型計算
                    float3 reflectDir = normalize(reflect(-worldLight,worldNormal));    //計算反射方向,worldLight表示入射光方向
                    float VdotR = max(0, dot(viewDir,reflectDir));   //反射光方向與觀察方向的夾角,dot(ViewDir,ReflectDir)
                    specular = _LightColor0.rgb * _Specular.rgb * pow(VdotR, _Gloss); //計算高光反射
                    color = ambient + diffuse + specular;
                //#endif
                
                #if defined(_BLINNPHONG)
                   //BlinnPhong模型計算
                    float3 halfDir = (worldLight +viewDir);  //計算半角向量,光線方向+視方向的結果歸一化
                    float NdotH = saturate(dot(halfDir,worldNormal));   //半角向量與法線方向的點積,結果歸一化
                    specular = _LightColor0.rgb * _Specular.rgb * pow(NdotH, _Gloss);   //計算BlinnPhong的高光值
                    color = ambient + diffuse + specular;
                #endif
                
                #if defined(_GOURAND)
                    color = i.color;    //直接使用頂點着色器中計算出來的顏色值
                #endif
                color = color * renderTex.rgb;
                return fixed4(color,1.0);
            }
            ENDCG
        }
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章