天天看點

NeHe OpenGL第八課:混合

NeHe OpenGL第八課:混合

NeHe OpenGL第八課:混合
NeHe OpenGL第八課:混合

混合:

在這一課裡,我們在紋理的基礎上加上了混合,它看起具有透明的效果,當然解釋它不是那麼容易,當希望你喜歡它。

簡單的透明

OpenGL中的絕大多數特效都與某些類型的(色彩)混合有關。混色的定義為,将某個象素的顔色和已繪制在螢幕上與其對應的象素顔色互相結合。至于如何結合這兩個顔色則依賴于顔色的alpha通道的分量值,以及/或者所使用的混色函數。Alpha通常是位于顔色值末尾的第4個顔色組成分量。前面這些課我們都是用GL_RGB來指定顔色的三個分量。相應的GL_RGBA可以指定alpha分量的值。更進一步,我們可以使用glColor4f()來代替glColor3f()。

絕大多數人都認為Alpha分量代表材料的透明度。這就是說,alpha值為0.0時所代表的材料是完全透明的。alpha值為1.0時所代表的材料則是完全不透明的。

混色的公式

若您對數學不感冒,而隻想看看如何實作透明,請跳過這一節。若您想深入了解(色彩)混合的工作原理,這一節應該适合您吧。『譯者注:其實并不難^-^。原文中的公式如下,CKER再唠叨一下吧。其實混合的基本原理是就将要分色的圖像各象素的顔色以及背景顔色均按照RGB規則各自分離之後,根據-圖像的RGB顔色分量*alpha值+背景的RGB顔色分量*(1-alpha值)-這樣一個簡單公式來混合之後,最後将混合得到的RGB分量重新合并。』

公式如下:

(Rs Sr + Rd Dr, Gs Sg + Gd Dg, Bs Sb + Bd Db, As Sa + Ad Da)

OpenGL按照上面的公式計算這兩個象素的混色結果。小寫的s和r分别代表源象素和目标象素。大寫的S和D則是相應的混色因子。這些決定了您如何對這些象素混色。絕大多數情況下,各顔色通道的alpha混色值大小相同,這樣對源象素就有 (As, As, As, As),目标象素則有1, 1, 1, 1) - (As, As, As, As)。上面的公式就成了下面的模樣:

(Rs As + Rd (1 - As), Gs As + Gd (1 - As), Bs As + Bs (1 - As), As As + Ad (1 - As))

這個公式會生成透明/半透明的效果。

OpenGL中的混色

在OpenGL中實作混色的步驟類似于我們以前提到的OpenGL過程。接着設定公式,并在繪制透明對象時關閉寫深度緩存。因為我們想在半透明的圖形背後繪制 對象。這不是正确的混色方法,但絕大多數時候這種做法在簡單的項目中都工作的很好。

Rui Martins 的補充: 正确的混色過程應該是先繪制全部的場景之後再繪制透明的圖形。并且要按照與深度緩存相反的次序來繪制(先畫最遠的物體)。

考慮對兩個多邊形(1和2)進行alpha混合,不同的繪制次序會得到不同的結果。(這裡假定多邊形1離觀察者最近,那麼正确的過程應該先畫多邊形2,再畫多邊形1。正如您再現實中所見到的那樣,從這兩個<透明的>多邊形背後照射來的光線總是先穿過多邊形2,再穿過多邊形1,最後才到達觀察者的眼睛。)

在深度緩存啟用時,您應該将透明圖形按照深度進行排序,并在全部場景繪制完畢之後再繪制這些透明物體。否則您将得到不正确的結果。我知道某些時候這樣做是很令人痛苦的,但這是正确的方法。

我們将使用第七課的代碼。一開始先在代碼開始處增加兩個新的變量。出于清晰起見,我重寫了整段代碼。

bool    blend;      // 是否混合?

bool bp;      // B 鍵按下了麼?

然後往下移動到 LoadGLTextures() 這裡。找到" if (TextureImage[0]=LoadBMP("Data/Crate.bmp")) "這一行。我們現在使用有色玻璃紋理來代替上一課中的木箱紋理。 

 if (TextureImage[0]=LoadBMP("Data/glass.bmp")) // 載入玻璃位圖

在InitGL()代碼段加入以下兩行。第一行以全亮度繪制此物體,并對其進行50%的alpha混合(半透明)。當混合選項打開時,此物體将會産生50%的透明效果。第二行設定所采用的混合類型。

Rui Martins 的補充: alpha通道的值為 0.0意味着物體材質是完全透明的。1.0 則意味着完全不透明。  

 glColor4f(1.0f,1.0f,1.0f,0.5f);   // 全亮度, 50% Alpha 混合

 glBlendFunc(GL_SRC_ALPHA,GL_ONE);  // 基于源象素alpha通道值的半透明混合函數

在接近第七課結尾處的地方找到下面的代碼段。 

 if (keys[VK_LEFT])    // Left方向鍵按下了麼?

 {

  yspeed-=0.01f;    // 若是, 減少yspeed

 }

接着上面的代碼,我們增加如下的代碼。這幾行監視B鍵是否按下。如果是的話,計算機檢查混合選項是否已經打開。然後将其置為相反的狀态。 

 if (keys['B'] && !bp)    // B 健按下且bp為 FALSE麼?

  bp=TRUE;    // 若是, bp 設為 TRUE

  blend = !blend;    // 切換混合選項的 TRUE / FALSE

  if(blend)    // 混合打開了麼?

  {

   glEnable(GL_BLEND);  // 打開混合

   glDisable(GL_DEPTH_TEST); // 關閉深度測試

  }

  else     // 否則

   glDisable(GL_BLEND);  // 關閉混合

   glEnable(GL_DEPTH_TEST); // 打開深度測試

 if (!keys['B'])     //  B 鍵松開了麼?

  bp=FALSE;    // 若是, bp設為 FALSE

原文及其個版本源代碼下載下傳:

http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=08

繼續閱讀