Unity shader 官網文檔全方位學習(二)

摘要: 這篇文章主要介紹Lighting model及自定義Lighting model

上文我們學了surface shader。這玩意在開始的時候啊,在定義哪一個函數處理surface時用必定要指定Lighting model(即光照模型)的。自帶的是Lambert和BlinnPhong.本文首先對這兩個進行說明,後面講解如何自定義光照模型及對官方實例的解析。http://docs.unity3d.com/Documentation/Components/SL-SurfaceShaderLighting.htmlhtml

1、簡單光反射模型swift

1.反射,其實就是光照到物體上,而後再由物體反射出去。這種過程就叫反射。markdown

2.漫反射,物體表面多是不光滑的,所以天然法線就不是均勻的,那麼這種狀況下,當幾條平行光照向物體時,反射回來的光線就再也不是平行的了,這種狀況叫漫反射。app

3.鏡面反射:與漫反射對應,若是物體表面光滑,即法線均勻(不必定都平行,會有曲面的狀況),則反射回來的也是均勻的,這種狀況叫鏡面反射。函數

4.環境光:光線照到指定物體的周圍物體,這時指定物體上有光線反射到,這種光可稱爲環境光或泛光。學習

5.光照 = 反射光 + 鏡面光 + 環境光 + 自發光。ui

對於簡單光反射模型: 入射光 = 反射光 + 吸引光。而實際上來講還須要加上投射光與散射光。spa

2、Lambert和BlinnPhong.net

1.馮式反射模型:Phong reflection 是一種將漫反射與鏡面反射進行關聯在一些的反射方法。3d

2.Lambert:一種主要應用於漫反射的光照模型。

3.BlinnPhong: 一種主要應用於鏡面反射的光照模型。

3、自定義光照模型

1.規則:定義一個函數,必須以 Lighting開頭,能夠寫在shader文件裏的任意位置或其餘include的文件。
=>half4 LightingName (SurfaceOutput s, half3 lightDir, half atten);  這種是無viewDir,在上文中有說到viewDir就是返回給視角的方向,不用依賴此值,就相似於漫反射的效果。由於漫反射中出來的光線是由不規則的表面來決定。

=>half4 LightingName (SurfaceOutput s, half3 lightDir, half3 viewDir, half atten); 這個方法是相對於上面的,須要依賴於viewDir。

=>half4 LightingName_PrePass (SurfaceOutput s, half4 light); 這個方法是可選的,若是須要光照延時(deferred),就加上此方法,不寫則所有采用快速光照(forward)。

2.自定義解碼光照

注意,若是使用了LightingName_PrePass,則光照解碼的方法在此方法以前,所以是有了光照延時。具體會針對與SingleLightMapping、DualLightMapping和StandardLightMapping三種的方法,與LightMapping的定義函數相似,具體的這裏不介紹,可參考官方文檔:http://docs.unity3d.com/Documentation/Components/SL-SurfaceShaderLighting.html

3、實例學習

1.自定義一個簡單的漫反射光照模型:

#pragma surface surf SimpleLambert //1 half4 LightingSimpleLambert (SurfaceOutput s, half3 lightDir, half atten) { //2 half NdotL = dot (s.Normal, lightDir); //3 half4 c; //4 c.rgb = s.Albedo * _LightColor0.rgb * (NdotL * atten * 2); //5 c.a = s.Alpha; //6 return c; //7 }

 

 

//1: 定義使用SimpleLambert作爲光照模型

//2: 光照模型的定義。這裏說說atten,根據atten的意思(衰減器),能夠理解到,這個參數就是光照的衰減值。

//3:算一點積,光照方向與法線的點積,可理解爲光照與法線的夾角。

//4:定義輸出的顏色四元組。

//5:光照的顏色 = 物體反射顏色 * 原光的顏色* 通過折射的衰減顏色。_LightColor0是在Lighting.cginc 裏定義的,我理解成反射光的顏色。另外還有一個_SpecColor,對應是鏡面反射光的顏色。此處因爲資料稀缺,所有我的的學習所得,若有錯誤,歡迎指出!

//6:設置光的透明與反射透明一致。

//7:返回。

效果:

2.Diffuse wrap

#pragma surface surf WrapLambert half4 LightingWrapLambert (SurfaceOutput s, half3 lightDir, half atten) { half NdotL = dot (s.Normal, lightDir); half diff = NdotL * 0.5 + 0.5; //! half4 c; c.rgb = s.Albedo * _LightColor0.rgb * (diff * atten * 2); c.a = s.Alpha; return c; }

 

 

此1不一樣的只是//! 處,這裏算得一個diff,目的是將原得出的點積單位從[-1,1]轉換成[0,1]之間。  
這樣作的用法,在各方問人,加上本身思想,想到的是將全部的座標轉成正值,這樣,在其接受到光源反射的全部地方都會有光,這樣使得光照的範圍擴大了很多。

3.Toon Ramp

#pragma surface surf Ramp sampler2D _Ramp; half4 LightingRamp (SurfaceOutput s, half3 lightDir, half atten) { half NdotL = dot (s.Normal, lightDir); half diff = NdotL * 0.5 + 0.5; half3 ramp = tex2D (_Ramp, float2(diff)).rgb; //1 half4 c; c.rgb = s.Albedo * _LightColor0.rgb * ramp * (atten * 2); c.a = s.Alpha; return c; }

 

 

這裏對比於2,把原本是固定的diff,再加上一個材質。

//1中,直接將diff強轉成float2的座標系,向_Ramp的材質中查找出相應的rgb。最終也以此rgb值及其餘光照值得出光照的rgb值。這種效果能夠考慮來作光暈。這裏我用一張具體的圖,以float2(diff)爲uv找的效果會有點奇怪。不過現象能夠反映出來。

效果:

4.Simple Specular

#pragma surface surf SimpleSpecular half4 LightingSimpleSpecular (SurfaceOutput s, half3 lightDir, half3 viewDir, half atten) { half3 h = normalize (lightDir + viewDir); half diff = max (0, dot (s.Normal, lightDir)); float nh = max (0, dot (s.Normal, h)); float spec = pow (nh, 48.0); half4 c; c.rgb = (s.Albedo * _LightColor0.rgb * diff + _LightColor0.rgb * spec) * (atten * 2); c.a = s.Alpha; return c; }

 

轉載:http://www.javashuo.com/article/p-wrfkvcrj-ds.html 

這個例子是自定義一個鏡面反射的例子。c.rgb 的組成可拆成一個漫反射和一個鏡面反射的組合。
c.rgb = (s.Albedo * _LightColor0.rgb * diff * (atten * 2)) + (_LightColor0.rgb * spec * (atten * 2));

 

 

前半段就是漫反射,不講了。後面半段區別用到了鏡面反射值。而這個值來自於:
float nh = max (0, dot (s.Normal, normalize (lightDir + viewDir)));

 

 

首先,光的方向和視角方向都是決定鏡面反射的重要因素,不能沒lightDir,不然鏡面反射則只跟視角來了,那樣是不現實的。所以此處須要讓兩個方向的向量之和與表面法線進行點積。這個nh範圍是在大於0的。因爲兩個單位向量點積,所以得出的值則是 0到1之間。

後面取pow是爲了放小nh的值,其值越小,則鏡面反射就越小。

上效果:

相關文章
相關標籤/搜索