(四)Shader中基本光照模型

2022-07-19 19:42:17 字數 4301 閱讀 5948

所謂的光照效果,反映到螢幕上就是乙個個畫素問題,所以光照的計算公式就是計算的乙個乙個顏色值。這些公式基本屬於經驗公式範疇,只是讓人看起來像真正的光效。

光分為環境光、自發光、漫反射以及高光反射,由於反映到畫素上就是顏色的疊加。即最終在片元著色器中返回的顏色值=環境光顏色+自發光顏色+漫反射顏色+高光反射顏色。下面依次對這些光進行說明。

環境光在unity中可以設定,即windows-lighting中即可看到,在2018中則是window-rendering-lightingsettings中設定。在shader中通過如下變數可以獲取到:unity_lightmodel_ambient。但是一般計算中我們只需要顏色的rgb值。

自發光是最簡單的,直接簡單粗暴的暴露乙個顏色值,包此值當作自發光顏色。

漫反射計算參考一下光照模型進行計算。

蘭伯特定律認為反射光線跟光源方向與法線夾角有關係(夾角余弦值),所以漫反射計算公式如下:

漫反射顏色 = 光源顏色 x 材質的漫反射顏色 x max(0,dot(法線,指向光源的方向)

其中:光源顏色:變數_lightcolor0代表光源顏色。

材質漫反射顏色:自定義的顏色值。

法線:可以獲取到每個頂點的法線,計算式採用單位向量。

光源方向:指從當前位置到光源的方向,計算式採用單位向量。

由於實際中當法線與光源方向夾角大於90°時,已經不會有反射效果,此時兩者余弦值為負值,所以此時應該取0。

逐頂點計算漫反射時,在頂點著色器中計算,此時計算量小,但是效果差。在計算世界座標系下的法線時,採用如下所示:

//獲取法線(統一到世界座標系下),不做歸一化效果要優於歸一化。

//fixed3 worldnormal = normalize(mul(v.normal,(float3x3)unity_worldtoobject));

fixed3 worldnormal = unityobjecttoworldnormal(v.normal);

上述注釋掉的方法也是unityobjecttoworldnormal方法,當然unitycg種方法比注釋掉的方法複雜一點。完整**如下:

shader "ll/light/diffusevertex_lambert"

subshader

pass

; struct v2f

;fixed4 _diffuse;

v2f vert (a2v v)

fixed4 frag (v2f i) : sv_target

endcg

} }fallback "diffuse"

}

注:在計算光源方向時,應該是光源方向應該是光源位置減頂點位置,但是在真正計算時考慮不同情況,計算方式不同,unitycg中也存在計算方法,直接用光源位置是一種情況,本文是示例,所以只採用最簡單的方法。

逐片元計算方法與頂點計算方法一致,只是在片元著色器中進行顏色計算,在頂點著色器中將法線傳遞過來即可,如下所示:

shader "ll/light/diffusefragment_lambert"

subshader

pass

; struct v2f

;fixed4 _diffuse;

v2f vert (a2v v)

fixed4 frag (v2f i) : sv_target

endcg

} }fallback "diffuse"

}

半蘭伯特光照其實還是根據蘭伯特定律進行的另外一種光照經驗公式。

漫反射顏色 = 光源顏色 x 材質的漫反射顏色 x( a*dot(法線,指向光源的方向) + b)

其他引數見4.1,a和b為兩個引數值,當其均為0.5時,則相當於將法線和光源方向的點積結果對映到0-1範圍內。

此方法只給出在片元著色器中的計算,跟4.1差別在於計算漫反射顏色方式有差別。

shader "ll/light/diffusefragment_halflambert"

subshader

pass

; struct v2f

;fixed4 _diffuse;

v2f vert (a2v v)

fixed4 frag (v2f i) : sv_target

endcg

} }fallback "diffuse"

}

高光反射本質上還是計算乙個顏色值,其計算公式如下所示:

高光反射顏色 = 入射光顏色 x 高光反射顏色 x max(0,dot(視角方向,反射方向))^反射係數

其中:視角方向可以通過攝像機與當前頂點位置計算,如下所示:

_worldspacecamerapos.xyz - mul(unity_objecttoworld, v.vertex).xyz

反射方向通過入射光方向與法線方向即可計算,如下所示:

fixed3 worldnormal = normalize(mul(v.normal,(float3x3)unity_worldtoobject));

//fixed3 worldnormal = mul(v.normal, (float3x3)unity_worldtoobject);

//fixed3 worldnormal = mul((float3x3)unity_objecttoworld, v.normal);

//獲取環境光方向

fixed3 worldlight = normalize(_worldspacelightpos0.xyz);

fixed3 reflectdir = normalize(reflect(-worldlight,worldnormal));

shader "ll/light/specularvertex"

subshader

pass

; struct v2f

;fixed4 _diffuse;

fixed4 _specular;

float _gloss;

v2f vert (a2v v)

fixed4 frag (v2f i) : sv_target

endcg

} }fallback "specular"

}

shader "ll/light/specularfragment"

subshader

pass

; struct v2f

;fixed4 _diffuse;

fixed4 _specular;

float _gloss;

v2f vert(a2v v)

fixed4 frag(v2f i) : sv_target

endcg

}} fallback "specular"

}

高光反射顏色值還可以採用如下方法計算,其計算公式如下所示:

高光反射顏色 = 入射光顏色 x 高光反射顏色 x max(0,dot(法向量,視角光照向量))^反射係數

其中:視角光照向量是視角方向與光照方向相加歸一後的法向量。

//獲取法線(統一到世界座標系下)

fixed3 worldnormal = normalize(i.normal);

//獲取環境光方向

fixed3 worldlight = normalize(_worldspacelightpos0.xyz);

//獲取視線方向

fixed3 view = normalize(_worldspacecamerapos.xyz - i.worldpos);

fixed halfdir = normalize(worldlight + view);

//計算blinnphong高光反射

fixed3 specular = _lightcolor0.rgb * _specular.rgb * pow(max(0,dot(worldnormal, halfdir)), _gloss);

以上為基本的光照模型,且計算均為單一情況測試,考慮不充分,只是用來學習。

Shader基本光照模型 菲涅爾模型

shader lijia fresneltest fresnelbase fresnelbase range 0 1 1 fresnelscale fresnelscale range 0 1 1 fresnelindensity fresnelindensity range 0 5 5 fresn...

Shader筆記1 基礎光照 光照模型

光照模型 1.定義 光照模型就是乙個公式,使用這個公式來計算在某個點的光照效果 2.標準光照模型 在標準光照模型中,我們把進入攝像機的光分為下面四部分 1 自發光 2 高光反射 specular 平行光 pow max 0,cos 引數x 為平行光的反射光與視野方向的夾角 blinn光照模型和bli...

Shader 基礎光照 漫反射光照模型

漫反射 diffuse 當光線從光源照射到模型表面,該表面回向每個方向散射多少輻射量 漫反射符合蘭伯特定律 反射光線的強度與表面法線與光源方向之間的夾角的余弦值成正比.漫反射的計算 diffuse.png n表面法線和l指向光源的向量的單位向量點乘來表示余弦值,用max防止點乘結果為負數,防止物體被...