Shader(三)基本光照
在現實中最重要的信息載體便是光,如果沒有光人類會損失90%以上的信息來源,也不可能有現代的社會。那不論在科學還是在繪畫與渲染中,光的一直是人類追尋的東西。
今天我們來講下三維世界中最基本的光照。
效果
源代碼
Shader "QQ/Lambert"n{ntPropertiesnt{ntt_LightColor("Light Color",color) = (1,1,1,1)ntt_LightProperty("xyz:Light Position w:intentsity",vector) = (0,1,0,1)ntt_MainTex ("Texture", 2D) = "white" {}nt}ntSubShadernt{nttTags { "RenderType"="Opaque" }nttLOD 100nnttPassntt{ntttCGPROGRAMnttt#pragma vertex vertnttt#pragma fragment fragnttt#include "UnityCG.cginc"nntttstruct a2vnttt{nttttfloat4 vertex : POSITION;nttttfloat2 uv : TEXCOORD0;nttttfloat3 normal :NORMAL;nttt};nntttstruct v2fnttt{nttttfloat4 pos : SV_POSITION;nttttfloat2 uv : TEXCOORD0;nttttfloat3 wPos : TEXCOORD1;nttttfloat3 normal : TEXCOORD2;nttt};nntttsampler2D _MainTex;ntttfloat4 _MainTex_ST;nntttfixed4 _LightColor;ntttfloat4 _LightProperty;ntttv2f vert (a2v v)nttt{nttttv2f o;ntttto.pos = mul(UNITY_MATRIX_MVP, v.vertex);ntttto.uv = TRANSFORM_TEX(v.uv, _MainTex);ntttto.wPos = mul(unity_ObjectToWorld,v.vertex);ntttto.normal = UnityObjectToWorldNormal(v.normal);nttttreturn o;nttt}nntttfixed4 frag (v2f i) : SV_Targetnttt{nttttfloat3 lightDir = normalize(_LightProperty.xyz - i.wPos);nttttfloat atten = dot(lightDir,i.normal);nttttatten = atten * _LightProperty.w;nttttfixed4 tex = tex2D(_MainTex, i.uv);nttttfixed4 col = tex * _LightColor * atten;nttttreturn col;nttt}ntttENDCGntt}nt}n}n
代碼解讀
在這裡呢,我們定義了兩個參數。
第一個是顏色,很明顯是燈光的顏色。
第二個是燈光的屬性,xyz分別代表燈光的位置,w則是燈光的強度。
btw:任何引擎中的燈光參數都是通過類似這種方式傳遞的,唯一的區別是咱們是手動輸入,引擎中是腳本傳遞參數。
因為寫光照,我們需要模型的法線信息,這裡定義我們需要取的數據 即:模型的頂點法線(並不是貼圖法線)。
同樣的,再頂點處理後的返回結構體中,我們也要定義法線變數。
同時還要定義一個該位置的世界坐標信息,即:wPos(worldPosition)
btw:如果我們所有的光照信息在頂點函數中處理,叫做逐頂點光照,如果留到片元函數中處理,叫逐像素光照。逐頂點光照是效率高,效果差。現在幾乎不用了。逐像素光照反之。
在頂點函數中,我們需要處理片元中需要的信息。
這裡面,o.wPos = mul(unity_ObjectToWorld,v.vertex);
unity_ObjectToWorld是一個矩陣。
這裡是指從模型坐標到世界坐標的變換矩陣。因為v.vertex為模型空間的頂點位置。
而這個矩陣同樣是有unity傳遞的。
btw:矩陣的乘法是不滿足交換律的,左乘和右乘是有區別的。
同樣是將,模型空間的法線轉換到世界空間。
而UnityObjectToWorldNromal為UnityCG.cginc中定義的方法。
打開UnityCG.cginc就能看到他的實現內容為:
inline float3 UnityObjectToWorldNormal( in float3 norm )n{nt// Multiply by transposed inverse matrix, actually using transpose() generates badly optimized codentreturn normalize(unity_WorldToObject[0].xyz * norm.x + unity_WorldToObject[1].xyz * norm.y + unity_WorldToObject[2].xyz * norm.z);n}n
官方為什麼要這麼寫呢?
1,unity_WorldToObject是個4x4的矩陣,而norm是個三維向量。
2,這裡使用了右乘。即:a*T(猜猜這裡,為什麼要右乘呢)
其中normalize為cg語言的內置函數,即將向量歸一化。
在片元函數中,我們首先就算出燈光的入射方向。
這裡就需要我們之前求出的世界位置。
燈光的入射方向即為:歸一化(燈光坐標 - 該像素世界坐標)
而我們要求的燈光的強度,即為燈光的入射方向與法線方向的夾角大小。
dot是點乘的意思,即對兩個向量進行點乘求值。
數學定義為: a·b=|a||b|cos∠θ 高三教過的。
得出的結果就是重合為1,正交為0,相反為-1。
最後我們得出的點乘值與強度係數 _LightProperty.w 相乘 即為最後的燈光強度。
然後用該強度乘以燈光顏色再乘以貼圖顏色,就會表現出貼近顯示的光照效果。
這裡我們的shader名為 lambert。
那為什麼叫lambert?
以及最後我們的模型還缺少那些信息才算比較完整且貼近現實呢?
那在實現標題效果的過程中,你有沒有發現我們現在代碼中的一個bug呢?
這裡是點光源,如果是平行光該如何處理呢?
你能猜出來嗎?下篇我們將補充缺少的一部分。
結合這一篇內容,你能寫出分階的卡通光照效果嗎?
下面為上篇文章最後的的答案
Shader "QQ/Blend"n{ntPropertiesnt{ntt_MainTex ("Texture", 2D) = "white" {}ntt_SecondTex("Texture", 2D) = "white" {}ntt_BlendTex("Blend",2D) = "white" {}nt}ntSubShadernt{nttTags { "RenderType"="Opaque" }nttLOD 100nnttPassntt{ntttCGPROGRAMnttt#pragma vertex vertnttt#pragma fragment fragnttt#pragma multi_compile_fognttt#include "UnityCG.cginc"nntttstruct a2vnttt{nttttfloat4 vertex : POSITION;nttttfloat2 uv : TEXCOORD0;nttt};nntttstruct v2fnttt{nttttfloat4 pos : SV_POSITION;nttttfloat2 uv[3] : TEXCOORD0;nttt};nntttsampler2D _MainTex;ntttfloat4 _MainTex_ST;ntttsampler2D _SecondTex;ntttfloat4 _SecondTex_ST;ntttsampler2D _BlendTex;ntttfloat4 _BlendTex_ST;nntttv2f vert (a2v v)nttt{nttttv2f o;ntttto.pos = mul(UNITY_MATRIX_MVP, v.vertex);ntttto.uv[0] = TRANSFORM_TEX(v.uv, _MainTex);ntttto.uv[1] = TRANSFORM_TEX(v.uv, _SecondTex);ntttto.uv[2] = TRANSFORM_TEX(v.uv, _BlendTex);nttttreturn o;nttt}nntttfixed4 frag (v2f i) : SV_Targetnttt{nttttfixed4 tex0 = tex2D(_MainTex, i.uv[0]);nttttfixed4 tex1 = tex2D(_SecondTex, i.uv[1]);nttttfixed4 blend = tex2D(_BlendTex, i.uv[2]);nttttfixed4 col = lerp(tex0,tex1, blend.a);nttttreturn col;nttt}ntttENDCGntt}nt}n}n
在這裡,我們選用了第三張貼圖。並用第三張貼圖的,alpha通道來融合另外兩張貼圖,當然我們還可以用rgb通道,或者用上面兩張貼圖的alpha通道等等。
那上篇地形材質的shader編寫你會了嗎?
推薦閱讀: