Phong光照模型、Blinn-phong光照模型歸納
上次說到Lambert漫反射光照模型,這是一個用來模擬粗糙表面對光線的漫反射現象的經驗模型,對於紙張、粗糙牆壁等等來說,這個模型或許夠用,但對於金屬這樣的光滑表面來說,我們就需要使用Phong模型來模擬光滑表面對光線的鏡面反射現象。同Lambert一樣,這個模型也是經驗模型,而且在程式中,我們經常同時使用Lambert和Phong兩個模型,因為在現實世界中,任何表面都會同時發生漫反射和鏡面反射兩種現象,因此我們就要使用兩種模型分別計算兩種反射後的光強(也就是頂點顏色值),是渲染的效果看起來真實一些。但要注意,這樣做並不會帶來真正真實的渲染效果,畢竟這兩種模型都是經驗模型,考慮的都是理想情況下。而Blinn-phong光照模型是基於Phong的修正模型,因此就一併歸納了。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
接下來讓我們看看Phong模型:
我們知道,在理想狀況下,鏡面反射後的光之集中在一條線上,因此我們的視線離這條線的距離越近,射入我們眼中的光線就越多,我們看到的光強也就越強。同時,鏡面反射也與物體表面的高光指數(物體表面光澤程度)有關,其數值越大,反射後的光線越集中,反之則越分散,這裡可能會有人想:如果將高光指數設定的很大,也就是光線極其分散,Phong是否可以用來代替Lambert?我想答案肯定是不行的,原因是漫反射是將光線反射到各個角度,而鏡面反射即使反射光線再分散,它們依舊被限制在一個90度的區域中,因此與漫反射的效果是不一樣的。
下面給出公式:
I_spec = k_z * I_l(V • R)^n_s
其中:k_z為表面材質的鏡面反射係數,n_s是高光指數,V表示頂點到視點的向量,R表示反射光的單位向量。
但是在實際的程式編寫中,我們一般都會更容易得到入射光線的單位向量L,所以我們最好轉換一下公式。設頂點的單位法向量為N,有公式:
R + L = (2N • L)N (這裡再次提醒一下,L的方向是由頂點指向光源的)
由這個可以推出:
R = (2N • L)N - L
所以模型公式可以變為:
I_spec = k_z * I_l(V • ((2N • L)N - L))^n_s
下面是用Cg語言實現Phong模型的程式碼:
/**************************************************/
/*Phone鏡面光照模型,同時也加入了Lambert漫反射光照模型 */
/**************************************************/
struct vertex_In
{
float4 in_Position : POSITION;
float4 in_Normal : NORMAL;
}
struct vertex_Out
{
float4 out_Position : POSITION;
float4 out_Color : COLOR0;
}
void main_v(vertex_In vertexI,
out vertex_Out vertexO,
uniform float4*4 modelViewProj,
uniform float4*4 worldMatrix,
uniform float4*4 worldMatrix_IT,
uniform float3 globalAmbient,
uniform float3 eyePosition,
uniform float3 lightPosition,
uniform float3 lightColor,
uniform float3 K_d,
uniform float3 K_s,
uniform float N_s
)
{
vertexO.out_Position = mul(modelViewProj , vertexI.in_Position);//計算輸出定點位置
float3 worldPosition = mul(worldMatrix , vertexI.in_Position).xyz;//計算定點世界位置
float3 N = normalize(mul(worldMatrix , vertexI.in_Normal).xyz);//計算定點法線向量
float3 V = normalize(eyePosition - worldPosition);//計算定點到視點的方向
float3 L = normalize(lightPosition - worldPosition);//計算入射光方向
float3 R = normalize(N*max(dot(2*N , L) , 0) - L);//計算反射光方向
float3 diffuseColor = K_d*globalAmbient + K_d*lightColor*max(dot(N , L) , 0);//計算漫反射光強
float3 specularColor = K_s*lightColor*pow(max(dot(V , R) , 0) , N_s);//計算鏡面反射光強
vertexO.out_Color.rgb = diffuseColor + specularColor;
vertexO.out_Color.a = 1;
}
以上程式碼只使用了頂點著色程式,因此只對幾何頂點進行渲染,而不對片段內部的點進行處理,因此如果用來渲染低精度模型效果會很不好,因此我們就要再加入片段著色程式。
程式碼如下:
/**************************************************/
/Phone鏡面光照模型,同時也加入了Lambert漫反射光照模型/
/**************************************************/
struct vertex_In
{
float4 in_Position : POSITION;
float4 in_Normal : NORMAL;
}
struct vertex_Out
{
float4 out_Position : POSITION;
float4 out_objecPos : TEXCOORD0;
float4 out_objectNormal : TEXCOORD1;
}
void main_v(vertex_In vertexI,
vertex_Out vertexO,
uniform float4*4 modelViewProj
)//頂點著色程式入口
{
vertexO.out_Position = mul(modelViewProj , vertexI.in_Position);//計算輸出定點位置
vertexO.out_objectPos = vertexI.in_Position;
vertexO.out_objectNormal = vertexI.in_Normal;
}
void main_f(vertex_Out vertexI,
out float4 colorO : COLOR,
uniform float4*4 worldMatrix,
uniform float4*4 worldMatrix_IT,
uniform float3 globalAmbient,
uniform float3 eyePosition,
uniform float3 lightPosition,
uniform float3 lightColor,
uniform float3 K_d,
uniform float3 K_s,
uniform float N_s
)//片段著色程式入口
{
float3 worldPos = mul(worldMatrix , vertexI.out_objecPos).xyz;//計算定點世界位置
float3 N = normalize(mul(worldMatrix , vertexI.out_objectNormal).xyz);//計算定點法線向量
float3 V = normalize(eyePosition - worldPosition);//計算定點到視點的方向
float3 L = normalize(lightPosition - worldPosition);//計算入射光方向
float3 R = normalize(N*max(dot(2*N , L) , 0) - L);//計算反射光方向
float3 diffuseColor = K_d*globalAmbient + K_d*lightColor*max(dot(N , L) , 0);//計算漫反射光強
float3 specularColor = K_s*lightColor*pow(max(dot(V , R) , 0) , N_s);//計算鏡面反射光強
colorO.rgb = diffuseColor + specularColor;
colorO.a = 1;
}
這樣的話程式就會對片段中的點也進行處理,渲染效果也會好一些。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
接下來歸納一下Blinn-phong光照模型
相比較Phong模型,Blinn-phong模型只適用N•H替換了V•R,但卻獲得了明顯的提高,它能提供比Phong更柔和、更平滑的高光,而且速度上也更快,因此成為很多CG軟體中預設的光照渲染方法,同時也被整合到大多數的圖形晶片中,而且在OpenGL和DirectX 3D的渲染管線中,它也是預設的光照模型。
由於這兩個光照模型公式基本相同,所以只解釋一下N•H:
N與前面相同,是頂點的單位法向量,而H則是入射光L和頂點到視點的單位向量的角平分線單位向量,通常也成為半形向量。其計算方法為:
H = (L + V) / (|L + V|)
書上說半形向量廣泛應用於各類關照模型,其中蘊含了很重要的資訊,至於具體是神馬,還需要去在考證一下。。。
Blinn-phong光照模型的程式碼與Phong幾乎一樣,這裡也就不給出了。
相關文章
- [computer graphics]簡單光照模型(Phong和Blinn-Phong)和明暗處理模型
- Lambert漫反射光照模型歸納反射模型
- 【Filament】自定義Blinn Phong光照模型模型
- 傳統光照模型模型
- WebGL多模型光照綜合例項Web模型
- OpenGL 4.0 GLSL 採用平行光照模型模型
- Unity3D 的物理渲染和光照模型Unity3D模型
- WebGL自學課程(12):光照模型與渲染方式Web模型
- OpenGL高階版本學習日誌2:光照模型&材質模型
- 【SICP歸納】6 副作用與環境模型模型
- 「技美之路 第08篇」圖形 2.4 傳統經驗光照模型詳解模型
- 用歸納偏置來增強你的模型效能模型
- Android OpenGLES2.0(十六)——3D模型貼圖及光照處理(obj+mtl)Android3D模型OBJ
- OpenGL ES on iOS — 光照進階iOS
- OpenGL 基礎光照詳解
- OpenGL ES on iOS --- 光照進階iOS
- WebGL程式設計指南(6)光照Web程式設計
- Lightmass靜態全域性光照
- 實現一個前向渲染的Phong模型(一)模型
- 全景光照在遊戲中的應用遊戲
- 【GLSL教程】(六)逐頂點的光照
- OpenGL學習筆記(12)基本光照筆記
- 【UE4_光照】UE4中光照的常見問題和解決方案(一)使用手冊
- 【UE4_光照】UE4中光照的常見問題和解決方案(二)使用手冊
- Unity的Forward+ FPTL光照剔除解析(一)UnityForward
- Unity的Forward+ FPTL光照剔除解析(三)UnityForward
- Unity的Forward+ FPTL光照剔除解析(四)UnityForward
- 低光照影像區域級質量推斷
- 邏輯迴歸模型邏輯迴歸模型
- 揭祕《Sherman》:使用Unity製作影視級光照效果Unity
- 在Unity中實現2D光照系統Unity
- Unity——基於ShaderLab實現光照系統Unity
- WidsMob HDR Mac(光照渲染效果照片處理器)Mac
- WidsMob HDR Mac 光照渲染效果照片處理器Mac
- Threes.js入門篇之7 - 場景光照JS
- 多元線性迴歸模型模型
- 工具歸納
- 微軟程式歸納新技術:元程式歸納微軟