NeHe OpenGL教程 (二十)

來源:互聯網
上載者:User

20課
  
  蒙板:

到目前為止你已經學會如何使用alpha混合,把一個透明物體渲染到螢幕上了,但有的使用它看起來並不是那麼的複合你的心意。使用蒙板技術,將會按照你蒙板的位置精確的繪製。
 
 歡迎來到第20課的教程,*.bmp映像被給各種作業系統所支援,因為它簡單,所以可以很輕鬆的作為紋理圖片載入它。知道現在,我們在把映像載入到螢幕上時沒有擦除背景色,因為這樣簡單高效。但是效果並不總是很好。
大部分情況下,把紋理混合到螢幕,紋理不是太少就是太多。當使用精靈時,我不希望背景從精靈的縫隙中透出光來;但在顯示文字時,你希望文字的間隙可以顯示背景色。

由於以上原因,我們需要使用“掩模”。使用“掩模”需要兩個步驟,首先我們在情境上放置黑白相間的紋理,白色代表透明部分,黑色代表不透明部分。接著我們使用一種特殊的混合方式,只有在黑色部分上的紋理才會顯示在情境中。

我只重寫那些改變的地方,如果你做好了學習的準備,我們就上路吧。
  
 在這個程式裡,我們使用7個全域變數。變數masking為一個布爾值,標誌是否使用“掩模”。變數mp標誌鍵M是否按下,變數sp標誌空格是否按下。
接著我們建立儲存5個紋理標誌的數組,loop為迴圈變數。變數roll使得紋理沿螢幕滾動。
 
bool    masking=TRUE;                    // 是否使用“掩模”
bool    mp;                        // 鍵M是否按下
bool    sp;                        // 空格是否按下
bool    scene;                        // 繪製那一個情境

GLuint    texture[5];                    // 儲存5個紋理標誌
GLuint    loop;                        // 迴圈變數

GLfloat    roll;                        // 滾動紋理

  
 載入紋理代碼基本沒變,只是這裡我們需要載入5個紋理 
  

int LoadGLTextures()                       
{
    int Status=FALSE;                       
    AUX_RGBImageRec *TextureImage[5];                // 建立儲存5個紋理的資料結構
    memset(TextureImage,0,sizeof(void *)*5);            // 初始化

    if ((TextureImage[0]=LoadBMP("Data/logo.bmp")) &&        // 載入紋理0
        (TextureImage[1]=LoadBMP("Data/mask1.bmp")) &&        // 載入掩模紋理1,作為“掩模”使用
        (TextureImage[2]=LoadBMP("Data/image1.bmp")) &&        // 載入紋理1
        (TextureImage[3]=LoadBMP("Data/mask2.bmp")) &&        // 載入掩模紋理2,作為“掩模”使用
        (TextureImage[4]=LoadBMP("Data/image2.bmp")))        // 載入紋理2
    {
        Status=TRUE;                       
        glGenTextures(5, &texture[0]);                // 建立5個紋理

        for (loop=0; loop<5; loop++)                // 迴圈載入5個紋理
        {
            glBindTexture(GL_TEXTURE_2D, texture[loop]);
            glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
            glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
            glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[loop]->sizeX, TextureImage[loop]->sizeY,
                0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[loop]->data);
        }
    }
    for (loop=0; loop<5; loop++)                   
    {
        if (TextureImage[loop])                   
        {
            if (TextureImage[loop]->data)           
            {
                free(TextureImage[loop]->data);       
            }
            free(TextureImage[loop]);           
        }
    }
    return Status;                       
}

  
 改變視窗大小和初始化OpenGL的函數沒有變化
 
  
  
 現在到了最有趣的繪製部分了,我們從清楚背景色開始,接著把物體移入螢幕2個單位。 
  

int DrawGLScene(GLvoid)       
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);           
    glLoadIdentity();                           
    glTranslatef(0.0f,0.0f,-2.0f);                        // 物體移入螢幕2個單位
  
 下面一行,我們選擇'logo'紋理。我們將要通過四邊形把紋理映射到螢幕,並按照頂點的順序設定紋理座標。
Jonathan Roy說OpenGL是一個基於頂點的圖形系統,大部分你設定的參數是作為頂點的屬性而記錄的,紋理座標就是這樣一種屬性。你只要簡單的設定各個頂點的紋理座標,OpenGL就自動幫你把多邊形內部填充紋理,通過一個插值的過程。

向前面幾課一樣,我們假定四邊形面對我們,並把紋理座標(0,0)綁定到左下角,(1,0)綁定到右下角,(1,1)綁定到右上方。給定這些設定,你應該能猜到四邊形中間對應的紋理座標為(0.5,0.5),但你自己並沒有設定此處的紋理座標!OpenGL為你做了計算。

在這一課裡,我們通過設定紋理座標達到一種滾動紋理的目的。紋理座標是被歸一化的,它的範圍從0.0-1.0,值0被映射到紋理的一邊,值1被映射到紋理的另一邊。超過1的值,紋理可以按照不同的方式被映射,這裡我們設定為它將迴繞道另一邊並重複紋理。例如如果使用這樣的映射方式,紋理座標(0.3,0.5)和(1.3,0.5)被映射到同一個紋理座標。在這一課裡,我們將嘗試一種無縫填充的效果。

 我們使用roll變數去設定紋理座標,當它為0時,它把紋理的左下角映射到四邊形的左下角。當它大於0時,把紋理的左上方映射到四邊形的左下角,看起來的效果就是紋理沿四邊形向上滾動。 
  

    glBindTexture(GL_TEXTURE_2D, texture[0]);                // 選擇Logo紋理
    glBegin(GL_QUADS);                            // 繪製紋理四邊形
        glTexCoord2f(0.0f, -roll+0.0f); glVertex3f(-1.1f, -1.1f,  0.0f);   
        glTexCoord2f(3.0f, -roll+0.0f); glVertex3f( 1.1f, -1.1f,  0.0f);   
        glTexCoord2f(3.0f, -roll+3.0f); glVertex3f( 1.1f,  1.1f,  0.0f);   
        glTexCoord2f(0.0f, -roll+3.0f); glVertex3f(-1.1f,  1.1f,  0.0f);   
    glEnd();       
  
 啟用混合和禁用深度測試 
  

    glEnable(GL_BLEND);                            // 啟用混合
    glDisable(GL_DEPTH_TEST);                            // 禁用深度測試

  
 接下來我們需要根據masking的值設定是否使用“掩模”,如果是,則需要設定相應的混合係數。 
  

    if (masking)                                // 是否啟用“掩模”
    {

  
 如果啟用了“掩模”,我們將要設定“掩模”的混合係數。一個“掩模”只是一幅繪製到螢幕的紋理圖片,但只有黑色和白色。白色的部分代表透明,黑色的部分代表不透明。
下面這個混合係數使得,任何對應“掩模”黑色的部分會變為黑色,白色的部分會保持原來的顏色。
 
  

        glBlendFunc(GL_DST_COLOR,GL_ZERO);                    // 使用黑白“掩模”混合螢幕顏色
    }

  
 現在我們檢查繪製那一個層,如果為True繪製第二個層,否則繪製第一個層 
  

    if (scene)   
    {

  
 為了不使它看起來顯得非常大,我們把它移入螢幕一個單位,並把它按roll變數的值進行旋轉(沿Z軸)。 
  

        glTranslatef(0.0f,0.0f,-1.0f);                    // 移入螢幕一個單位
        glRotatef(roll*360,0.0f,0.0f,1.0f);                    // 沿Z軸旋轉

  
 接下我們檢查masking的值來繪製我們的對象 
  

        if (masking)                            // “掩模”是否開啟
        {

  
 如果“掩模開啟”,我們會把掩模繪製到螢幕。當我們完成這個操作時,將會看到一個鏤空的紋理出現在螢幕上。 
  

            glBindTexture(GL_TEXTURE_2D, texture[3]);        // 選擇第二個“掩模”紋理
            glBegin(GL_QUADS);                    // 開始繪製四邊形
                glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.1f, -1.1f,  0.0f);   
                glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.1f, -1.1f,  0.0f);   
                glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.1f,  1.1f,  0.0f);   
                glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.1f,  1.1f,  0.0f);   
            glEnd();                       
        }

  
 當我們把“掩模”繪製到螢幕上後,接著我們變換混合係數。這次我們告訴OpenGL把任何黑色部分對應的像素複製到螢幕,這樣看起來紋理就像被鏤空一樣文章螢幕上。
注意,我們在變換了混合模式後在選擇的紋理。

如果我們沒有使用“掩模”,我們的映像將與螢幕顏色混合。
 
  

        glBlendFunc(GL_ONE, GL_ONE);                // 把紋理2複製到螢幕
        glBindTexture(GL_TEXTURE_2D, texture[4]);            // 選擇第二個紋理
        glBegin(GL_QUADS);                        // 繪製四邊形
            glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.1f, -1.1f,  0.0f);   
            glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.1f, -1.1f,  0.0f);   
            glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.1f,  1.1f,  0.0f);   
            glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.1f,  1.1f,  0.0f);   
        glEnd();                       
    }

  
 繪製第一層映像 
  

    else                                   
    {

  
 如果“掩模開啟”,我們會把掩模繪製到螢幕。當我們完成這個操作時,將會看到一個鏤空的紋理出現在螢幕上。 
  

        if (masking)                            // “掩模”是否開啟
        {

  
 如果“掩模開啟”,我們會把掩模繪製到螢幕。當我們完成這個操作時,將會看到一個鏤空的紋理出現在螢幕上。 
  

            glBindTexture(GL_TEXTURE_2D, texture[1]);        // 選擇第一個“掩模”紋理
            glBegin(GL_QUADS);                    // 開始繪製四邊形
                glTexCoord2f(roll+0.0f, 0.0f); glVertex3f(-1.1f, -1.1f,  0.0f);   
                glTexCoord2f(roll+4.0f, 0.0f); glVertex3f( 1.1f, -1.1f,  0.0f);   
                glTexCoord2f(roll+4.0f, 4.0f); glVertex3f( 1.1f,  1.1f,  0.0f);   
                glTexCoord2f(roll+0.0f, 4.0f); glVertex3f(-1.1f,  1.1f,  0.0f);   
            glEnd();                       
        }

  
 當我們把“掩模”繪製到螢幕上後,接著我們變換混合係數。這次我們告訴OpenGL把任何黑色部分對應的像素複製到螢幕,這樣看起來紋理就像被鏤空一樣文章螢幕上。
注意,我們在變換了混合模式後在選擇的紋理。

如果我們沒有使用“掩模”,我們的映像將與螢幕顏色混合。
 
  

        glBlendFunc(GL_ONE, GL_ONE);                    // 把紋理1複製到螢幕
        glBindTexture(GL_TEXTURE_2D, texture[2]);                // 選擇第一個紋理
        glBegin(GL_QUADS);                            // 開始繪製四邊形
            glTexCoord2f(roll+0.0f, 0.0f); glVertex3f(-1.1f, -1.1f,  0.0f);   
            glTexCoord2f(roll+4.0f, 0.0f); glVertex3f( 1.1f, -1.1f,  0.0f);   
            glTexCoord2f(roll+4.0f, 4.0f); glVertex3f( 1.1f,  1.1f,  0.0f);   
            glTexCoord2f(roll+0.0f, 4.0f); glVertex3f(-1.1f,  1.1f,  0.0f);   
        glEnd();           
    }

  
 接下來啟用深度測試,禁用混合。 
  

    glEnable(GL_DEPTH_TEST);                            // 啟用深度測試
    glDisable(GL_BLEND);                            // 禁用混合

  
 最後增加roll變數,如果大於1,把它的值減1。 
  

    roll+=0.002f;                                // 增加紋理滾動變數
    if (roll>1.0f)                                // 大於1則減1
    {
        roll-=1.0f;                       
    }

    return TRUE;                                // 成功返回
}

  
 函數KillGLWindow(), CreateGLWindow() 和 WndProc() 沒有改變。
 
  
  
 接下來在wWinMain,我們添加鍵盤控制函數。我們檢查空格是否按下,如果是則設定sp變數為TRUE,sp變數用來切換情境。 
  

                if (keys[' '] && !sp)                // 空格鍵是否被按下?
                {
                    sp=TRUE;               
                    scene=!scene;                // 是則切換情境
                }

  
 如果空格鍵釋放,記錄下來 
  

                if (!keys[' '])                    // 如果空格鍵釋放,記錄下來
                {
                    sp=FALSE;               
                }

  
 我們檢查M鍵是否按下,如果是則設定mp變數為TRUE,sp變數用來切換是否使用“掩模” 
  

                if (keys['M'] && !mp)                // M鍵是否被按下
                {
                    mp=TRUE;               
                    masking=!masking;                // 是則切換“掩模”
                }

  
 如果M鍵釋放,記錄下來 
  

                if (!keys['M'])                    // 如果M鍵釋放,記錄下來
                {
                    mp=FALSE;               
                }

  
 Eric Desrosiers指出,你也可以在載入的時候測試*.bmp映像中的每一個像素,如果你你想要透明的結果,你可以把顏色的alpha設定為0。對於其他的顏色,你可以把alpha設定為1。這個方法也能達到同樣的效果,但需要一些額外的代碼。
在這課裡,我們給你示範了一個簡單的例子,它能高效的繪製一部分紋理而不使用alpha值。

謝謝Rob Santa的想法和例子程式,我從沒想到過這種方法。

我希望你喜歡這個教程,如果你在理解上有任何問題或找到了任何錯誤,請我知道,我想做最好的教程,你的反饋是非常重要的。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.