OpenGL之混合


首先說說透明度吧,平時我們怎么說明一個物體是透明,想必是將此物體和背后的物體混合起來看,發現只看到后面的物體,所以就說這個物體是透明的。

實際上物體透明分成兩種透明,一種是完全透明另一種是部分透明,完全透明的話會使顏色完全穿透,而部分透明使顏色穿透的同時也顯示自身顏色。描述一個物體的透明度我們引入顏色值中的Alpha值。當Alpha值為0.0時,那么該物體完全透明,1.0則是完全不透明。

 

接下來就是如何去載入一個有透明部分的紋理:

此時就要告訴SOIL庫載入放是要選擇GL_RGBA方式,同時設置紋理時也要改成GL_RGBA方式。

unsigned char * image = SOIL_load_image(path, &width, &height, 0, SOIL_LOAD_RGBA);

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);

片段着色器中

void main()

{

  // color = vec4(vec3(texture(texture1, TexCoords)), 1.0);

      color = texture(texture1, TexCoords);

}

如果僅僅只做以上修改,那么顯示出來的結果這樣:,原因是OpenGL默認是不知道如何處理alpha值的,此時就要用到GLSL語言中的discard,有點類似於編程語言中break味道,它保證了片段不會被進一步處理,這樣就不會進入顏色緩沖。

所以着色器要這樣設置

 

但是上面這樣做的方式是不能渲染出部分透明的紋理,他們要么是完全透明然后被discard,要么只渲染不透明部分。所以為了渲染出不同的透明度級別,我們需要開啟混合(Blending)

OpenGL混合的方式:

例如我把綠色物體渲染到紅色物體上,那么此時目標顏色是紅色,源顏色是綠色。至於因子,先設置源因子就是源向量的Alpha值,然后目標因子是1.0-源因子

那么該如何設置這樣的混合呢?

glBlendFunc的函數。

void glBlendFunc(GLenum sfactor, GLenum dfactor)接收兩個參數用來設置源(source)和目標(destination)因子。其中參數選項如下:

此例子中我們這樣設置:glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

 

之后開始應用混合:

首先要開啟混合glEnable(GL_BLEND)

設置混合處理方式glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

由於我們開啟了混合,就不需要丟棄片段了所以片段着色器只需

但此時還會出現前面的窗子透明部分阻塞了后面的現象

此時原因是當混用深度測試和混合時,深度測試不關心片段是否有透明度,所以透明部分被寫入深度緩沖,就和其他值沒什么區別,那么后面的深度值比較大那么該片段就會被丟棄,此時就起不到透明的效果。

為保證前面窗子顯示了它后面的窗子,我們必須首先繪制后面的窗子。這意味着我們必須手工調整窗子的順序,從遠到近地逐個渲染,這僅僅是對於要透明部分的物體,如果對於不要透明部分的物體,無需混合僅僅丟棄即可。

 

所以我們遵循下面原則來修改:

當無透明度物體和透明物體一起繪制的時候,通常要先繪制所有不透明物體,為所有透明物體排序,按順序繪制透明物體。 一種排序透明物體的方式是,獲取一個物體到觀察者透視圖的距離。這可以通過獲取攝像機的位置向量和物體的位置向量來得到。接着我們就可以把它和相應的位置向量一起儲存到一個map中。map會自動基於它的鍵排序它的值。

計算z值並排序

std::map<float, glm::vec3> sorted;

for (GLuint i = 0; i < windows.size(); i++) // windows contains all window positions

{

   GLfloat distance = glm::length(camera.Position - windows[i]);

   sorted[distance] = windows[i];

}

 之后繪制只需要逆序繪制即可

 

最終結果

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM