OpenGL學習筆記《八》光照

2022-08-28 11:51:14 字數 4419 閱讀 4136

在理解opengl中的光照之前,先理解一下顏色。在我們現實生活中,我們看到的物體顏色,是物體反射的顏色,即沒有被物體吸收掉的部分。opengl利用這個,在系統中模擬的顏色,就是定義乙個表示物件的顏色向量a,再頂乙個乙個表示光源的顏色向量b,然後在片段著色器中將兩個向量相乘得到表示物體的顏色。因此大致可以理解為,opengl中最終要渲染出的顏色,其實是表示物件的顏色乘以某個影響係數,得出來的。

因為現實生活中的光照非常的複雜,早期計算裝置條件不足的情況下不能做很複雜的計算,得出的光照效果比較粗糙。近年來隨著計算裝置能力的提公升,開始出現光照追蹤技術,盡可能的模擬出現實生活中的光照效果。

opengl中採用的光照模型,叫做馮氏光照模型(phong lighting model),由三個分量組成:環境光(ambient),漫散射光(diffuse),鏡面反射光(specular),三個分量在opengl中分別使用乙個vec3向量表示,vec3三個分量x,y,z分別表示r,g,b。單獨乙個分量對最終渲染的影響,就是用表示分量顏色的向量去乘以物件顏色的向量,得到的結果就是opengl系統模擬的物件在受光照影響下的效果。而馮氏光照模型,就是將三個分量的效果組合起來,得到最終的影響效果。三種模式效果如下:

環境光(ambient)

在現實生活中光照的**有很多,如別的物體反射過來的,因此可能在我們並沒有直接看到光源的情況下,我們也能看到眼前的某些物體(即這些物體有反射光線過來)。馮氏光照模型中的環境光分量就是用來模擬這種效果,我們在這裡簡單的模擬,即在光源顏色的基礎上乘以乙個常量係數,得到的就是環境光顏色,再將這個顏色乘以物件顏色,得到模擬出來的效果,在這裡假定這個常量為0.1,調整片元著色器**:

void

main()

得到的效果如下:

通過調整常量的值,我們可以模擬出在不同的光照強度下,物件的不同表現。

漫散射光(diffuse)

在現實生活中,以燈泡為光源,我們拿乙個物體放到離燈泡不同的位置,物體表現出來的顏色效果會有不同,如果離的近、與燈泡垂直了,那麼物體表面就會更亮,如果離的遠那麼就會相對暗點。馮氏光照模型中的漫散射光分量模擬的就是這種效果,以下圖為例:

我們提到的與燈泡垂直,離燈泡遠,其實可以理解為上圖中θ角度的變化,θ角度越小,即接近於垂直,那麼此時物體表現的就會越亮,反之則暗,參考上文中提到的環境光係數的影響,在這裡我們也可以模擬乙個係數,來達到效果。從數學角度出發,兩個單位向量的點乘,結果等於兩個單位向量的模乘以兩個向量夾角的余弦值,0-90度範圍內,夾角越小,值越大。因此在這裡我們可以根據這個特性,來模擬漫散射效果。

根據光源位置,頂點座標,我們可以得到表示光源方向的環境向量,然後我們再引入法線向量這個概念(垂直於表面的向量),用兩個向量相乘得到的值,乘以光源的顏色就可以得到模擬漫反射的光源顏色,再將這個顏色乘以物件的顏色,就可以模擬出漫反射影響下的物件表現效果。

兩個向量相減,可以得到乙個表示方向的向量,在這裡我們是用頂點的位置減去光源的位置,得到乙個從頂點位置指向光源的單位向量,而法線向量我們可以根據物件的形狀直接得到,調整片元著色器**:

void

main()

因為我們提到了是用單位向量進行計算,所以保險起見對於我們要使用到的向量,都呼叫normalize處理一下。最終得到的效果:

光源的位置,是白色矩形的位置,從上圖就可以看到與光源夾角越小的就更亮,否則就更暗。

鏡面反射光(specular)

在現實生活中,我們也有這樣的體會,我們從不同的角度去觀察物體,看到的效果也會不一樣。在馮氏光照模型中,使用鏡面反射光來模擬這個效果,如下圖所示:

在這裡使用到的是光源向量基於法線對稱後,與表示視線方向向量的夾角,來模擬鏡面反射的效果,用兩個向量點乘後得到的值,再乘以光源顏色,得到表示鏡面反射光分量的顏色向量,再去乘以物件的顏色,得到模擬出來的效果。調整後的片元著色器**:

void

main()

我們使用glsl內建的reflect函式計算反射後的光源方向,然後計算與視線方向單位向量的夾角值,最後我們取這個值的32次方值,取的次方值越高,在表現上就越像聚焦的效果,如下圖:

最終我們將三個分量的值相加,再去乘以物件的顏色,就得到了馮氏光照模型下模擬出來的效果。

材質(material)lighting map投光物(light caster)

現實生活中,光照的效果非常複雜,比如一組物體,離光源的遠近,會影響物體的亮度;木頭和鐵塊表現出來的效果不同;以聚光燈為光源照射一組物體,中心區域的物體表現的會亮一點,周圍區域的會表現的暗一點。我們上面提到的馮氏光照模型其實也可以模擬出這種效果,我們可以看到上面的片元著色器**中,環境光、漫散射光、鏡面反射光都有乘以乙個常量,如果我們動態的去調整這個常量,就可以得到不同的效果。

如,我們模擬乙個離光源遠近,物體表現不同的效果,我們可以乘以乙個衰減係數,這個衰減係數的計算有乙個公式:

\begin f_ = \frac \end

其中,分子部分為常量1,保證最終得到的系數值需要小於1,分母由三個部分組成,乙個常量項,乙個線性項,乙個二次項部分;d則表示距離光源的遠近,用來模擬下圖的系數值:

即隨著距離的增加,系數值變小,到一定距離之後這個系數值基本維持在乙個比較小的範圍。調整後的片元著色器**:

//

attenuation

float distance = length(u_light.position -ofragpos);

float attenuation = 1.0 / (u_light.constant + u_light.linear * distance + u_light.quadratic * (distance *distance));

//ambient

vec3 ambient = u_light.ambient *vec3(texture(u_material.diffuse, otexcoords));

ambient *=attenuation;

//diffuse

vec3 norm =normalize(onormal);

vec3 lightdir = normalize(u_light.position -ofragpos);

float diff = max(dot(norm, lightdir), 0.0f

); vec3 diffuse = u_light.diffuse * (diff *vec3(texture(u_material.diffuse, otexcoords)));

diffuse *=attenuation;

//specular

vec3 viewdir = normalize(u_viewpos -ofragpos);

vec3 reflectdir = reflect(-lightdir, norm);

float spec = pow(max(dot(viewdir, reflectdir), 0.0f

), u_material.shininess);

vec3 specular = u_light.specular * (spec *vec3(texture(u_material.specular, otexcoords)));

specular *=attenuation;

vec3 result = (ambient + diffuse +specular);

fragcolor = vec4(result, 1.0f);

得到的效果如下:

以上就是簡單的理解一下opengl中的光照。學習的**上通過乙個章節來講解,主要就是圍繞對馮氏光照模型的三個分量,乘以不同的系數值,來達到模擬現實生活中不同的效果。

OPENGL學習筆記 光照

1 隱藏表面消除 隱藏表面消除就是消除實心物體被其他物體所遮擋住的部分,最簡單的方法就是使用深度緩衝區。深度緩衝區的原理是把乙個距離觀察平面 通常是近側裁剪平面 的深度值與視窗中的每乙個畫素相關聯。首先使用glclear 函式,把所有畫素的深度值設定為最大可能的距離,然後在場景中以任意順序繪製所有的...

OpenGL學習筆記(3) 光照

opengl通過定義光源 材料和光照模型屬性來渲染光照物體,其中gl ambient gl diffuse gl specular屬性是光源和材料都有的,用gllight 可以分別設定光的環境強度 散射強度 鏡面強度,用glmaterial 可以分別設定環境的相對應的各個屬性,具體的解釋參見open...

OpenGL學習筆記(八)

在opengl中繪製乙個物體,會像是這樣 0.複製頂點陣列到緩衝中供opengl使用 glbindbuffer gl array buffer,vbo glbufferdata gl array buffer,sizeof vertices vertices,gl static draw 1.設定頂...