【UnityShader】高光反射光照模型

光照模型

基本光照模型中高光反射部分的計算公式
Cspecular = (Clight * Mspecular)max(0, v*r)Mgloss
參數:
  Mgloss 光澤度,反光度,控制高光區域的大小,值越大,亮點越小
  Mspecular 材質的高光反射顏色,它用於控制該材質對於高光反射的強度和顏色
  Clight 光源顏色和強度
  v 是視角方向
  r 是反射方向,可以通過計算反射方向的函數
    r = reflect(I,n)
      I,入射方向(要求由光源指向交點處)
      n 法線方向
      r = 2 (n * I)* n - I 菱形
Blinn-Phong 模型的公式
Cspecular = (Clight * Mspecular)max(0, n*h)Mgloss
參數:
  h = normalize(v + I)

實現

逐頂點光照

缺點:高光部分明顯不平滑。主要原因是,高光反射部分的計算是非線性的,而在頂點着色器中計算光照再進行插值的過程是線性的,破壞了原計算的非線性關係,就會出現較大的視覺問題,因此,我們需要使用逐像素的方法來計算高光反射。

Shader "Custom/Shader6_1_sepular_v"
{
    // 高光反射,逐頂點光照
    // 基礎高光放射模型 Csepular = (Clight * Msepular)max(0, n*r)Mgloss
    Properties
    {
        _Diffuse("Diffuse",color)=(1,1,1,1)
        _Sepular("Sepular",color)=(1,1,1,1)
        _Gloss("Gloss",Range(0,256))=128
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 200
        Pass
        {
            Tags{"LightModel"="ForwardBase"}
            CGPROGRAM
            #pragma vertex vert 
            #pragma fragment frag 

            #include "Lighting.cginc"

            fixed4 _Diffuse;
            fixed4 _Sepular;
            float _Gloss;

            struct a2v
            {
                float4 position:POSITION;
                float3 normal:NORMAL;
            };
            struct v2f
            {
                float4 pos:SV_POSITION;
                fixed3 color:COLOR;
            };

            v2f vert(a2v v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.position);

                // 環境光
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                // 漫反射
                fixed3 worldNormal = normalize(mul(v.normal, (fixed3x3)unity_WorldToObject));
                fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
                // 半蘭伯特公式
                fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * (0.5 * dot(worldNormal, worldLightDir) + 0.5);

                // 高光反射
                fixed3 reflectDir = normalize(reflect(-worldLightDir, worldNormal));
                fixed3 sepular = _LightColor0.rgb * _Sepular.rgb * pow(saturate(dot(worldLightDir, reflectDir)), _Gloss);
                o.color = ambient + diffuse + sepular;
                return o;
            }

            fixed4 frag(v2f v):SV_Target
            {
                return fixed4(v.color, 1.0);
            }

            ENDCG
        }
    }
    FallBack "Diffuse"
}
逐像素光照

使用逐像素的方式處理可以得到更加平滑的高光效果。

Shader "Custom/Shader6_1_sepular_f"
{
    // 逐像素光照
    Properties
    {   
        _Diffuse("Diffuse",color) = (1,1,1,1)
        _Sepular("Sepular",color) = (1,1,1,1)
        _Gloss("Gloss",Range(0, 8)) = 4
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 200
        Pass
        {
            Tags{"LightModel"="ForwardBase"}
            CGPROGRAM
            #pragma vertex vert 
            #pragma fragment frag 

            #include "Lighting.cginc"

            fixed4 _Diffuse;
            fixed4 _Sepular;
            float _Gloss;

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

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

            v2f vert(a2v v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.position);
                o.worldNor = mul(v.normal, (fixed3x3)unity_WorldToObject);
                o.worldPos = mul(unity_ObjectToWorld,v.position).xyz;
                return o;
            }

            fixed4 frag(v2f v):SV_Target
            {
                // 環境光
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                fixed3 worldNormal = normalize(v.worldNor);
                fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
                // 漫反射
                fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * (0.5 * (dot(worldNormal, worldLightDir)) + 0.5); 
                // 反射方向
                fixed3 reflectDir = normalize(reflect(-worldLightDir, worldNormal));
                // 視覺方向
                fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - v.worldPos.xyz);
                // 高光反色
                fixed3 sepular = _LightColor0.rgb * _Sepular.rgb * pow(saturate(dot(reflectDir, viewDir)), _Gloss);
                fixed3 c = ambient + diffuse + sepular;
                return fixed4(c, 1.0); 
            }
            ENDCG
        }
    }
    FallBack "Diffuse"
}
Blinn-Phong 模型

Blinn-Phong 光照模型的高光反射部分看起來更大、更亮一些。

Shader "Custom/Shader6_2_sep_bp"
{
    Properties
    {
        _Diffuse("Diffuse",color)=(1,1,1,1)
        _Specular("Specular",color)=(1,1,1,1)
        _Gloss("Gloss",Range(0,20))=10
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 200

        Pass
        {
            Tags{"LightModel"="ForwardBase"}
            CGPROGRAM
            #pragma vertex vert 
            #pragma fragment frag 
            #include "Lighting.cginc"

            fixed4 _Diffuse;
            fixed4 _Specular;
            float _Gloss;

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

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

            v2f vert(a2v v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.position);
                o.worldNor = mul(v.normal, (fixed3x3)unity_WorldToObject);
                o.worldPos = mul(unity_ObjectToWorld, v.position).xyz;
                return o;
            }

            fixed4 frag(v2f v):SV_Target
            {
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                fixed3 worldNor = normalize(v.worldNor);
                fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
                fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNor, worldLightDir));
                fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - v.worldPos);
                fixed3 h = normalize(viewDir + worldLightDir);
                fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(worldNor, h)), _Gloss);

                return fixed4(ambient + diffuse + specular, 1);
            }

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