麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 編程 > Delphi > 正文

NeHe的opengl教程delphi版(8)----簡單的透明

2019-11-18 18:30:21
字體:
來源:轉載
供稿:網友
 

{

呵呵,這兩課早就翻譯好了,一直沒貼,大家久等了(有人再等嗎?)

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

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

混色的公式
若您對數學不感冒,而只想看看如何實現透明,請跳過這一節。
若您想深入理解(色彩)混合的工作原理,這一節應該適合您吧。
『CKER的補充:其實并不難^-^。原文中的公式如下,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,最后才到達觀察者的眼睛。)
在深度緩存啟用時,您應該將透明圖形按照深度進行排序,
并在全部場景繪制完畢之后再繪制這些透明物體。否則您將得到不正確的結果。
我知道某些時候這樣做是很令人痛苦的,但這是正確的方法。

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

}
Var
   h_RC             : HGLRC;            // Rendering Context(著色描述表)。
   h_DC             : HDC;              // Device Context(設備描述表)
   h_Wnd            : HWND;             // 窗口句柄
   h_Instance       : HINST;            // 程序Instance(實例)。
   keys             : Array[0..255] Of Boolean; // 用于鍵盤例程的數組

   light            : Boolean;          // 光源的開/關

   blend            : Boolean;          // Blending OFF/ON? ( 新增 )

   lp               : Boolean;          // L鍵按下了么?
   fp               : Boolean;          // F鍵按下了么?

   bp               : Boolean;          // B 鍵按下了么? ( 新增 )

   xrot             : GLfloat;          // X 旋轉
   yrot             : GLfloat;          // Y 旋轉
   xspeed           : GLfloat;          // X 旋轉速度
   yspeed           : GLfloat;          // Y 旋轉速度

   z                : GLfloat = -5.0 f; // 深入屏幕的距離
   LightAmbient     : Array[0..3] Of GLfloat = (0.5, 0.5, 0.5, 1.0);  //環境光參數 ( 新增 )
   LightDiffuse     : Array[0..3] Of GLfloat = (1.0, 1.0, 1.0, 1.0);  // 漫射光參數 ( 新增 )
   LightPosition    : Array[0..3] Of GLfloat = (0.0, 0.0, 2.0, 1.0);  // 光源位置 ( 新增 )
   filter           : GLuint;           // 濾波類型
   texture          : Array[0..2] Of GLuint; // 3種紋理的儲存空間

PRocedure glGenTextures(n: GLsizei; Var textures: GLuint); stdcall; external
   opengl32;

Procedure glBindTexture(target: GLenum; texture: GLuint); stdcall; external
   opengl32;

Function gluBuild2DMipmaps(target: GLenum; components, width, height: GLint;
   format, atype: GLenum; data: Pointer): Integer; stdcall; external glu32 name
   'gluBuild2DMipmaps';

{
然后往下移動到 LoadGLTextures() 這里。
找到 if (TextureImage[0]=LoadBMP('Data/Crate.bmp'))
這一行。我們現在使用有色玻璃紋理來代替上一課中的木箱紋理。
if (TextureImage[0]=LoadBMP("Data/glass.bmp")); // 載入玻璃位圖 ( 已修改 )
}

Function LoadTexture: boolean;          // 載入位圖并轉換成紋理
Var
   Status           : boolean;          // Status 指示器
   TextureImage     : Array[0..1] Of PTAUX_RGBImageRec; // 創建紋理的存儲空間
Begin
   Status := false;
   ZeroMemory(@TextureImage, sizeof(TextureImage)); // 將指針設為 NULL
   TextureImage[0] := LoadBMP('Walls.bmp');
   If TextureImage[0] <> Nil Then
      Begin
         Status := TRUE;                // 將 Status 設為 TRUE
         glGenTextures(1, texture[0]);  // 創建紋理
         // 創建 Nearest 濾波貼圖
         glBindTexture(GL_TEXTURE_2D, texture[0]);
         // 生成紋理
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);  // ( 新增 )
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);  // ( 新增 )

         glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0].sizeX,
            TextureImage[0].sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE,
            TextureImage[0].data);
         glBindTexture(GL_TEXTURE_2D, texture[1]);  // 使用來自位圖數據生成 的典型紋理
         // 生成紋理
         glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0].sizeX,
            TextureImage[0].sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE,
            TextureImage[0].data);
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);  // 線形濾波
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);  // 線形濾波
         // 創建 MipMapped 紋理
         glBindTexture(GL_TEXTURE_2D, texture[2]);
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
            GL_LINEAR_MIPMAP_NEAREST);  // ( 新增 )
         gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[0].sizeX,
            TextureImage[0].sizey, GL_RGB, GL_UNSIGNED_BYTE,
            TextureImage[0].data);      //(新增)  }
      End;
   If assigned(TextureImage[0]) Then    // 紋理是否存在
      If assigned(TextureImage[0].data) Then // 紋理圖像是否存在
         TextureImage[0].data := Nil;   // 釋放紋理圖像占用的內存
   TextureImage[0] := Nil;              // 釋放圖像結構
   result := Status;                    // 返回 Status
End;

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

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

Procedure glInit();                     // 此處開始對OpenGL進行所有設置
Begin
   If (Not LoadTexture) Then            // 調用紋理載入子例程
      exit;                             // 如果未能載入,退出

   glEnable(GL_TEXTURE_2D);             // 啟用紋理映射
   glShadeModel(GL_SMOOTH);             // 啟用陰影平滑
   glClearColor(0.0, 0.0, 0.0, 0.0);    // 黑色背景
   glClearDepth(1.0);                   // 設置深度緩存
   glEnable(GL_DEPTH_TEST);             // 啟用深度測試
   glDepthFunc(GL_LESS);                // 所作深度測試的類型
   glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); //高度優化的透視投影計算
   glLightfv(GL_LIGHT1, GL_AMBIENT, @LightAmbient[0]); // 設置環境光
   glLightfv(GL_LIGHT1, GL_DIFFUSE, @LightDiffuse[0]); // 設置漫射光
   glLightfv(GL_LIGHT1, GL_POSITION, @LightPosition); // 光源位置
   glEnable(GL_LIGHT1);                 // 啟用一號光源

   glColor4f(1.0, 1.0, 1.0, 0.5);       // 全亮度, 50% Alpha 混合( 新增 )
   glBlendFunc(GL_SRC_ALPHA, GL_ONE); // 基于源象素alpha通道值的半透明混合函數 ( 新增 )

End;

 {在接近第七課結尾處的地方找到下面的代碼段。
                  If keys[VK_LEFT] Then    //Left方向鍵按下了么?
                  yspeed := yspeed - 0.01; //若是, 減少yspeed
                接著上面的代碼,我們增加如下的代碼。
                這幾行監視B鍵是否按下。
                如果是的話,計算機檢查混合選項是否已經打開。
                然后將其置為相反的狀態。
                }
               If (keys[ord('B')] And Not bp) Then //B 健按下且bp為 FALSE么?
                  Begin
                     bp := TRUE;        // 若是, bp 設為 TRUE
                     blend := Not blend; // 切換混合選項的 TRUE / FALSE
                     If (blend) Then    // 混合打開了么?
                        Begin
                           glEnable(GL_BLEND); // 打開混合
                           glDisable(GL_DEPTH_TEST); // 關閉深度測試
                        End
                     Else               // 否則
                        Begin
                           glDisable(GL_BLEND); // 關閉混合
                           glEnable(GL_DEPTH_TEST); // 打開深度測試
                        End;
                  End;
               If (Not keys[ord('B')]) Then //  B 鍵松開了么?
                  Begin
                     bp := FALSE;       // 若是, bp設為 FALSE
                  End;
               {
               但是怎樣才能在使用紋理貼圖的時候指定混合時的顏色呢?很簡單,
               在調整貼圖模式時,文理貼圖的每個象素點的顏色都是由alpha通道參數
               與當前地象素顏色相乘所得到的。
               比如,繪制的顏色是 (0.5, 0.6, 0.4),
               我們會把顏色相乘得到(0.5, 0.6, 0.4, 0.2)
                (alpha參數在沒有指定時,缺省為零)。
               就是如此!OpenGL實現Alpha混合的確很簡單!
               }
               {
                原文注 (11/13/99)
                我(NeHe)混色代碼進行了修改,以使顯示的物體看起來更逼真。
                同時對源象素和目的象素使用alpha參數來混合,會導致物體的人造痕跡看起來很明顯。
                會使得物體的背面沿著側面的地方顯得更暗。
                基本上物體會看起來很怪異。
                我所用的混色方法也許不是最好的,但的確能夠工作。
                啟用光源之后,物體看起來很逼真。
                感謝Tom提供的原始代碼,他采用的混色方法是正確的,
                但物體看起來并不象所期望的那樣吸引人:)
                代碼所作的再次修改是因為在某些顯卡上glDepthMask()函數存在尋址問題。
                這條命令在某些卡上啟用或關閉深度緩沖測試時似乎不是很有效,
                所以我已經將啟用或關閉深度緩沖測試的代碼轉成老式的glEnable和glDisable。

                紋理貼圖的Alpha混合
                用于紋理貼圖的alpha參數可以象顏色一樣從問題貼圖中讀取。
                方法如下,您需要在載入所需的材質同時取得其的alpha參數。
                然后在調用glTexImage2D()時使用GL_RGBA的顏色格式。
               }


上一篇:NeHe的opengl教程delphi版(9)----星星

下一篇:Delphi代碼創建形式規范

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
學習交流
熱門圖片

新聞熱點

疑難解答

圖片精選

網友關注

主站蜘蛛池模板: 高清中文字幕在线 | 国产乱淫a∨片免费视频 | 久久久久久久一区二区三区 | 又黄又爽免费无遮挡在线观看 | 成人免费观看av | 久久久久久久久久久久久九 | 91久久久久久久久久久久久久 | 九九热精品在线播放 | 韩国精品视频在线观看 | 久久探花 | 免费一级特黄做受大片 | 欧美 国产 综合 | 中国美女一级黄色大片 | 亚洲福利在线视频 | 国产在线看一区 | 久久人人爽人人爽人人片av高清 | 精品国产99久久久久久宅男i | 国内精品伊人久久久久网站 | 一级黄色在线免费观看 | 毛片视频观看 | 九九热九九爱 | 黄网站免费入口 | 羞羞视频免费观看入口 | 黄色一级片在线免费观看 | 亚洲国产精品久久久久久久久久久 | 国产88久久久国产精品免费二区 | 久久久久亚洲a | 最新在线黄色网址 | 国产九九热| 蜜桃精品视频在线观看 | 成人一级免费视频 | 成人国产精品一区 | 久久久免费 | 欧美a级毛片| 鲁丝一区二区二区四区 | 欧美一级片在线 | 成人综合一区二区 | 久久超| 国产二区三区在线播放 | a视频在线播放 | 欧产日产国产精品v |