1. 程式人生 > 其它 >【UnityShader】高光反射光照模型

【UnityShader】高光反射光照模型

先給出基本光照模型中高光反射部分的計算公式:

其中要知道高光反射係數m,視角方向v和反射方向。

反射方向可以由表面法線和光線方向計算 r = l-2(n·l)n ,CG中也提供了reflect函式來操作。

這裡給出逐頂點計算的程式碼:

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'

Shader "Custom/Chapter6-SpecularVertexLevel"
{
    Properties{
        _Diffuse(
"Diffuse",Color) = (1,1,1,1) _Specular("Specular",Color)=(1,1,1,1) //高光顏色 _Gloss("Gloss",Range(8.0,256)) = 20//高光區域大小 } SubShader{ Pass{ Tags{"LightMode" = "ForwardBase"} CGPROGRAM #pragma vertex vert #pragma fragment frag #include
"Lighting.cginc" fixed4 _Diffuse; fixed4 _Specular; float _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.xyz; //將法線由模型空間轉化到世界座標 fixed3 worldNormal =normalize( mul(v.normal,(float3x3)unity_WorldToObject)); //得到光源方向 fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz); //計算漫反射 fixed3 diffuse = _Diffuse.rgb*_LightColor0*saturate(dot(worldNormal,worldLightDir)); //_LightColor0為內建變數 :表示光色及強度 //計算反射方向 fixed3 reflectDir = normalize(reflect(-worldLightDir,worldNormal)); //計算視角方向 fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz-mul(unity_ObjectToWorld,v.vertex).xyz); //計算高光反射 fixed3 specular = _LightColor0*_Specular.rgb*pow(saturate(dot(reflectDir,viewDir)),_Gloss); o.color = ambient+diffuse+specular; return o; } fixed4 frag(v2f i):SV_Target{ return fixed4(i.color,1.0); } ENDCG } } FallBack "Specular" }

此外,還有一種Blinn-Phong光照模型:

Blinn模型引入了一個新的向量h來替換phomh中的r。

其中h的計算公式如下:

給出程式如下:

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'

Shader "Custom/Chapter6-SpecularVertexLevel"
{
    Properties{
        _Diffuse("Diffuse",Color) = (1,1,1,1)
        _Specular("Specular",Color)=(1,1,1,1) //高光顏色
        _Gloss("Gloss",Range(8.0,256)) = 20//高光區域大小
    }
    SubShader{
        Pass{
            Tags{"LightMode" = "ForwardBase"}
            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag

            #include "Lighting.cginc"

            fixed4 _Diffuse;
            fixed4 _Specular;
            float _Gloss;

            struct a2v{
                float4 vertex:POSITION;//頂點資訊
                float3 normal:NORMAL;
            };
            struct v2f{
                float4 pos:SV_POSITION;//裁剪空間資訊
                fixed3 worldNormal:TEXCOORD0;
                fixed3 worldPos:TEXCOORD1;
            };

            v2f vert(a2v v){
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);//將模型空間座標轉化為裁剪空間
                o.worldNormal = mul(v.normal,(float3x3)unity_WorldToObject);
                //o.worldNormal = UnityObjectToWorldNormal(v.normal);
                o.worldPos = mul(unity_ObjectToWorld,v.vertex);
                return o;
            }

            fixed4 frag(v2f i):SV_Target{
                 //獲得環境光
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                fixed3 worldNormal = normalize(i.worldNormal);

                fixed3 worldLightDir = normalize(_WorldSpaceLightPos0).xyz;
                //fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));

                fixed3 diffuse = _Diffuse.rgb*_LightColor0*saturate(dot(worldNormal,worldLightDir));  //_LightColor0為內建變數 :表示光色及強度
                //計算反射方向
                fixed3 reflectDir = normalize(reflect(-worldLightDir,worldNormal));
                //計算視角方向
                fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz-i.worldPos.xyz);
                //fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
                //計算B-P模型新向量
                fixed3 halfDir = normalize(worldLightDir+viewDir);
                //計算高光反射
                fixed3 specular = _LightColor0*_Specular.rgb*pow(max(0,dot(reflectDir,halfDir)),_Gloss);
              
                return fixed4(ambient+diffuse+specular,1.0);
            }
            ENDCG
        }
    }
    
    FallBack "Specular"
}

一般來說B-P模型高光反射部分更大更亮,而在實際渲染中我們也常選擇這個模型。但是注意的是,此為經驗模型。

從左到右依次是B-P模型,逐畫素,逐頂點的渲染情況。

= (·)