Unity Shader的學習筆記
第八天 開始Unity Shader的學習之Blinn-Phong光照模型
文章目錄
- Unity Shader的學習筆記
- 前言
- 一、Blinn-Phong光照模型
- ①計算高光反射部分
- 效果展示
- 二、召喚神龍:使用Unity內置的函數
- 總結
前言
今天我們編寫另一種高光反射的實現方法 – Blinn光照模型.同時了解一些Unity的內置函數.
提示:以下是本篇文章正文內容,下面案例可供參考
一、Blinn-Phong光照模型
Blinn模型沒有使用反射方向,而是引入了新的矢量h,它是通過對視角方向v和光照方向l相加后在歸一化得到的.公式如下:
Blinn模型計算高光反射的公式如下:
代碼如下:
Shader "Unity Shaders Book/Chapter 6/Blinn Phong"{Properties{_Diffuse ("Diffuse", Color) = (1, 1, 1, 1)_Specular ("Specular", Color) = (1, 1, 1, 1)//_Gloss用于控制高光反射屬性_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;float3 worldNormal : TEXCOORD0;float3 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).xyz;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 = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightDir));①fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);fixed3 halfDir = normalize(viewDir + worldLightDir);fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(i.worldNormal, halfDir)), _Gloss);return fixed4(ambient + diffuse + specular, 1.0);}ENDCG}}Fallback "Specular"
}
①計算高光反射部分
首先我們還是計算出視角方向,然后再對視角方向和光照方向相加之后再歸一化得到的,最后再計算高光部分即可.
效果展示
可以從效果圖看出來,Blinn-Phong光照模型的高光反射部分看起來更大,更亮一點,在實際渲染中,絕大多數我們都會選擇Blinn-Phong光照模型,但是這兩種光照模型都是經驗模型,換句話說,我們不應該認為Bliin_phong模型是對"正確的"Phong模型的近似,實際上,Blinn-Phong模型更符合實驗結果.
二、召喚神龍:使用Unity內置的函數
我們在之前的Shader代碼中,很多東西都是我們手動計算的,例如視角方向,光源方向等(雖然我們使用的_WorldSpaceLightPos0.xyz得到的光源方向只適合平行光,如果有更復雜的光源信息,這種方法就是錯誤的了),但是手動計算的過程比較麻煩,Unity提供一些內置函數來幫助我們計算這些信息.
函數名 | 描述 |
---|---|
float3 WorldSpaceViewDir(float4 v) | 輸入一個模型空間中的頂點位置,返回世界空間中從該點到攝像機的觀察方向,內部實現使用了UnityWorldSpaceViewDir函數 |
float3 UnityWorldSpaceViewDir(float4 v) | 輸入一個世界空間中的頂點位置,返回世界空間中從該點到攝像機的觀察方向 |
float3 ObjectSpaceViewDir(float4 v) | 輸入一個模型空間中的頂點位置,返回模型空間中從該點到攝像機的觀察方向 |
float3 WorldSpaceLightDir (float4 v) | 僅可用于前向渲染中,輸入一個模型空間中的頂點位置,返回世界空間中從該點到光源的光照方向,內部使用了UnityWorldSpaceLightDir 函數,沒有被歸一化 |
UnityWorldSpaceLightDir (float4 v) | 僅可用于前向渲染中,輸入一個世界空間中的頂點位置,返回世界空間中從該點到光源的光照方向,沒有被歸一化 |
float3 ObjSpaceLightDir(float4 v) | 僅可用于前向渲染中,輸入一個模型空間中的頂點位置,返回模型空間中從該點到光源的光照方向,沒有被歸一化 |
float3 UnityObjectToWorldNormal(float3 norm) | 把法線方向從模型空間轉換到世界空間中 |
float3 UnityObjectToWorldDir(float3 dir) | 把方向矢量從模型空間變換到世界空間中 |
float3 UnityWorldToObjectDir(float3 dir) | 把方向矢量從世界空間變換到模型空間中 |
類似于UnityXXXX的幾個函數都是Unity5中新添加的內置函數,這些幫助函數使得我們不需要跟各種變換矩陣,內置變量打交道,也不需要考慮使用了哪種光源這種問題,而僅僅調用一個函數就可以得到需要的信息.
上面的9個幫助函數中,我們已經掌握了五個器內部實現,都在我們之前的代碼中找到,但是需要注意的是,這些函數沒有保證得到的方向矢量都是單位矢量,因此我們使用之前都需要將他們歸一化.
總結
今天的內容就這么多,我們也可以進行一些嘗試,將之前的計算使用這些函數代替一下.