青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

  C++博客 :: 首頁(yè) :: 聯(lián)系 ::  :: 管理
  163 Posts :: 4 Stories :: 350 Comments :: 0 Trackbacks

常用鏈接

留言簿(48)

我參與的團(tuán)隊(duì)

搜索

  •  

積分與排名

  • 積分 - 402524
  • 排名 - 59

最新評(píng)論

閱讀排行榜

評(píng)論排行榜

本教程由NeHe和Giuseppe D'Agata提供。
我知道每個(gè)人都或許厭惡字體。目前為止我寫的文字教程不僅能顯示文字,還能顯示3D文字,有紋理貼圖的文字,以及處理變量。但是當(dāng)你將你的作品移植到不支持位圖或是輪廓字體的機(jī)器上會(huì)發(fā)生什么事呢?

由于Giuseppe D'Agata我們有了另一篇字體教程。你還會(huì)問(wèn)什么?如果你記得在第一篇字體教程中我提到使用紋理在屏幕上繪制文字。通常當(dāng)你使用紋理繪制文字時(shí)你會(huì)調(diào)用你最喜歡的圖像處理程序,選擇一種字體,然后輸入你想顯示的文字或段落。然后你保存位圖并把它作為紋理讀入到你的程序里。對(duì)一個(gè)需要很多文字或是文字在不停變化的程序來(lái)說(shuō)這么做效率并不高。

本教程只使用有一個(gè)紋理來(lái)顯示任意256個(gè)不同的字符。記住平均一個(gè)字符只有16個(gè)像素寬,大概16個(gè)像素高。如果你使用標(biāo)準(zhǔn)的256x256的紋理那么很明顯你可以放入交叉的16個(gè)文字(即一個(gè)X),且最多16行16列。如果你需要一個(gè)更詳細(xì)的解釋:紋理是256個(gè)像素寬,一個(gè)字符是16個(gè)像素寬,256除以16得16:)

現(xiàn)在讓我們來(lái)創(chuàng)建一個(gè)2D紋理字體demo!這課的程序基于第一課的代碼。在程序的第一段,我們包括數(shù)學(xué)(math)和標(biāo)準(zhǔn)輸入輸出庫(kù)(stdio)。我們需要數(shù)學(xué)庫(kù)來(lái)使用正弦和余弦函數(shù)在屏幕上移動(dòng)我們的文字,我們需要標(biāo)準(zhǔn)輸入輸出庫(kù)來(lái)保證在我們制作紋理前要使用的位圖實(shí)際存在。

 
  
  
 我們將要加入一個(gè)變量base來(lái)指向我們的顯示列表。我們還加入texture[2]來(lái)保存我們將要?jiǎng)?chuàng)建的兩個(gè)紋理。Texture 1將是字體紋理,texture 2將是用來(lái)創(chuàng)建簡(jiǎn)單3D物體的凹凸紋理。
我們加入用來(lái)執(zhí)行循環(huán)的變量loop。最后我們加入用來(lái)繞屏幕移動(dòng)文字和旋轉(zhuǎn)3D物體的cnt1和cnt2。

 
  

GLuint    base;            // 繪制字體的顯示列表的開(kāi)始位置
GLuint    texture[2];        // 保存字體紋理
GLuint    loop;            // 通用循環(huán)變量

GLfloat    cnt1;            // 字體移動(dòng)計(jì)數(shù)器1
GLfloat    cnt2;            // 字體移動(dòng)計(jì)數(shù)器2

  
 接下來(lái)是讀取紋理代碼。這跟前面紋理影射教程中的一模一樣。 
  
  
 下面的代碼同樣對(duì)之前教程的代碼改動(dòng)很小。如果你不清楚下面每行的用途,回頭復(fù)習(xí)一下。
注意TextureImage[ ]將保存2個(gè)rgb圖像記錄。復(fù)查處理讀取或存儲(chǔ)紋理的紋理很重要。一個(gè)錯(cuò)誤的數(shù)字可能導(dǎo)致內(nèi)存溢出或崩潰! 
  

int LoadGLTextures()                            // 載入位圖(調(diào)用上面的代碼)并轉(zhuǎn)換成紋理
{
    int Status=FALSE;                            // 狀態(tài)指示器
    AUX_RGBImageRec *TextureImage[2];                    // 創(chuàng)建紋理的存儲(chǔ)空間

  
 下一行十分重要。如果你用別的數(shù)字替換2將發(fā)生嚴(yán)重問(wèn)題。再查一次!這個(gè)數(shù)字應(yīng)該與你在設(shè)置TextureImages[ ]時(shí)的數(shù)字相匹配。
我們將讀取的紋理是font.bmp 和bumps.bmp。第二個(gè)紋理可用任何你想用的紋理替換。我不是特別有創(chuàng)造性,所以我使的紋理可能有些單調(diào)。

 
  

memset(TextureImage,0,sizeof(void *)*2);                    // 將指針設(shè)為 NULL

    if ((TextureImage[0]=LoadBMP("Data/Font.bmp")) &&            // 載入字體圖像
        (TextureImage[1]=LoadBMP("Data/Bumps.bmp")))            // 載入紋理圖像
    {
        Status=TRUE;                        // 將 Status 設(shè)為 TRUE

  
 另一十分重要,要檢查兩遍的行。我無(wú)法開(kāi)始告訴你我收到多少email問(wèn)“為什么我只看到一個(gè)紋理,或?yàn)槭裁次业募y理是全白的!?!”通常問(wèn)題都出在這行。如果你用1替換2,那么將只創(chuàng)建一個(gè)紋理,第二個(gè)紋理將顯示為全白。如果你用3替換2,你的程序可能崩潰!
你應(yīng)該只調(diào)用glGenTextures()一次。調(diào)用glGenTextures()后你應(yīng)該創(chuàng)建你的所有紋理。我曾見(jiàn)過(guò)有人在每創(chuàng)建一個(gè)紋理前都加上一行g(shù)lGenTextures()。這通常導(dǎo)致新建的紋理覆蓋了你之前創(chuàng)建的。決定你需要?jiǎng)?chuàng)建多少個(gè)紋理是個(gè)好主意,調(diào)用glGenTextures()一次,然后創(chuàng)建所有的紋理。把glGenTextures()放進(jìn)循環(huán)是不明智的,除非你有自己的理由。

 
  

glGenTextures(2, &texture[0]);                            // 創(chuàng)建紋理

        for (loop=0; loop<2; loop++)                    // 循環(huán)設(shè)置所有的紋理
        {
            // 生成所有紋理
            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);
        }
    }

  
 下面的幾行代碼檢查我們讀取的位圖數(shù)據(jù)是否在內(nèi)存里。如果是,釋放內(nèi)存。注意我們還要檢查并釋放rgb圖像記錄。如果我們使用了3個(gè)不同的圖像來(lái)創(chuàng)建紋理,我們要檢查并釋放3個(gè)rgb圖像記錄。 
  

    for (loop=0; loop<2; loop++)
        {
            if (TextureImage[loop])                        // 紋理是否存在
            {
                if (TextureImage[loop]->data)            // 紋理圖像是否存在
                {
                    free(TextureImage[loop]->data);        // 釋放紋理圖像占用的內(nèi)存
                }
                free(TextureImage[loop]);                // 釋放圖像結(jié)構(gòu)
            }
        }
    return Status;                                // 返回 Status
}

  
 現(xiàn)在我們將創(chuàng)建字體。我將以同樣的細(xì)節(jié)來(lái)解釋這段代碼。這并沒(méi)那么復(fù)雜,但是有些數(shù)學(xué)要了解,我知道不是每個(gè)人都喜歡數(shù)學(xué)。 
  

GLvoid BuildFont(GLvoid)                                // 創(chuàng)建我們的字符顯示列表
{

  
 下面兩個(gè)變量將用來(lái)保存字體紋理中每個(gè)字的位置。cx將用來(lái)保存紋理中水平方向的位置,cy將用來(lái)保存紋理中豎直方向的位置。
 
  

float    cx;                                    // 字符的X坐標(biāo)
    float    cy;                                // 字符的Y坐標(biāo)
  
 接著我們告訴OpenGL我們要建立256個(gè)顯示列表。變量base將指向第一個(gè)顯示列表的位置。第二個(gè)顯示列表將是base+1,第三個(gè)是base+2,以此類推。
下面的第二行代碼選擇我們的字體紋理(texture[0])。
 
  

    base=glGenLists(256);                            // 創(chuàng)建256個(gè)顯示列表
    glBindTexture(GL_TEXTURE_2D, texture[0]);                    // 選擇字符圖象

  
 現(xiàn)在我們開(kāi)始循環(huán)。循環(huán)間創(chuàng)建所有的256個(gè)字符,每個(gè)存在它自己的顯示列表里。  
  

    for (loop=0; loop<256; loop++)                        // 循環(huán)256個(gè)顯示列表
    {

  
 下面的第一行或許看上去讓人有點(diǎn)困惑。%符號(hào)表示loop除以16的余數(shù)。cx將我們通過(guò)字體紋理從左至右移動(dòng)。你將注意到在后面的代碼中我們用1減去cy從而從上到下而不是從下到上移動(dòng)我們。%符號(hào)很難解釋,但我將嘗試去解釋。

我們真正關(guān)心的是(loop%16)。/16只是將結(jié)果轉(zhuǎn)化為紋理坐標(biāo)。所以如果loop等于16,cx將等于16/16的余數(shù)也就是0。但cy將等于16/16也就是1。所以我們將下移一個(gè)字符的高度,且我們將不往右移。如果loop等于17,cx將等于17/16也就是1.0625。余數(shù)0.625也等于1/16。意味著我們將右移一個(gè)字符。cy將仍是1因?yàn)槲覀冎魂P(guān)心小數(shù)點(diǎn)左邊的數(shù)字。18/16將右移2個(gè)字符,但仍下移一個(gè)字符。如果loop是32,cx將再次等于0,因?yàn)?2除以16沒(méi)有余數(shù),但cy將等于2。因?yàn)樾?shù)點(diǎn)左邊的數(shù)字現(xiàn)在是2,將下移2個(gè)字符。這么講清楚嗎?
 
  

        cx=float(loop%16)/16.0f;                    // 當(dāng)前字符的X坐標(biāo)
        cy=float(loop/16)/16.0f;                    // 當(dāng)前字符的Y坐標(biāo)

  
 Ok。現(xiàn)在我們通過(guò)從字體紋理中依據(jù)cx和cy的值選擇一個(gè)單獨(dú)的字符創(chuàng)建了2D字體。在下面的行里我們給base的值加上loop,若不這么做,每個(gè)字都將建在第一個(gè)顯示列表里。我們當(dāng)然不想要那樣的事發(fā)生,所以通過(guò)給base加上loop,我們創(chuàng)建的每個(gè)字都被存在下個(gè)可用的顯示列表里。 
  

        glNewList(base+loop,GL_COMPILE);                //開(kāi)始創(chuàng)建顯示列表

  
 現(xiàn)在我們已選擇了我們要?jiǎng)?chuàng)建的顯示列表,我們創(chuàng)建字符。這是通過(guò)繪制四邊形,然后給他貼上字體紋理中的單個(gè)字符的紋理來(lái)完成的。 
  

            glBegin(GL_QUADS);                    // 使用四邊形顯示每一個(gè)字符

  
 cx和cy應(yīng)該保存一個(gè)從0.0到1.0的非常小的浮點(diǎn)數(shù)。如果cx和cy同時(shí)為0,下面第一行的代碼將為:glTexCoord2f(0.0f,1-0.0f-0.0625f)。記得0.0625正是我們紋理的1/16,或者說(shuō)是一個(gè)字符的寬/高。下面的紋理坐標(biāo)將是我們紋理的左下角。
注意我們使用glVertex2i(x,y)而不是glVertex3f(x,y,z)。我們的字體是2D字體,所以我們不需要z值。因?yàn)槲覀兪褂玫氖钦煌队埃覀儾恍枰七M(jìn)屏幕。在一個(gè)正交投影平面繪圖你所需的是指定x和y坐標(biāo)。因?yàn)槲覀兊钠聊皇且韵袼匦问綇?到639(寬)從0到479(高),我們既不需用浮點(diǎn)數(shù)也不用負(fù)數(shù):)

我們?cè)O(shè)置正交投影屏幕的方式是,(0,0)將是屏幕的左下角,(640,480)是屏幕的右上角。x軸上0是屏幕的左邊界,639是右邊界。y軸上0時(shí)下便捷,479是上便捷。基本上我們避免了負(fù)坐標(biāo)。對(duì)那些不在乎透視,更愿意同像素而不是單元打交道的人來(lái)說(shuō)更方便:)
 
  

                glTexCoord2f(cx,1-cy-0.0625f);        // 左下角的紋理坐標(biāo)
                glVertex2i(0,0);                // 左下角的坐標(biāo)

  
 下一個(gè)紋理坐標(biāo)現(xiàn)在是上個(gè)紋理坐標(biāo)右邊1/16(剛好一個(gè)字符寬)。所以這將是紋理的右下角。
 
  

                glTexCoord2f(cx+0.0625f,1-cy-0.0625f);    // 右下角的紋理坐標(biāo)
                glVertex2i(16,0);                // 右下角的坐標(biāo)

  
 第三個(gè)紋理坐標(biāo)在我們的字符的最右邊,但上移了紋理的1/16(剛好一個(gè)字符高)。這將是一個(gè)單獨(dú)字符的右上角。 
  

                glTexCoord2f(cx+0.0625f,1-cy);        // 右上角的紋理坐標(biāo)
                glVertex2i(16,16);                // 右上角的坐標(biāo)

  
 最后我們左移來(lái)設(shè)置字符左上角的最后一個(gè)紋理坐標(biāo)。  
  

                glTexCoord2f(cx,1-cy);            // 左上角的紋理坐標(biāo)
                glVertex2i(0,16);                // 左上角的坐標(biāo)
            glEnd();                        // 四邊形字符繪制完成

  
 最終,我們右移了10個(gè)像素,置于紋理的右邊。如果我們不平移,文字將被繪制到各自的上面。由于我們的字體太窄,我們不想右移16個(gè)像素。如果那樣的話,每個(gè)字之間將有很大間隔。只移動(dòng)10個(gè)像素去除了間隔。  
  

            glTranslated(10,0,0);                    // 繪制完一個(gè)字符,向右平移16個(gè)單位
        glEndList();                            // 字符顯示列表結(jié)束
    }                                    // 循環(huán)建立256個(gè)顯示列表
}

  
 下面這段代碼與我們?cè)谄渌煮w教程中用來(lái)在程序退出前釋放顯示列表的相同。所有自base開(kāi)始的256個(gè)顯示列表都將被銷毀(這樣做很好!)。  
  

GLvoid KillFont(GLvoid)                               
{
    glDeleteLists(base,256);                        // 從內(nèi)存中刪除256個(gè)顯示列表
}

  
 下一段代碼將完成繪圖。一切都幾乎是新的,所以我將盡可能詳細(xì)的解釋每一行。一個(gè)小提示:很多都可加入這段代碼,像是變量的支持,字體大小、間距的調(diào)整,和很多為恢復(fù)到我們決定打印前的狀況所做的檢查。
glPrint()有三個(gè)參數(shù)。第一個(gè)是屏幕上x軸上的位置(從左至右的位置),下一個(gè)是y軸上的位置(從下到上...0是底部,越往上越大)。然后是字符串(我們想打印的文字),最后是一個(gè)叫做set的變量。如果你看過(guò)Giuseppe D'Agata制作的位圖,你會(huì)注意到有兩個(gè)不同的字符集。第一個(gè)字符集是普通的,第二個(gè)是斜體的。如果set為0,第一個(gè)字符集被選中。若set為1則選擇第二個(gè)字符集。
 
  

GLvoid glPrint(GLint x, GLint y, char *string, int set)                // 繪制字符
{

  
 我們要做的第一件事是確保set的值非0即1。如果set大于1,我們將使它等于1。  
  

    if (set>1)                                // 如果字符集大于1
    {
        set=1;                                // 設(shè)置其為1
    }

  
 現(xiàn)在我們選擇字體紋理。我們這么做是防止在我們決定往屏幕上輸出東西時(shí)選擇了不同的紋理。  
  

    glBindTexture(GL_TEXTURE_2D, texture[0]);                // 綁定為字體紋理

  
 現(xiàn)在我們禁用深度測(cè)試。我這么做是因?yàn)榛旌系男Ч麜?huì)更好。如果你不禁用深度測(cè)試,文字可能會(huì)被什么東西擋住,或得不到正確的混合效果。如果你不打算混合文字(那樣文字周圍的黑色區(qū)域就不會(huì)顯示)你可以啟用深度測(cè)試。  
  

    glDisable(GL_DEPTH_TEST);                        // 禁止深度測(cè)試

  
 下面幾行十分重要!我們選擇投影矩陣。之后使用一個(gè)叫做glPushMatrix()的命令。glPushMatrix存儲(chǔ)當(dāng)前矩陣(投影)。有些像計(jì)算器的存儲(chǔ)按鈕。 
  

    glMatrixMode(GL_PROJECTION);                        // 選擇投影矩陣
    glPushMatrix();                                // 保存當(dāng)前的投影矩陣

  
 現(xiàn)在我們保存了投影矩陣,重置矩陣并設(shè)置正交投影屏幕。第一和第三個(gè)數(shù)字(0)表示屏幕的底邊和左邊。如果愿意我們可以將屏幕的左邊設(shè)為-640,但如果不需要我們?yōu)槭裁匆O(shè)負(fù)數(shù)呢。第二和第四個(gè)數(shù)字表示屏幕的上邊和右邊。將這些值設(shè)為你當(dāng)前使用的分辨率是明智的做法。我們不需要用到深度,所以我們將z值設(shè)為-1與1。 
  

    glLoadIdentity();                                // 重置投影矩陣
    glOrtho(0,640,0,480,-1,1);                            // 設(shè)置正投影的可視區(qū)域

  
 現(xiàn)在我們選擇模型視點(diǎn)矩陣,用glPushMatrix()保存當(dāng)前設(shè)置。然后我們重置模型視點(diǎn)矩陣以便在正交投影視點(diǎn)下工作。  
  

    glMatrixMode(GL_MODELVIEW);                            // 選擇模型變換矩陣
    glPushMatrix();                                // 保存當(dāng)前的模型變換矩陣
    glLoadIdentity();                                // 重置模型變換矩陣

  
 在保存了透視參數(shù),設(shè)置了正交投影屏幕后,現(xiàn)在我們可以繪制文字了。我們從移動(dòng)到繪制文字的位置開(kāi)始。我們使用 glTranslated()而不是glTranslatef()因?yàn)槲覀兲幚淼氖窍袼兀愿↑c(diǎn)值并不重要。畢竟,你不可能用半個(gè)像素:)  
  

    glTranslated(x,y,0);                            // 把字符原點(diǎn)移動(dòng)到(x,y)位置

  
 下面這行選擇我們要使用的字符集。如果我們想使用第二個(gè)字符集,我們?cè)诋?dāng)前的顯示列表基數(shù)上加上128(128時(shí)我們256個(gè)字符的一半)。通過(guò)加上128,我們跳過(guò)了頭128個(gè)字符。 
  

    glListBase(base-32+(128*set));                        // 選擇字符集

  
 現(xiàn)在剩下的就是在屏幕上繪制文字了。我們同其它字體教程一樣來(lái)完成這步。我們使用glCallLists()。strlen(string)是字符串的長(zhǎng)度(我們想繪制多少字符),GL_UNSIGNED_BYTE意味著每個(gè)字符被表示為一個(gè)無(wú)符號(hào)字節(jié)(一個(gè)字節(jié)是一個(gè)從0到255的值)。最后,字符串保存我們想打印的文字。  
  

    glCallLists(strlen(string),GL_BYTE,string);                    // 把字符串寫入到屏幕

  
 現(xiàn)在我們所要做的是恢復(fù)透視視圖。我們選擇投影矩陣并用glPopMatrix()恢復(fù)我們先前用glPushMatrix()保存的設(shè)置。用相反的順序恢復(fù)設(shè)置很重要。
 
  

    glMatrixMode(GL_PROJECTION);                        // 選擇投影矩陣
    glPopMatrix();                                // 設(shè)置為保存的矩陣

  
 現(xiàn)在我們選擇模型視點(diǎn)矩陣,做相同的工作。我們使用glPopMatrix()恢復(fù)模型視點(diǎn)矩陣到我們?cè)O(shè)置正交投影顯示之前。  
  

    glMatrixMode(GL_MODELVIEW);                            // 選擇模型矩陣
    glPopMatrix();                                // 設(shè)置為保存的矩陣

  
 最后,我們啟用深度測(cè)試。如果你沒(méi)有在上面的代碼中關(guān)閉深度測(cè)試,你不需要這行。  
  

    glEnable(GL_DEPTH_TEST);                        // 啟用深度測(cè)試
}

  
 我們沒(méi)有修改ReSizeGLScene(),所以我們直接跳到InitGL()。
 
  

int InitGL(GLvoid)                                // 此處開(kāi)始對(duì)OpenGL進(jìn)行所有設(shè)置
{

  
 我們跳到創(chuàng)建紋理的代碼。如果由于某種原因創(chuàng)建紋理失敗了,我們返回FALSE。這將讓我們的程序知道發(fā)生了一個(gè)錯(cuò)誤從而關(guān)閉程序。 
  

    if (!LoadGLTextures())                            // 調(diào)用紋理載入子例程
    {
        return FALSE;                            // 如果未能載入,返回FALSE
    }

  
 如果沒(méi)有錯(cuò),我們跳到創(chuàng)建字體的代碼。在創(chuàng)建字體時(shí)不會(huì)出什么錯(cuò)所以我們省略了錯(cuò)誤檢查。
 
  

    BuildFont();                                // 創(chuàng)建字符顯示列表

  
 現(xiàn)在我們做通常的GL設(shè)置。我們將背景色設(shè)為黑色,將深度清為1.0。我們選擇一個(gè)深度測(cè)試模式和一個(gè)混合模式。我們啟用平滑著色,最后啟用2維紋理映射。 
  

    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);                    // 黑色背景
    glClearDepth(1.0);                                // 設(shè)置深度緩存
    glDepthFunc(GL_LEQUAL);                            // 所作深度測(cè)試的類型
    glBlendFunc(GL_SRC_ALPHA,GL_ONE);                        // 設(shè)置混合因子
    glShadeModel(GL_SMOOTH);                            // 啟用陰影平滑
    glEnable(GL_TEXTURE_2D);                            // 啟用紋理映射
    return TRUE;                                // 初始化成功
}

  
 下面這段代碼將完成繪圖。我們先繪制3D物體最后繪制文字,這樣文字將顯示在3D物體上面,而不會(huì)被3D物體遮住。我之所以加入一個(gè)3D物體是為了演示透視投影和正交投影可同時(shí)使用。 
  

int DrawGLScene(GLvoid)                                // 從這里開(kāi)始進(jìn)行所有的繪制
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);                // 清除屏幕和深度緩存
    glLoadIdentity();                                // 重置當(dāng)前的模型觀察矩陣

  
 我們選擇bumps.bmp紋理來(lái)創(chuàng)建簡(jiǎn)單的小3D物體。為了看見(jiàn)3D物體,我們往屏幕內(nèi)移動(dòng)5個(gè)單位。我們繞z軸旋轉(zhuǎn)45度。這將使我們的四邊形順時(shí)針旋轉(zhuǎn)45度,讓我們的四邊形看起來(lái)更像鉆石而不是矩形。 
  

    glBindTexture(GL_TEXTURE_2D, texture[1]);                    // 設(shè)置為圖像紋理
    glTranslatef(0.0f,0.0f,-5.0f);                        // 移入屏幕5個(gè)單位
    glRotatef(45.0f,0.0f,0.0f,1.0f);                        // 沿Z軸旋轉(zhuǎn)45度

  
 在旋轉(zhuǎn)45度后,我們讓物體同時(shí)繞x軸和y軸旋轉(zhuǎn)cnt1x30度。這使我們的物體象在一個(gè)點(diǎn)上旋轉(zhuǎn)的鉆石那樣旋轉(zhuǎn)。 
  

    glRotatef(cnt1*30.0f,1.0f,1.0f,0.0f);                    //  沿(1,1,0)軸旋轉(zhuǎn)30度

  
 我們關(guān)閉混合(我們希望3D物體看上去像實(shí)心的),設(shè)置顏色為亮白色。然后我們繪制一個(gè)單獨(dú)的用了紋理映像的四邊形。 
  

    glDisable(GL_BLEND);                            // 關(guān)閉混合
    glColor3f(1.0f,1.0f,1.0f);                            //設(shè)置顏色為白色
    glBegin(GL_QUADS);                                // 繪制紋理四邊形
        glTexCoord2d(0.0f,0.0f);                   
        glVertex2f(-1.0f, 1.0f);                   
        glTexCoord2d(1.0f,0.0f);                   
        glVertex2f( 1.0f, 1.0f);                   
        glTexCoord2d(1.0f,1.0f);                   
        glVertex2f( 1.0f,-1.0f);                   
        glTexCoord2d(0.0f,1.0f);                   
        glVertex2f(-1.0f,-1.0f);                   
    glEnd();                               
  
 在畫完第一個(gè)四邊形后,我們立即同時(shí)繞x軸和y軸旋轉(zhuǎn)90度。然后我們畫下一個(gè)四邊形,。第二個(gè)四邊形從第一個(gè)四邊形的中間切過(guò)去,來(lái)形成一個(gè)好看的形狀。 
  

    glRotatef(90.0f,1.0f,1.0f,0.0f);                    //  沿(1,1,0)軸旋轉(zhuǎn)90度
    glBegin(GL_QUADS);                            // 繪制第二個(gè)四邊形,與第一個(gè)四邊形垂直
        glTexCoord2d(0.0f,0.0f);                   
        glVertex2f(-1.0f, 1.0f);                   
        glTexCoord2d(1.0f,0.0f);                   
        glVertex2f( 1.0f, 1.0f);                   
        glTexCoord2d(1.0f,1.0f);                   
        glVertex2f( 1.0f,-1.0f);                   
        glTexCoord2d(0.0f,1.0f);                   
        glVertex2f(-1.0f,-1.0f);                   
    glEnd();                               
  
 在繪制完有紋理貼圖的四邊形后,我們開(kāi)啟混合并繪制文字。  
  

    glEnable(GL_BLEND);                            // 啟用混合操作
    glLoadIdentity();                                // 重置視口

  
 我們使用同其它字體教程一樣的生成很棒的顏色的代碼。顏色會(huì)隨著文字的移動(dòng)而逐漸改變。
 
  

    // 根據(jù)字體位置設(shè)置顏色
    glColor3f(1.0f*float(cos(cnt1)),1.0f*float(sin(cnt2)),1.0f-0.5f*float(cos(cnt1+cnt2)));

  
 我們來(lái)繪制文字。我們?nèi)匀皇褂胓lPrint()。第一個(gè)參數(shù)是x坐標(biāo),第二個(gè)是y坐標(biāo),第三個(gè)("NeHe")是要繪制的文字,最后一個(gè)是使用的字符集(0-普通,1-斜體)。
正如你猜的,我們使用SIN和COS連同計(jì)數(shù)器cnt1和cnt2來(lái)移動(dòng)文字。如果你不清楚SIN和COS的作用,閱讀之前的教程。
 
  

    glPrint(int((280+250*cos(cnt1))),int(235+200*sin(cnt2)),"NeHe",0);   

    glColor3f(1.0f*float(sin(cnt2)),1.0f-0.5f*float(cos(cnt1+cnt2)),1.0f*float(cos(cnt1)));
    glPrint(int((280+230*cos(cnt2))),int(235+200*sin(cnt1)),"OpenGL",1);   
  
 我們將屏幕底部作者名字的顏色設(shè)為深藍(lán)色和白色。然后用亮白色文字再次繪制他的名字。亮白色文字是有點(diǎn)偏藍(lán)色的文字。這創(chuàng)造出一種附有陰影的樣子。(如果混合沒(méi)打開(kāi)則沒(méi)有這種效果)。  
  

    glColor3f(0.0f,0.0f,1.0f);                       
    glPrint(int(240+200*cos((cnt2+cnt1)/5)),2,"Giuseppe D'Agata",0);   

    glColor3f(1.0f,1.0f,1.0f);                       
    glPrint(int(242+200*cos((cnt2+cnt1)/5)),2,"Giuseppe D'Agata",0);   
  
 我們所做的最后一件事是以不同的速率遞增我們的計(jì)數(shù)器。這使得文字移動(dòng),3D物體自轉(zhuǎn)。  
  

    cnt1+=0.01f;                                // 增加計(jì)數(shù)器值
    cnt2+=0.0081f;                                // 增加計(jì)數(shù)器值
    return TRUE;                                // 成功返回
}

  
 KillGLWindow(), CreateGLWindow()和WndProc()的代碼都沒(méi)有更改,所以我們跳過(guò)它們。 
  
  
 如下所示,最后要做的是在KillGLWindow()的最后添加KillFont()。添加這行很重要,它在我們退出程序前將所有的清除干凈。  
  

KillFont();                        // 刪除字體

  
 我認(rèn)為現(xiàn)在我可以正式說(shuō)我的網(wǎng)站已經(jīng)把所有繪制文字的方法教給大家了{(lán)笑}。總之,我認(rèn)為我的教程很不錯(cuò)。這課的代碼可在任何能運(yùn)行OpenGL的電腦上運(yùn)行,它很容易使用,且這樣繪制文字對(duì)系統(tǒng)的資源消耗很少。
我要感謝這篇教程的原作者Giuseppe D'Agata。我做了大量的修改,并將它轉(zhuǎn)變?yōu)樾率降拇a,但要是沒(méi)有他寄給我這份代碼我是不會(huì)完成這篇教程的。他的代碼有更多的選項(xiàng),像是改變文字間距等等。但我用很cool的3D物體來(lái)彌補(bǔ)了{(lán)笑}。

我希望你們喜歡這篇教程。若有什么問(wèn)題,給我或Giuseppe D'Agata發(fā)email。

Giuseppe D'Agata

Jeff Molofee (NeHe)

 


posted on 2007-12-15 12:06 sdfasdf 閱讀(2030) 評(píng)論(0)  編輯 收藏 引用 所屬分類: OPENGL
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            免费欧美视频| 一区二区三区回区在观看免费视频| 久久精品国产99国产精品| 一区二区欧美在线观看| 99re6热只有精品免费观看| 99热在这里有精品免费| 一区二区三区国产精品| 亚洲综合精品四区| 久久久精品tv| 欧美激情中文字幕一区二区| 欧美精品一区在线播放| 国产精品欧美一区喷水| 精品动漫3d一区二区三区| 亚洲国产欧美精品| 亚洲一级二级| 久久精品最新地址| 亚洲国产精品女人久久久| 亚洲伦理在线免费看| 亚洲一区成人| 美女视频黄免费的久久| 亚洲免费观看| 亚洲欧美日韩精品久久亚洲区 | 国产亚洲一区在线| 在线观看亚洲精品| 在线视频精品一区| 久久国产精品网站| 最新中文字幕一区二区三区| 亚洲女ⅴideoshd黑人| 欧美韩日视频| 一区二区在线观看av| 午夜国产精品影院在线观看| 欧美激情亚洲| 久久久精品一区| 国产欧美日韩一区| 亚洲综合国产精品| 亚洲区国产区| 久久综合伊人77777尤物| 国产精品日韩久久久久| 中国女人久久久| 亚洲黑丝在线| 欧美电影在线观看完整版| 国产亚洲视频在线| 欧美在线3区| 亚洲综合不卡| 国产欧美日韩精品在线| 亚洲香蕉伊综合在人在线视看| 欧美暴力喷水在线| 欧美中文字幕在线视频| 国产欧美日韩亚洲一区二区三区| 在线视频亚洲欧美| 日韩亚洲精品电影| 欧美三级黄美女| 一本色道久久综合亚洲精品不| 欧美成人综合一区| 美女视频网站黄色亚洲| 亚洲国产mv| 欧美激情中文不卡| 欧美精品性视频| 一本色道久久综合亚洲精品按摩 | 在线观看91精品国产麻豆| 久久精品国产免费看久久精品| 亚洲调教视频在线观看| 国产精品女主播| 欧美综合激情网| 久久成人免费视频| 亚洲观看高清完整版在线观看| 美女诱惑一区| 免费成人性网站| 日韩亚洲欧美成人| 一本色道久久综合亚洲精品小说| 欧美视频免费看| 欧美综合国产精品久久丁香| 欧美一级久久久| 极品尤物久久久av免费看| 一区二区三区在线观看欧美 | 亚洲精品美女久久久久| 欧美精选在线| 亚洲女同精品视频| 欧美主播一区二区三区| 亚洲国产欧美一区二区三区同亚洲 | 一本色道久久综合亚洲91| 一本大道久久a久久精二百| 国产精品久久久久婷婷| 久久免费高清| 欧美精品色网| 欧美一级淫片aaaaaaa视频| 久久九九精品99国产精品| 亚洲欧洲日本在线| 亚洲自拍偷拍色片视频| 在线日韩一区二区| 99精品热6080yy久久| 黄色成人av在线| 99精品国产99久久久久久福利| 国产日韩三区| 日韩午夜高潮| 亚洲国产成人在线| 亚洲一区二区三区四区五区午夜| 在线不卡欧美| 亚洲欧美精品在线| 亚洲精品日韩精品| 久久精品成人| 亚洲欧美视频在线观看视频| 久久一区二区三区国产精品| 亚洲综合欧美| 欧美日韩成人网| 亚洲第一区在线观看| 国产精品一区亚洲| 亚洲日本视频| 亚洲精品1区2区| 欧美一区二视频| 性欧美在线看片a免费观看| 欧美电影在线观看| 欧美~级网站不卡| 一区在线观看视频| 性色一区二区| 欧美一区二区三区视频| 欧美日韩另类综合| 91久久在线| 亚洲美女视频在线免费观看| 久久―日本道色综合久久| 久久九九久久九九| 国产女人精品视频| 亚洲制服丝袜在线| 午夜精品在线视频| 国产精品乱人伦一区二区| 一区二区三区回区在观看免费视频| 亚洲国产精品成人va在线观看| 欧美自拍偷拍| 久久一二三国产| 精品999在线播放| 久久精品亚洲国产奇米99| 久久视频这里只有精品| 韩日欧美一区| 久久久噜噜噜久久狠狠50岁| 久久亚洲高清| 久久久久综合一区二区三区| 欧美亚洲综合久久| 国产精品视频99| 中文亚洲免费| 亚洲欧美在线一区| 国产精品一区二区久久久久| 亚洲影院色无极综合| 先锋影音网一区二区| 国产亚洲精品bv在线观看| 欧美一区二区三区在线视频| 久久久999精品视频| 黄色资源网久久资源365| 久久午夜电影网| 91久久精品国产91久久| 99一区二区| 国产精品视频内| 久久久av毛片精品| 亚洲欧洲精品一区二区三区不卡 | 一区二区三区偷拍| 国产精品theporn88| 亚洲欧美大片| 免费亚洲一区二区| 夜夜狂射影院欧美极品| 国产精品久久久久av| 欧美一区二区三区四区在线观看地址 | 亚洲精品久久久久中文字幕欢迎你| 久久一区二区三区四区| 亚洲国产综合91精品麻豆| 亚洲一区二区三区在线看| 国产亚洲电影| 欧美福利视频| 亚洲综合视频网| 欧美大片免费观看| 亚洲在线网站| 在线日韩中文| 欧美日韩亚洲一区二区三区| 欧美一级精品大片| 亚洲日本电影| 久久夜色精品国产噜噜av| 亚洲视频免费| 亚洲成色777777女色窝| 国产精品v片在线观看不卡| 久久精品视频在线看| 一区二区精品在线观看| 美女图片一区二区| 西西裸体人体做爰大胆久久久| 亚洲高清影视| 国产无一区二区| 欧美三级韩国三级日本三斤| 久久综合精品国产一区二区三区| 夜夜躁日日躁狠狠久久88av| 噜噜噜久久亚洲精品国产品小说| 亚洲一区视频| 一本一本久久a久久精品牛牛影视| 国产在线欧美日韩| 国产精品女主播一区二区三区| 欧美成人资源网| 久久亚洲风情| 久久久久亚洲综合| 欧美在线观看www| 欧美亚洲在线观看| 亚洲欧美日韩一区在线| 亚洲毛片播放| 亚洲激情视频网| 久久精品国产999大香线蕉|