GLSL教程 (六)逐頂點的光照

2021-06-09 04:39:39 字數 3157 閱讀 3664

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拆分,以確定哪些是需要逐畫素操作的。首先看看每個頂點接收到的資訊 法線 半向量 光源方向 我們需要將法線變換到視點空間然後歸一化。我們還需要...