数据立方体_立方体纹理
立方體紋理就是包含6個2D紋理的紋理.6個紋理有序排列在立方體的6個面.其可以通過方向向量采樣立方體紋理上的紋素.
創(chuàng)建立方體貼圖跟創(chuàng)建2D貼圖一樣,但是綁定到GL_TEXTURE_CUBE_MAP上.
glGenTextures(1, &CubeMapID); glBindTexture(GL_TEXTURE_CUBE_MAP, CubeMapID);立方體紋理右6個面,每個面都要調(diào)用一次glTexImage2D,因此共需要調(diào)用6次.每個面有特定的紋理目標(biāo).按照順序是這樣.
這些紋理目標(biāo)為枚舉型,按照順序他們的值是線性疊加的.因此編寫代碼的時候可以用for循環(huán)調(diào)用glTexImage2D,然后用循環(huán)次數(shù)作為這些紋理目標(biāo)的枚舉值.從GL_TEXTUREE_MAP_POSITIVE_X開始.
例如以i作為循環(huán)次數(shù)記錄.
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);立方體紋理也需要設(shè)置環(huán)繞模式與過濾模式.
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);一般的紋理是二維的因此僅需要設(shè)定ST的環(huán)繞模式即可.但是立方體紋理是三維的因此需要對R設(shè)置.可以簡單理解為z坐標(biāo).
天空盒
立方體紋理常用于天空盒.設(shè)置好紋理數(shù)據(jù)和VAO,VBO之后,編寫天空盒用的shader就可以了.
#version 330 core layout(location=0) in vec3 aPos;out vec3 TexCoords;uniform mat4 projection; uniform mat4 view;void main() {TexCoords=aPos;gl_Position = projection * view * vec4(aPos, 1.0); }片元著色器獲取立方體紋理的紋素作為顏色輸出.
#version 330 core out vec4 FragColor; in vec3 TexCoords; uniform samplerCube skyBox; void main() {FragColor=texture(skyBox,TexCoords); }在繪制天空和的時候需要開啟深度測試,以及關(guān)閉天空盒的深度寫入.因?yàn)橛行ο笈c相機(jī)的距離可能比天空盒面到相機(jī)的距離遠(yuǎn).因此這種情況下天空盒有可能將某些物體覆蓋了.并且需要注意需要先渲染天空盒再渲染其他物體.
int main() { glDepthMask(GL_FALSE); //繪制天空盒 //... glDepthMask(GL_TRUE); //繪制其他物體 }如果按照以往的思路將MVP矩陣參數(shù)傳進(jìn)去將紋理坐標(biāo)設(shè)置好的話并不會得到一個良好的結(jié)果.
因?yàn)槲覀儾幌胩炜蘸懈鷪鼍爸衅渌矬w一樣.天空盒不應(yīng)受移動影響.僅受旋轉(zhuǎn)和縮放影響.因此需要去掉觀察矩陣的平移部分.即保留矩陣左上角部分.
view=glm::mat4(glm::mat3(view))將這個view傳進(jìn)去shader可得到正確的顯示.
以上的做法是關(guān)閉深度寫入,讓天空盒不參與深度測試.讓每個像素都運(yùn)行一次天空盒的片元著色器.但其實(shí)將天空盒的深度值永遠(yuǎn)設(shè)置為1就可以獲得正確的效果了并且參與深度測試的話也不需要每個像素都調(diào)用天空盒的著色器.因?yàn)樵谀承?fù)雜的場景里面天空盒僅僅顯示一小部分.為此,我們需要將天空盒深度值永遠(yuǎn)設(shè)為1.
根據(jù)流水線,在頂點(diǎn)著色器運(yùn)行時投影矩陣會進(jìn)行透視除法,并最后處于標(biāo)準(zhǔn)化設(shè)備空間(NDC)中的.
因此若想經(jīng)過透視除法后的z值為1,則需要將z值定為w.
#version 330 core layout(location=0) in vec3 aPos;out vec3 TexCoords;uniform mat4 projection; uniform mat4 view;void main() {TexCoords=aPos;vec4 pos = projection * view * vec4(aPos, 1.0);gl_Position = pos.xyww; }將z值定為w進(jìn)行透視除法后就變?yōu)?.
這時候還需要開啟深度測試并調(diào)用深度測試函數(shù)設(shè)置比較運(yùn)算符為GL_LEQUAL.
GL_LEQUAL為片元的深度值小于等于緩存的深度值時通過測試.因?yàn)槿绻{(diào)用默認(rèn)的GL_LESS的話基本上天空盒是不會通過測試的.這時候就不需要設(shè)置關(guān)閉深度寫入了.
glDepthFunc(GL_LEQUAL); //繪制天空盒 glDepthFunc(GL_LESS);繪制完天空盒之后改回默認(rèn)的深度運(yùn)算操作符,以便其他物體進(jìn)行深度測試.
如果場景里面沒有需要透明度混合的物體的話則天空盒可以隨便放置于主循環(huán)的某一個位置進(jìn)行渲染.否則的話會出現(xiàn)這種情況.
2B因?yàn)椴恍枰该鞫然旌?因此可以獲得正常的渲染效果.但是草地于窗戶精靈體需要透明度混合因此會出現(xiàn)奇怪的效果.
這里我是先渲染場景的所有物體,最后才渲染天空盒的.因此這時候場景物體部分的深度值比1小,通過測試與默認(rèn)的顏色緩存的顏色進(jìn)行混合.接著天空盒與深度緩存進(jìn)行測試,因?yàn)樘炜蘸猩疃戎禐?,比場景里物體的深度值大,因此這部分片元會被拋棄.所以物體混合的顏色里面沒有天空盒紋理的顏色.
為此,最好在主循環(huán)剛開始的時候渲染天空盒.讓天空盒顏色代替默認(rèn)顏色緩存里的顏色.
所以,無論是對天空盒關(guān)閉深度寫入還是設(shè)置天空盒的深度值為1,都最好在主循環(huán)開始的時候渲染.
立方體紋理可以用于環(huán)境映射.常用有反射和折射.
首先是反射
反射很簡單.主要就是獲取向量R的方向然后通過R在立方體紋理中獲取紋素.
在頂點(diǎn)著色器獲取片元的位置以及法向量輸出到片元著色器.
#version 330 core layout (location=0) in vec3 aPos; layout (location=1) in vec3 aNormal;out vec3 fragPos; out vec3 Normal;uniform mat4 model; uniform mat4 view; uniform mat4 projection;void main() { Normal=mat3(transpose(inverse(view*model)))*aNormal;fragPos=vec3(view*model*vec4(aPos,1.0));gl_Position=projection*view*model*vec4(aPos,1.0); }這里的法線用了法線矩陣消除縮放對物體法線的影響.片元位置放置在相機(jī)空間中,因?yàn)槲移糜趯⑦@些計(jì)算放在相機(jī)空間,這樣就不用在片元著色器計(jì)算觀察位置到片元位置了,直接可以用片元位置代替,因?yàn)樵谙鄼C(jī)空間中,攝像機(jī)的位置就是原點(diǎn).
根據(jù)上面的圖片,需要在片元著色器計(jì)算反射向量
.反射向量可以通過GLSL內(nèi)置函數(shù) 計(jì)算,也可以用反射向量的計(jì)算方式計(jì)算 .因?yàn)樵陧旤c(diǎn)著色器片元位置在相機(jī)空間下,所以向量 僅需要對片元位置歸一化即可.#version 330 core out vec4 FragColor; in vec3 Normal; in vec3 fragPos;uniform samplerCube skybox;void main() { //環(huán)境映射反射vec3 I=normalize(fragPos);vec3 R=reflect(I,normal);FragColor=vec4(texture(skybox,R).xyz,1.0); }可以運(yùn)用反射貼圖使模型的僅某一部分進(jìn)行反射.通過引入反射貼圖并對反射貼圖進(jìn)行采樣獲得當(dāng)前網(wǎng)格的反射系數(shù),然后運(yùn)用插值對模型的反射貼圖與其他光照模型進(jìn)行綜合
struct Material {sampler2D texture_diffuse0;sampler2D texture_specular0;sampler2D texture_normal0;sampler2D texture_reflection0;float shininess;//影響鏡面高光的散射/半徑 };在material就結(jié)構(gòu)體里面增加一個反射貼圖的聲明.接著求出反射系數(shù).
float reflectRate=(texture(material.texture_reflection0,TexCoords).r+texture(material.texture_reflection0,TexCoords).g+texture(material.texture_reflection0,TexCoords).b)/3;不過反射貼圖一般顏色分量不是0就是1,所以也可以簡單點(diǎn)
float reflectRate=texture(material.texture_reflection0,TexCoords).r;在總顏色輸出那里做一個插值就可以了.
void main() { vec3 normal=normalize(Normal);vec3 viewDir=normalize(-fragPos);//觀察空間下進(jìn)行vec3 Direction=CalcDirectionalLight(dirLight,normal,viewDir);vec3 Point = CalcPointLight(pointLight,normal,fragPos,viewDir);vec3 Spot=CalcSpotLight(spotLight,normal,fragPos,viewDir);//環(huán)境映射反射vec3 I=normalize(fragPos);vec3 R=reflect(I,normal);float reflectRate=texture(material.texture_reflection0,TexCoords).r;vec4 reflection=texture(skybox,R);FragColor=vec4(reflectRate*reflection.xyz+(1-reflectRate)*(Spot+Point+Direction),1.0); }最終效果中可以看到身上比較閃閃的地方都有天空盒的映射,其中以眼部的鏡片效果最明顯.
折射
折射與反射的區(qū)別不大,就是將
函數(shù)改為 函數(shù),再加一個折射率常數(shù).折射用到了斯涅耳定律,斯涅耳定律很簡單:
其中
, 表示兩種介質(zhì)的折射率, , 表示光線方向與法線的夾角.介質(zhì)的折射率有一個固定的參數(shù).
但是!!!我們不需要自己計(jì)算斯涅爾定律,反射有內(nèi)建GLSL函數(shù).折射與反射的區(qū)別不大,就是將
函數(shù)改為 函數(shù),再加一個折射率常數(shù).將上述反射部分的片元著色器代碼修改下.其中
,兩種折射率比例.然后作為 的第三個參數(shù)就行float ratio=1.0/1.33; vec3 I=normalize(fragPos); vec3 R=refract(I,normal,ratio);FragColor=vec4(texture(skybox,R).xyz,1.0);當(dāng)然,
函數(shù)想要自己算也不是不行.楊超:cg refract函數(shù)?zhuanlan.zhihu.com這里有一篇折射函數(shù)的推導(dǎo)過程.其中
.按照這篇文章的推導(dǎo)即可得到正確折射向量.
vec3 refract(vec3 I,vec3 normal,float ratio) {vec3 OC=dot(-I,normal)*normal;vec3 CA=-I-OC;vec3 EB=-ratio*CA;float EB_length_2=EB.x*EB.x+EB.y*EB.y+EB.z+EB.z;vec3 OE=-sqrt(1-EB_length_2)*normal;return EB+OE; } 立方體貼圖 - LearnOpenGL CN?learnopengl-cn.github.io總結(jié)
以上是生活随笔為你收集整理的数据立方体_立方体纹理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python递归和循环的区别_递归与伪递
- 下一篇: python与golang_Golang