NeHe OpenGL教程 (十五)

來源:互聯網
上載者:User

第15課
  
  圖形字型的紋理映射:

這一課,我們將在上一課的基礎上建立帶有紋理的字型,它真的很簡單。
 
 在發布了前兩篇關於位元影像字型和輪廓字型的教程以後,我收到很多郵件,很多讀者都想知道如何才能給字型賦予紋理貼圖。你可以使用自動紋理座標產生器。它會為字型上的每一個多邊形產生紋理座標。
一個小注釋,這段代碼是專門針對Windows寫的,它使用了Windows的wgl函數來建立字型,顯然,Apple機系統有agl,X系統有glx來支援做同樣事情的,不幸的是,我不能保證這些代碼也是容易使用的。如果哪位有能在螢幕上顯示文字且獨立於平台的代碼,請告訴我,我將重寫一個有關字型的教程。

我們將使用第14課的代碼來創作紋理字型的示範。如果程式中哪部分的代碼有變化,我會重寫那部分的所有代碼以便看出我做的改動。

 我們還要添加一個叫做texture[]的整型變數。它用於儲存紋理。後面3行是第14課中的代碼,本課不做改動。
 
 下面的部分做了一些小改動。我打算在這課使用wingdings字型來顯示一個海盜旗(骷髏頭和十字骨頭)的標誌。如果你想顯示文字的話,就不用改動第14課中的代碼了,也可以選擇另一種字型。
有些人想知道如何使用wingdings字型,這也是我不用標準字型的一個原因。wingdings是一種符號字型,使用它時需要做一些改動。告訴Windows使用wingdings字型並不太簡單。如果你把字型的名字改為wingdings,你會注意到字型其實並沒有選到。你必須告訴Windows這種字型是一種符號字型而不是一種標準字元字型。後面會繼續解釋。

GLvoid BuildFont(GLvoid)                        // 建立位元影像字型
{
    GLYPHMETRICSFLOAT    gmf[256];                    // 記錄256個字元的資訊
    HFONT    font;                        // 字型控制代碼

    base = glGenLists(256);                    // 建立256個顯示列表
    font = CreateFont(    -12,                    // 字型高度
                0,                // 字型寬度
                0,                // 字型的旋轉角度 Angle Of Escapement
                0,                // 字型底線的旋轉角度Orientation Angle
                FW_BOLD,                // 字型的重量
                FALSE,                // 是否使用斜體
                FALSE,                // 是否使用底線
                FALSE,                // 是否使用刪除線

 這就是有魔力的那一行!不使用第14課中的ANSI_CHARSET,我們將使用SYMBOL_CHARSET。這會告訴Windows我們建立的字型並不是由標準字元組成的典型字型。所謂符號字型通常是由一些小圖片(符號)組成的。如果你忘了改變這行,wingdings,webdings以及你想用的其它符號字型就不會工作。
 
                SYMBOL_CHARSET,            // 設定字元集

 下面幾行沒有變化。
 
                OUT_TT_PRECIS,            // 輸出精度
                CLIP_DEFAULT_PRECIS,        // 裁剪精度
                ANTIALIASED_QUALITY,        // 輸出品質
                FF_DONTCARE|DEFAULT_PITCH,        // Family And Pitch
  
 既然我們已經選擇了符號字元集標識符,我們就可以選擇wingdings字型了 
  
                "Wingdings");            // 字型名稱
  
 剩下幾行代碼沒有變化 
 
    SelectObject(hDC, font);                    // 選擇建立的字型

    wglUseFontOutlines(    hDC,                // 設定當前視窗裝置描述表的控制代碼
                0,                // 用於建立顯示列表字型的第一個字元的ASCII值
                255,                // 字元數
                base,                // 第一個顯示列表的名稱

 我們允許有更多的誤差,這意味著GL不會嚴格的遵守字型的輪廓線。如果你把誤差設定為0.0f,你就會發現嚴格地在曲面上貼圖存在一些問題。但是如果你允許一定的誤差,很多問題都可以避免。
 
                0.1f,                // 字型的光滑度,越小越光滑,0.0為最光滑的狀態

 下面三行代碼還是相同的 
  
                0.2f,                // 在z方向突出的距離
                WGL_FONT_POLYGONS,            // 使用多邊形來產生字元,每個頂點具有獨立的法線
                gmf);                // 一個接收字形度量資料的數組的地址,每個數組元素用它對應的顯示列表字元的資料填充
}

 在ReSizeGLScene()函數之前,我們要加上下面一段代碼來讀取紋理。你可能會認得這些前幾課中的代碼。我們建立一個儲存位元影像的地方,讀取位元影像,告訴Windows產生一個紋理,並把它儲存在texture[0]中。
我們建立一種細化紋理(mipmapped texture),這樣會看起來好些。紋理的名字叫做lights.bmp。
 
if (TextureImage[0]=LoadBMP("Data/Lights.bmp"))            // 載入位元影像

 下面四行代碼將為我們繪製在螢幕上的任何物體自動產生紋理座標。函數glTexGen非常強大,而且複雜,如果要完全講清楚它的數學原理需要再寫一篇教程。不過,你只要知道GL_S和GL_T是紋理座標就可以了。預設狀態下,它被設定為提取物體此刻在螢幕上的x座標和y座標,並把它們轉換為頂點座標。你會發現到物體在z平面沒有紋理,只顯示一些斑紋。正面和反面都被賦予了紋理,這些都是由glTexGen函數產生的。(X(GL_S)用於從左至右映射紋理,Y(GL_T)用於從上到下映射紋理。
GL_TEXTURE_GEN_MODE允許我們選擇我們想在S和T紋理座標上使用的紋理映射模式。你有3種選擇:

GL_EYE_LINEAR - 紋理會固定在螢幕上。它永遠不會移動。物體將被賦予處於它通過的地區的那一塊紋理。

GL_OBJECT_LINEAR - 這種就是我們使用的模式。紋理被固定於在螢幕上運動的物體上。
GL_SPHERE_MAP - 每個人都喜歡。建立一種有金屬質感的物體。

        // 設定紋理映射模式
        glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
        glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
        glEnable(GL_TEXTURE_GEN_S);                // 使用自動產生紋理
        glEnable(GL_TEXTURE_GEN_T);       
  
 在InitGL()的最後有幾行新代碼。BuildFont()被放到了讀取紋理的代碼之後。glEnable(GL_COLOR_MATERIAL) 這行被刪掉了,如果你想使用glColor3f(r,g,b)來改變紋理的顏色,那麼就把glEnable(GL_COLOR_MATERIAL)這行重新加到這部分代碼中。 
  
int InitGL(GLvoid)                            // 此處開始對OpenGL進行所有設定
{
    if (!LoadGLTextures())                    // 載入紋理
    {
        return FALSE;                    // 失敗則返回
    }
    BuildFont();                        // 建立字型顯示列表

    glShadeModel(GL_SMOOTH);                    // 啟用陰影平滑
    glClearColor(0.0f, 0.0f, 0.0f, 0.5f);            // 黑色背景
    glClearDepth(1.0f);                    // 設定深度緩衝
    glEnable(GL_DEPTH_TEST);                    // 啟用深度測試
    glDepthFunc(GL_LEQUAL);                    // 所作深度測試的類型
    glEnable(GL_LIGHT0);                    // 使用第0號燈
    glEnable(GL_LIGHTING);                    // 使用光照
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);        // 告訴系統對透視進行修正
  
 啟動2D紋理映射,並選擇第一個紋理。這樣就把第一個紋理映射到我們繪製在螢幕上的3D物體上了。如果你想加入更多的操作,可以按自己的意願啟動或禁用紋理映射。 
  
    glEnable(GL_TEXTURE_2D);                    // 使用二維紋理
    glBindTexture(GL_TEXTURE_2D, texture[0]);            // 選擇使用的紋理
    return TRUE;                        // 初始化成功
}

 重設大小的代碼沒有變化,但DrawGLScene這部分代碼有變化。 
  
 這裡是第一處變動。我們打算使用COS和SIN讓物體繞著旋轉螢幕而不是把它固定在螢幕中間。我們將把物體向螢幕裡移動3個單位。在x軸,我們將移動範圍限制在-1.1到+1.1之間。我們使用rot變數來控制左右移動。我們把上下移動的範圍限制在+0.8到-0.8之間。同樣使用rot變數來控制上下移動(最好充分利用你的變數)。 
  
    // 設定字型的位置
    glTranslatef(1.1f*float(cos(rot/16.0f)),0.8f*float(sin(rot/20.0f)),-3.0f);

 下面做常規的旋轉。這會使符號在X,Y和Z軸旋轉。 
  
    glRotatef(rot,1.0f,0.0f,0.0f);                // 沿X軸旋轉
    glRotatef(rot*1.2f,0.0f,1.0f,0.0f);                // 沿Y軸旋轉
    glRotatef(rot*1.4f,0.0f,0.0f,1.0f);                // 沿Z軸旋轉

 我們將物體相對觀察點向左向下移動一點,以便於把符號定位於每個軸的中心。否則,當我們旋轉它的時候,看起來就不像是在圍繞它自己的中心在旋轉。-0.35隻是一個能讓符號正確顯示的數。我也試過一些其它數,因為我不知道這種字型的寬度是多少,可以適情況作出調整。我不知道為什麼這種字型沒有一個中心。 
  
    glTranslatef(-0.35f,-0.35f,0.1f);                // 移動到可以顯示的位置

 最後,我們繪製海盜旗的符號,然後增加rot變數,從而使這個符號在螢幕中旋轉和移動。如果你不知道我是如何從字母‘N’中得到海盜旗符號的,那就開啟Microsoft Word或是寫字板。在字型下拉式功能表中選擇Wingdings字型。輸入大寫字母‘N’,就會顯示出海盜旗符號了。 
  
    glPrint("N");                        // 繪製海盜旗符號
    rot+=0.1f;                        // 增加旋轉變數

 最後要做的事就是在KillGLWindow()的最後添加KillFont()函數,如下所示。添加這行代碼很重要。它將在我們退出程式之前做清理工作。
 
 儘管我沒有講的細緻入微,但我想你應該很好的理解了如何讓OpenGL為你產生紋理座標。在給你的字型或者是同類物體賦予紋理映射時,應該沒有問題了,而且只需要改變兩行代碼,你就可以啟用球體映射了,它的效果簡直酷斃了!

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.