from:
引言
在opengl中有三種型別的光:方向光(directional)、點光(point)、聚光(spotlight)。本教程將從方向光講起,首先我們將使用glsl來模仿opengl中的光。
我們將向shader中逐漸新增環境光、散射光和高光效果。
後面的教程中我們將使用逐畫素光照以獲得更好的效果。
接下來我們將實現逐畫素的點光和聚光。這些內容與方向光很相近,大部分**都是通用的。
在**著色的教程中我們接觸過在glsl中如何訪問opengl狀態中關於光源的部分,這些資料描述了每個光源的引數。
[cpp]view plain
copy
struct
gl_lightsourceparameters
; uniform gl_lightsourceparameters gl_lightsource[gl_maxlights];
struct
gl_lightmodelparameters
; uniform gl_lightmodelparameters gl_lightmodel;
在glsl中也同樣可以訪問材質引數:
[cpp]view plain
copy
struct
gl_materialparameters
; uniform gl_materialparameters gl_frontmaterial;
uniform gl_materialparameters gl_backmaterial;
在opengl程式中,這些引數中的大部分,不論屬於光源還是材質,用起來都是相似的。我們將使用這些引數實現自己的方向光。
方向光i
本節的公式來自《opengl程式設計指南》中「和光照有關的數學知識」這一章。
我們從散射光開始討論。在opengl中假定,不管觀察者的角度如何,得到的散射光強度總是相同的。散射光的強度與光源中散射光成分以及材質中散射光反射係數相關,此外也和入射光角度與物體表面法線的夾角相關。
opengl用下面的公式計算散射光成分:
i是反射光的強度,ld是光源的散射成分(gl_lightsource[0].diffuse),md是材質的散射係數(gl_frontmaterial.diffuse)。
這個公式就是lambert漫反射模型。lambert余弦定律描述了平面散射光的亮度,正比於平面法線與入射光線夾角的余弦,這一理論提出已經超過200年了。
在頂點shader中要實現這個公式,需要用到光源引數中的方向、散射成分強度,還要用到材質中的散射成分值。因此使用此shader時,在opengl中需要像在平時一樣設定好光源。注意:由於沒有使用固定功能流水線,所以不需要對光源呼叫glenable。
要計算余弦值,首先要確保光線方向向量(gl_lightsource[0].position)與法線向量都是歸一化的,然後就可以使用點積得到余弦值。注意:對方向光,opengl中儲存的方向是從頂點指向光源,與上面圖中畫的相反。
opengl將光源的方向儲存在視點空間座標系內,因此我們需要把法線也變換到視點空間。完成這個變換可以用預先定義的一致變數gl_normalmatrix。這個矩陣是模型檢視變換矩陣的左上3×3子矩陣的逆矩陣的轉置。
以下就是上述內容的頂點shader**:
[cpp]view plain
copy
void
main()
在片斷shader中要做的就是使用易變變數gl_color設定顏色。
[cpp]view plain
copy
void
main()
下圖顯示了應用此shader的茶壺效果。注意茶壺的底部非常黑,這是因為還沒有使用環境光的緣故。
加入環境光非常容易,只需要使用乙個全域性的環境光引數以及光源的環境光引數即可,公式如下所示:
前面的頂點shader中需要加入幾條語句完成環境光的計算:
[cpp]view plain
copy
void
main()
下圖顯示了最終效果。加入環境光後整個畫面都變亮了,不過相對於應用了反射光效果的全域性光照模型(global illumination model),這種計算環境光的方式只能算廉價的解決方案。
方向光ii
下面介紹opengl方向光中的鏡面反射部分。我們使用稱為blin-phong模型的光照模型,這是phong模型的簡化版。在這之前,我們有必要先看看phong模型,以便於更好地理解blin-phong模型。
在phong模型中,鏡面反射成分和反射光線與視線夾角的余弦相關,如下圖:
l表示入射光,n表示法線,eye表示從頂點指向觀察點的視線,r是l經鏡面反射後的結果,鏡面反射成分與α角的余弦相關。
如果視線正好和反射光重合,我們將接收到最大的反射強度。當視線與反射光相分離時,反射強度將隨之下降,下降速率可以由乙個稱為shininess的因子控制,shininess的值越大,下降速率越快。也就是說,shininess越大的話,鏡面反射產生的亮點就越小。在opengl中這個值的範圍是0到128。
計算反射光向量的公式:
opengl中使用phong模型計算鏡面反射成分的公式:
式中指數s就是shininess因子,ls是光源中鏡面反射強度,ms是材質中的鏡面反射係數。
blinn提出了一種簡化的模型,也就是blinn-phong模型。它基於半向量(half-vector),也就是方向處在觀察向量以及光線向量之間的乙個向量:
現在可以利用半向量和法線之間夾角的余弦來計算鏡面反射成分。opengl所使用的blinn-phong模型計算鏡面反射的公式如下:
這個方法與顯示卡的固定流水線中使用的方法相同。因為我們要模擬opengl中的方向光,所以在shader中也使用此公式。幸運的是:opengl會幫我們算半向量,我們只需要使用下面的**:
[cpp]view plain
copy
/* compute the specular term if ndotl is larger than zero */
if(ndotl > 0.0)
GLSL 逐頂點的光照
引言 在opengl中有三種型別的光 方向光 directional 點光 point 聚光 spotlight 本教程將從方向光講起,首先我們將使用glsl來模仿opengl中的光。我們將向shader中逐漸新增環境光 散射光和高光效果。後面的教程中我們將使用逐畫素光照以獲得更好的效果。接下來我們...
GLSL教程 (七)逐畫素的光照
from 逐畫素的方向光 directional light per pixel 這一節將把前面的shader 改為逐畫素計算的方向光。我們需要將工作按照兩個shader拆分,以確定哪些是需要逐畫素操作的。首先看看每個頂點接收到的資訊 法線 半向量 光源方向 我們需要將法線變換到視點空間然後歸一化。...
GLSL 逐畫素的光照
逐畫素的方向光 directional light per pixel 這一節將把前面的shader 改為逐畫素計算的方向光。我們需要將工作按照兩個shader拆分,以確定哪些是需要逐畫素操作的。首先看看每個頂點接收到的資訊 法線 半向量 光源方向 我們需要將法線變換到視點空間然後歸一化。我們還需要...