1. 程式人生 > >基礎光照

基礎光照

一、馮氏光照模型

其主要結構由3個分量組成:環境(ambient)、漫反射(diffuse)、鏡面(specular)光照。下邊這張圖展示了這些分量看起來的樣子:

環境光照:即使在黑暗的環境下,世界上通常也仍然有一些光亮(月亮、遠處的光),所以物體幾乎永遠不是完全黑暗的。為了模擬這種效果,我們會使用一個環境光照常量,它永遠會給物體一些顏色。

漫反射光照:模擬光源對物體的方向性影響。它是馮氏光照模型中最顯著的分量。物體的某一部分越是正對著光源,它就會越亮。

鏡面光照:模擬有光澤物體上面出現的亮點。

二、環境光照

把環境光照新增到場景裡非常簡單,用光的顏色乘以一個很小的常量環境因子,再乘以物體的顏色,然後將最終結果作為片段的顏色。

1 void main(){
2     float ambientStrength = 0.1;//一個很小的常量環境因子
3     vec3 ambient = ambientStrength * lightColor;
4 
5     vec3 result = ambient * lightColor;
6     FragColor = vec4(result,1.0f);      
7 }

執行結果:

立方體非常暗,但是應用了環境光,所以不是全黑。

 

三、漫反射光照

環境光照本身不能提供顯著的結果,漫反射可以對物體產生顯著的視覺效果。漫反射光照使物體上與光線方向越接近的片段能從光源處獲得更多的亮度。

 如果光線垂直於物體表面,那麼這束光會對物體的影響最大化。為了測量光線和片段的角度,我們使用法向量(黃色箭頭)。

注:為了只得到兩個向量夾角的餘弦值,我們使用單位向量,所以我們需要確保點乘的向量都要經過標準化。

計算漫反射光照需要什麼?

1>法向量:一個垂直於頂點表面的向量

2>定向的光線:光源位置與片段位置的向量差。

四、法向量

我們把法向量加入到頂點資料中,更新立方體的頂點著色器

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
out vec3 normal;
void main(){
  gl_Position = projection * view * model * vec4(aPos,1.0f);
  normal = aNormal;
}

五、計算漫反射光照

1、在片段著色器中將光源位置設為uniform

2、我們在世界空間中進行所有的光照計算,因此我們需要一個在世界空間中的頂點位置。我們可以通過把頂點位置屬性乘以模型矩陣(不是觀察和投影矩陣)來把它變換到世界空間座標。在頂點著色器中:

out vec3 FragPos;  
out vec3 Normal;

void main()
{
    gl_Position = projection * view * model * vec4(aPos, 1.0);
    FragPos = vec3(model * vec4(aPos, 1.0));
    Normal = aNormal;
}

3、在片段著色器中新增光照計算

1>計算光照方向

1 vec3 normal = normalize(normal);
2 vec3 lightDir =  normalize(lightPos - FragPos);

計算光照時一定對向量進行單位化,只關心方向

2>計算漫反射分量

我們對normlightDir向量進行點乘,計算光源對當前片段實際的漫發射影響。結果值再乘以光的顏色,得到漫反射分量。兩個向量之間的角度越大,漫反射分量就會越小:

1 float diff = max(dot(norm,lightDir),0);
2 vec3 diffuse = diff * lightColor;

如果兩個向量之間的角度大於90度,點乘的結果就會變成負數,這樣會導致漫反射分量變為負數。為此,我們使用max函式返回兩個引數之間較大的引數,從而保證漫反射分量不會變成負數。因為負數的光照是沒有定義的。

現在我們有了環境光分量和漫反射分量,我們把它們相加,然後把結果乘以物體的顏色,來獲得片段最後的輸出顏色。

1 vec3 result = (ambient + difuse) * objectColor;
2 FragColor = vec4(result,1.0);

六、鏡面光照

也是根據光的方向向量和物體的法向量來決定的,但也依賴於觀察方向

vec3 reflectDir = reflect(-lightDir, norm);

需要注意的是我們對lightDir向量進行了取反。reflect函式要求第一個向量是光源指向片段位置的向量,但是lightDir當前正好相反,是從片段指向光源(由先前我們計算lightDir向量時,減法的順序決定)。為了保證我們得到正確的reflect向量,我們通過對lightDir向量取反來獲得相反的方向。第二個引數要求是一個法向量,所以我們提供的是已標準化的norm向量。

 

我們先計算視線方向與反射方向的點乘(並確保它不是負值),然後取它的32次冪。這個32是高光的反光度(Shininess)。一個物體的反光度越高,反射光的能力越強,散射得越少,高光點就會越小。在下面的圖片裡,你會看到不同反光度的視覺效果影響:

我們不希望鏡面成分過於顯眼,所以我們把指數保持為32。