GLSL教程 (七)逐畫素的光照

2021-06-09 04:39:39 字數 3838 閱讀 8239

from:

逐畫素的方向光(directional light per pixel)

這一節將把前面的shader**改為逐畫素計算的方向光。我們需要將工作按照兩個shader拆分,以確定哪些是需要逐畫素操作的。

首先看看每個頂點接收到的資訊:

•法線•半向量

•光源方向

我們需要將法線變換到視點空間然後歸一化。我們還需要將半向量和光源方向也歸一化,不過它們已經位於視點空間中了。這些歸一化之後的向量會進行插值,然後送入片斷shader,所以需要宣告易變變數儲存這些向量。

我們也可以在頂點shader中完成一些與光和材質相關的計算,這樣可以幫助平衡頂點shader和片斷shader的負載。

頂點shader**可以寫成如下形式:

[cpp]view plain

copy

varying vec4 diffuse,ambient;  

varying vec3 normal,lightdir,halfvector;  

void

main()    

接下來在片斷shader中,首先要宣告同樣的易變變數。此外還要再次對法線進行歸一化,光線向量不需要進行歸一化了,因為方向光對所有頂點都是一致的,插值得到的結果自然也不會變。之後就是計算插值過的法線向量與光線向量的點積。

[cpp]view plain

copy

varying vec4 diffuse,ambient;  

varying vec3 normal,lightdir,halfvector;  

void

main()  

gl_fragcolor = color;  

下圖顯示了逐畫素光照和逐頂點光照效果的區別:

逐畫素的點光(point light per pixel)

本節基於前面有關方向光的內容,大部分**都相同。本節內容主要涉及方向光和點光的不同之處。方向光一般假設光源在無限遠的地方,所以到達物體時是平行光。相反,點光源有乙個空間中的位置,並向四面八方輻射光線。此外,點光的強度會隨到達頂點的距離而衰弱。

對於opengl程式來說,這兩種光的區別主要有:

•光源的position域的w分量:對方向光來說它是0,表面這個position實際是乙個方向(direction);對點光來說,這個分量是1。

•點光源的衰減由三個係數決定:乙個常數項,乙個線性項和乙個二次項。

對方向光來說,光線的方向對所有頂點相同,但是對點光來說,方向是從頂點指向光源位置的向量。因此對我們來說需要修改的就是在頂點shader中加入計算光線方向的內容。

在opengl中衰減是按照如下公式計算的:

式中k0是常數衰減係數,k1是線性衰減係數,k2是二次衰減係數,d是光源位置到頂點的距離。

注意衰減與距離是非線性關係,所以我們不能逐頂點計算衰減再在片斷shader中使用插值結果,不過我們可以在頂點shader中計算距離,然後在片斷shader中使用距離的插值計算衰減。

使用點光計算顏色值的公式為:

在上面公式中,環境光部分必須分解為兩項:使用光照模型的全域性環境光設定和光源中的環境光設定。頂點shader也必須分別計算這兩個環境光成分。新的頂點shader如下:

[cpp]view plain

copy

varying vec4 diffuse,ambientglobal,ambient;  

varying vec3 normal,lightdir,halfvector;  

varying float

dist;  

void

main()    

在片斷shader中需要計算衰減,還需要將插值得到的光線方向向量歸一化,因為一般來說照到每個頂點的光線方向都不同。

[cpp]view plain

copy

varying vec4 diffuse,ambientglobal, ambient;  

varying vec3 normal,lightdir,halfvector;  

varying float

dist;  

void

main()  

gl_fragcolor = color;  

}  

下圖顯示了固定功能的逐頂點與本節中逐畫素計算得到的點光效果:

逐畫素的聚光(spot light per pixel)

本節內容與上一節基本一致,唯一不同的就是聚光不同於點光,其發出的光線被限制在乙個圓錐體中。

對於opengl程式來說,這兩種光的區別主要有:

•聚光包含乙個方向向量spotdirection,表示圓錐體的軸。

•圓錐體包含乙個角度,在glsl中可以使用應用程式設定的角度值以及對應的余弦值spotcoscutoff。

•最後還有乙個衰減速率spotexponent,它表示從圓錐的中心軸向外表面變化時光強度的衰減。

聚光的頂點shader與點光完全相同,我們只需要對片斷shader進行一些修改。只有當當前片斷位於聚光的光錐內時,才需要對散射光、鏡面反射光和環境光成分進行著色。所以我們首先要檢查這個條件。

光源與某點連線向量以及聚光方向向量(spotdirection)之間夾角的余弦值必須大於spotcoscutoff,否則此點位於聚光之外,只能接收到全域性環境光。

[cpp]view plain

copy

...  

n = normalize(normal);  

/* compute the dot product between normal and ldir */

ndotl = max(dot(n,normalize(lightdir)),0.0);  

if(ndotl > 0.0)  

}  gl_fragcolor = ...  

下面的光照計算與點光非常相似,唯一區別是衰減必須乘以聚光效果(spotlight effect),這個值按如下公式計算:

上式中spotdirection來自opengl中設定的狀態,lightdir是光源到某點的向量,spotexp是聚光衰減率,這個值也是在opengl程式中設定的,它用來控制從聚光光錐中心到邊緣的衰減。spotexp越大衰減越快,如果為0表示在光錐內光強是常數。

[cpp]view plain

copy

spoteffect = pow(spoteffect, gl_lightsource[0].spotexponent);  

att = spoteffect / (gl_lightsource[0].constantattenuation +  

gl_lightsource[0].linearattenuation * dist +  

gl_lightsource[0].quadraticattenuation * dist * dist);  

color += att * (diffuse * ndotl + ambient);  

halfv = normalize(halfvector);  

ndothv = max(dot(n,halfv),0.0);  

color += att * gl_frontmaterial.specular *  

gl_lightsource[0].specular *  

pow(ndothv,gl_frontmaterial.shininess);  

下圖分別顯示了使用固定功能流水線的逐頂點光照計算,以及使用本節shader的逐畫素光照計算得到的聚光效果。

GLSL程式設計之GLSL(七) 逐畫素光照

下邊第二部分 逐畫素點光,我試驗出了修改方法,但是至於為什麼要這樣修改,我並不清楚,希望有大神可以幫忙解答,小女感激不盡!本文參考 但經過實驗,修正其中部分問題 第一部分 逐畫素方向光 由原本 執行得到的結果為 主要原因是其片段著色器並未將所有顏色加在一起,最後加上這條語句即可 color glob...

GLSL 逐畫素的光照

逐畫素的方向光 directional light per pixel 這一節將把前面的shader 改為逐畫素計算的方向光。我們需要將工作按照兩個shader拆分,以確定哪些是需要逐畫素操作的。首先看看每個頂點接收到的資訊 法線 半向量 光源方向 我們需要將法線變換到視點空間然後歸一化。我們還需要...

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

from 引言 在opengl中有三種型別的光 方向光 directional 點光 point 聚光 spotlight 本教程將從方向光講起,首先我們將使用glsl來模仿opengl中的光。我們將向shader中逐漸新增環境光 散射光和高光效果。後面的教程中我們將使用逐畫素光照以獲得更好的效果。...