OpenGL學習腳印:Blinn-Phong光照模型
寫在前面
在前面基礎光照部分,我們學習了Phong Shading模型,Blinn-Phong模型對Phong模型的鏡面光成分進行了改進,雖然在物理上解釋沒有Phong好,但是能更好地模擬光照。本節程式碼可以在我的github下載。
Phong不能處理的情況
我們知道,Phong模型在計算鏡面光係數為:
float specFactor = pow(max(dot(reflectDir, viewDir), 0.0), 32); // 32為鏡面高光係數
這裡的計算由反射向量和觀察向量決定,當兩者的夾角
而右圖的這種情況實際上是存在的,將鏡面光成分取為0,沒有很好地體現實際光照情況。例如下面的圖表示的是,鏡面光係數為1.0,法向量為(0.0,1.0,0.0)的平面位置在-0.5,光源在原點時,觀察者在(0,0,4.0)位置時,光照展示的情形:
這裡我們看到,Phong的鏡面光成分,在邊緣時立馬變暗,這種對比太明顯,不符合實際情形。
為什麼會產生這樣一個光線明暗分明的情形? 我嘗試這樣推導,對此不感興趣地可以跳過。
首先記表面位置為
法向量為:
根據reflect函式的計算原理,得到反射向量為:
設觀察點位置為
那麼反射向量和觀察向量的點積為:
記
令
由此可以看出,位置在平面y=-0.5上的點,以適當位置觀察時,會形成兩個同心圓,在兩個同心圓之間的部分則滿足
也就是說當觀察向量和反射向量超過90度,這種截斷引起了明顯的明暗對比,這種情形在Blinn-Phong中得到改善。
Blinn-Phong
Blinn-Phong模型鏡面光的計算,採用了半形向量(half-angle vector),這個向量是光照向量L和觀察向量V的取中向量,如下圖所示(來自Blinn-Phong Model):
計算為:
當觀察向量與反射向量越接近,那麼半形向量與法向量N越接近,觀察者看到的鏡面光成分越強。
對比Phong和Blinn-Phong計算鏡面光係數為:
vec3 viewDir = normalize(viewPos - fs_in.FragPos);
float specFactor = 0.0;
if(blinn) // 使用Blinn-P