在講Unity光照模型之前,先介紹圖形學(xué)中的兩個(gè)基礎(chǔ)光照模型原理,將會(huì)更利于我們理解和使用Unity中的光照模型。
物體表面的光照顏色由入射光。物體材質(zhì),以及材質(zhì)和光的交互規(guī)律共同決定的。
1、圖形學(xué)中的兩個(gè)基礎(chǔ)光照模型
(1)漫反射與Lambert光照模型
粗糙的物體表面向各個(gè)方向等強(qiáng)度地反射光,這種等同度地散射現(xiàn)象稱為光的漫反射(Diffuse Reflection)。產(chǎn)生光的漫反射現(xiàn)象的物體表面稱為理想漫反射體,也稱為L(zhǎng)ambert反射體。
對(duì)于暴露在環(huán)境光下的Lambert反射體,可以用以下公式表示某點(diǎn)處的漫發(fā)射光強(qiáng):
Iad= K*Ia
(約定:小寫的字母表示下標(biāo),ad = ambient diffuse)
其中Ia表示環(huán)境光強(qiáng)度,k(0<k<1)為材質(zhì)對(duì)環(huán)境光的反射系數(shù),Iad是漫發(fā)射體與環(huán)境光交互時(shí)反射的光強(qiáng)。
理想的環(huán)境光是無序的,但是表面光強(qiáng)還依賴于光線的入射方向,這種現(xiàn)象可以用Lambert定律進(jìn)行數(shù)學(xué)上的量化。
Lambert定律:當(dāng)方向光照射到理想反射體上時(shí),漫反射光的光強(qiáng)與入射光方向和入射點(diǎn)便面法向量夾角的余弦成正比。
Ild = K*Il*Cosa
Iid是漫反射體與方向光交互反射的光強(qiáng),Il是方向光的光源強(qiáng)度,a是入射光線與定點(diǎn)法向量的夾角,k是材質(zhì)的反射系數(shù)。
當(dāng)入射角為零時(shí),說明光線垂直于物體表面,漫反射光強(qiáng)最大;九十度時(shí)光線與物體表面平行,物體接收不到任何光線。
若N表示頂點(diǎn)單位法向量,L表示從頂點(diǎn)指向光源位置的單位向量(主意指向,不要弄反了),那么Cosa等價(jià)于N與L的點(diǎn)積。
即:
Ild = k*I*(N·L)
那么綜合考慮環(huán)境光和方向光,Lambert光照模型可寫為:
Idiff = Iad + Ild = k*Ia + k*Il*(N·L)
(****2****)鏡面反射與****Phong****光照模型
Lambert模型較好的表現(xiàn)了粗糙表面的光照現(xiàn)象,如墻壁,紙張等,但是在用于諸如金屬等有光澤效果的材質(zhì)上則會(huì)顯得呆板,表現(xiàn)不出光澤,主要原因是Lambert光照模型沒有考慮表現(xiàn)這些表面的鏡面反射效果。
一個(gè)光滑物體被光照射時(shí),可以早某個(gè)方向上看到很強(qiáng)的反射光,這是因?yàn)樵诮咏R面反射角的一個(gè)區(qū)域內(nèi),反射了入射光的全部或大部分光強(qiáng),這種現(xiàn)象稱為鏡面發(fā)射。
故此,Phong Bui Tuong提出一個(gè)計(jì)算鏡面反射光強(qiáng)的光照模型,稱為Phong模型,認(rèn)為鏡面反射的光強(qiáng)與反射光線和視線的夾角相關(guān)。
Phong模型數(shù)學(xué)表達(dá)式:
Ispec = Ks*Il*(V·R)^n
注:((V·R)^n表示(V·R)的n次方即(V·R)^n 。
Ks表示材質(zhì)的鏡面反射系數(shù),n指高光指數(shù),V表示從頂點(diǎn)到視點(diǎn)觀察方向,R表示反射光方向。
高光指數(shù)n反映了物體表面的光澤程度。n越大,反射越集中,當(dāng)偏離發(fā)射方向時(shí),光線衰減的越厲害,只有當(dāng)視線方向與反射光線非常接近時(shí),才能看到鏡面反射的高光現(xiàn)象。此時(shí),鏡面反射光將會(huì)在反射方向附近形成亮且小的光斑。n越小,表示物體表面越粗糙,反射光越分散,觀察到的光斑區(qū)域越小,強(qiáng)度弱。
反射光方向向量R可以通過入射方向L(從頂點(diǎn)指向光源)和物體表面法向量L求出。
R+L = (2N·L)N
下面是一段Phong模型的cg代碼:
void main_f( VertexScreen posIn,
out float4 color : COLOR,
uniform float4x4 worldMatrix,
uniform float4x4 worldMatrix_IT,
uniform float3 globalAmbient,
uniform float3 eyePosition,
uniform float3 lightPosition,
uniform float3 lightColor,
uniform float3 Kd,
uniform float3 Ks,
uniform float shininess)
{
float3 worldPos = mul(worldMatrix, posIn.objectPos).xyz;
float3 N = mul(worldMatrix_IT, posIn.objectNormal).xyz;
N = normalize(N);
//計(jì)算入射光方向、視線方向、反射光線方向
float3 L = normalize(lightPosition - worldPos);
float3 V = normalize(eyePosition - worldPos);
float3 R = 2*max(dot(N, L), 0)*N-L;
R = normalize(R);
// 計(jì)算漫反射分量
float3 diffuseColor = Kd * globalAmbient +Kd*lightColor*max(dot(N, L), 0);
//計(jì)算鏡面反射分量
float3 specularColor = Ks * lightColor*pow(max(dot(V, R), 0), shininess);
color.xyz = diffuseColor + specularColor;
color.w = 1;
}
(3)BlinnPhong光照模型
BlinnPhong光照模型混合和了Lambert的漫反射和標(biāo)準(zhǔn)的高光,渲染小股票有時(shí)比Phong高光更柔和、更平滑,此外它的處理速度相當(dāng)快,因此成為許多CG軟件中默認(rèn)的光照渲染方法。
在Phong模型中,必須計(jì)算V·R的值,其中R為反射光線的單位向量,V為視線方向的單位向量,但是在BlinnPhong模型中,用N·H的值來取代V·R。
BlinnPhong光照模型公式:
Ibp = Ks*Il(N·H)^n
其中N是入射點(diǎn)的單位法向量,H是“光入射方向L和視點(diǎn)方向V的中間向量”,通常也稱為半角向量。
注:半角向量被廣泛運(yùn)用于各類光照模型,因?yàn)槠浼群懈鞣N信息價(jià)值(光線入射方向以及視點(diǎn)方向),而且計(jì)算快速方便。
H = (L+V)/(|L+V|)
同樣還有Cook-Torrence、BRDF等高級(jí)光照模型,可以自己去查資料拓展。
2、Unity中自定義光照模型
(1)、光照模型聲明
光照模型函數(shù)的聲明一般以“Lighting”開頭的幾個(gè)模板,可以被定義在你的Shader里的任何位置。
1、half4 Lighting<name> (SurfaceOutput s,half3 lightDir,half atten);
這個(gè)函數(shù)模板一般用于正向渲染路徑(forward rendering path),并且是視線方向無關(guān)的。
2、half4 Lighting<name>(SurfaceOutput s,half3 lightDir,half3 viewDir,half atten);
一般用于forward rendering path,并且是視線方向相關(guān)的。
3、half4 Lighting<name>_OrePass(SurfaceOutput s,half4 light);
用于deferred lighting path。
你不需要聲明所有的函數(shù),一個(gè)光照模型是否使用view direction。如果一個(gè)光照模型不在deferred lighting起作用,你就不需要聲明_PrePass函數(shù),并且所有的Shader都會(huì)被編譯成forward rendering path。
(2)、解碼光照貼圖
對(duì)于forward 和 deferred 光照,解碼光照貼圖可以被定制為何光照函數(shù)相似的方式。使用下面的函數(shù)取決于你是否使用了視線方向相關(guān)的光照模型。
解碼基礎(chǔ)的Unity光照貼圖數(shù)據(jù)(通過color,totalcolor,indirectOnlyColor和scale參數(shù))使用內(nèi)置的DecodeLightmap函數(shù)。
定制的光照貼圖解碼函數(shù)會(huì)自動(dòng)處理forward和deferred渲染路徑。但是在deferred case Lighting<name> _PrePass函數(shù)將會(huì)在光照貼圖解碼之后被調(diào)用,并且光照參數(shù)將會(huì)包含實(shí)時(shí)光照和光照貼圖。
如果需要的需要的話你可以用Unity內(nèi)置的宏UNITY_PASS_PREPASSFINAL來區(qū)分forward和deferred渲染路徑。
對(duì)于解碼單個(gè)光照貼圖的自定義函數(shù):
1、half4 Lighting<Name> _SingleLingtingMap(SurfaceOutput s,fixed4 color);
用于不依賴視線方向的光照模型。
2、half4 Lighting<Name>(SurfaceOutput s,fixed4 color,half3 vieDir);
用于依賴視線方向的光照模型。
對(duì)于解碼雙光照貼圖的自定義函數(shù):
1、half4 Lighting<Name> _DualLightMap(SurfaceOurput s,fixed4 totalColor,fixed4 indirectionOnlyColor,half indirectFade);
用于不依賴視線方向的光照模型。
2、half4 Lighting<Name> _DualLightMap(SurfaceOurput s,fixed4 totalColor,fixed4 indirectionOnlyColor,half indirectFade,half3 viewDir);
用于依賴視線方向的光照模型。
對(duì)于解碼定向光照貼圖的自定義函數(shù):
1、half4 Lighting<Name> _DirLightMap(SurfaceOutput s,fixed4 color,fixed4 scale,bool surfFuncWritesNormal);
用于不依賴視線方向的光照模型。
2、half Lighting<Name> _DirLightMap(SurfaceOutput s,fixed4 color,fixed4 scale,half3 viewDir,bool suefFuncWritesNormal,out half3 specColor);
用于依賴視線方向的光照函數(shù)。