• <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>
            posts - 131, comments - 12, trackbacks - 0, articles - 0
              C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

            OpenGL可以把紋理映射到指定的圖形的表面上。簡單一點的,就是給平面映射紋理,比如一個四邊形,一個長方體的6個面,都可以指定位圖作為紋理映射到各個面上。

            關于將一個位圖作為紋理映射到某個或者多個面上,可以學習Jeff Molofee的OpenGL系列教程。

            對于指定的多個紋理,要根據自己的需要映射到不同的面上,需要對位圖創建一個數組,用來存儲位圖的名稱,然后在初始化OpenGL的時候,可以讀取這些位圖,然后生成多個紋理存儲到一個紋理數組中,接著就可以指定繪制的某個面,對該指定的面進行紋理映射。

            下面,在的Jeff Molofee教程的第六課的基礎上,實現對6個面分別進行不同的紋理映射。

            準備工作就是制作6幅不同的位圖,如圖所示:


            關鍵代碼及其說明如下。

            創建全局紋理數組

            GLuint texture[6];   // 創建一個全局的紋理數組,用來存儲將位圖轉換之后得到的紋理,對應于立方體的6個面

            加載位圖文件

            加載位圖,也就是把位圖讀取到內存空間,實現紋理的創建,加載位圖的函數說明一下:

            AUX_RGBImageRec *LoadBMP(char *Filename)    // 根據位圖文件的名稱進行加載
            {
            FILE *File=NULL;        // 文件指針

            if (!Filename)         // 如果沒有指定位圖文件名稱就返回NULL
            {
               return NULL;         
            }

            File=fopen(Filename,"r");       // 根據指定的位圖文件名稱,打開該位圖文件

            if (File)           // 如果位圖文件存在
            {
               fclose(File);         // 因為只是需要判斷問題是否存在,而不需要對位圖文件進行寫操作,所以關閉位圖文件
               return auxDIBImageLoad(Filename);   // 其實,只需要一個真正存在的位圖文件的名稱,實現加載位圖文件,并返回一個指針
            }

            return NULL;          // 位圖文件加載失敗就返回NULL
            }

            上面實現加載位圖的函數中,AUX_RGBImageRec是glaux.h中定義的類型,該類型的定義如下所示:

            /*
            ** RGB Image Structure
            */

            typedef struct _AUX_RGBImageRec {
                GLint sizeX, sizeY;
                unsigned char *data;
            } AUX_RGBImageRec;

            首先,AUX_RGBImageRec類型是一個RGB圖像結構類型。該結構定義了三個成員:

            sizeX —— 圖像的寬度;
            sizeY —— 圖像的高度;
            data; —— 圖形所包含的數據,其實也就是該圖形在內存中的像素數據的一個指針。

            AUX_RGBImageRec類型的變量描述了一幅圖像的特征。

            上述函數中,調用了glaux.h庫文件中的auxDIBImageLoad函數,其實它是一個宏,函數原型為auxRGBImageLoadW(LPCWSTR)或者auxRGBImageLoadA(LPCSTR),可以在該庫文件中找到它的定義,如下所示:

            /* AUX_RGBImageRec * APIENTRY auxRGBImageLoad(LPCTSTR); */
            #ifdef UNICODE
            #define auxRGBImageLoad auxRGBImageLoadW
            #else
            #define auxRGBImageLoad auxRGBImageLoadA
            #endif
            AUX_RGBImageRec * APIENTRY auxRGBImageLoadA(LPCSTR);
            AUX_RGBImageRec * APIENTRY auxRGBImageLoadW(LPCWSTR);

            #ifdef UNICODE
            #define auxDIBImageLoad auxDIBImageLoadW
            #else
            #define auxDIBImageLoad auxDIBImageLoadA
            #endif
            AUX_RGBImageRec * APIENTRY auxDIBImageLoadA(LPCSTR);
            AUX_RGBImageRec * APIENTRY auxDIBImageLoadW(LPCWSTR);

            宏auxDIBImageLoad實現的功能就是:根據指定的位圖名稱,將該位圖的信息加載到內存中,以便用來創建成為紋理。

            創建紋理并加載紋理

            用于創建并加載紋理的函數為LoadGLTextures,實現如下所示:

            int LoadGLTextures()         // 根據加載的位圖創建紋理
            {
            int Status=FALSE;         // 指示紋理創建是否成功的標志

            AUX_RGBImageRec *TextureImage[6];     // 創建一個紋理圖像數組,這里指定數組大小為6

            memset(TextureImage,0,sizeof(void *)*6);          // 初始化紋理圖像數組,為其分配內存

            char *pictures[] = {// 創建一個位圖名稱數組,對應6幅位圖
               "Data/No1.bmp",
               "Data/No2.bmp",
               "Data/No3.bmp",
               "Data/No4.bmp",
               "Data/No5.bmp",
               "Data/No6.bmp"
            };
            for(int i=0; i<6; i++)// 遍歷位圖名稱數組,根據位圖名稱分別生成
            {
               if (TextureImage[i]=LoadBMP(pictures[i]))// 加載位圖i成功,修改狀態標志變量Status為TRUE
               {
                Status=TRUE;         

               glGenTextures(1, &texture[i]);     // 為第i個位圖創建紋理
               glBindTexture(GL_TEXTURE_2D, texture[i]);// 將生成的紋理的名稱綁定到指定的紋理上
               glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[i]->sizeX, TextureImage[i]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[i]->data);
               glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
                glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
               }

               if (TextureImage[i])         // 釋放位圖數組占用的內存空間
               {
                if (TextureImage[i]->data)       
                {
                 free(TextureImage[i]->data);    
                }

                free(TextureImage[i]);        
               }
            }
            return Status;          // 創建紋理并加載,返回成功或者失敗的標志Status
            }

            上述函數是創建和加載紋理的核心實現。

            1、glGenTextures函數

            其中,調用了glGenTextures函數,查看MSDN可以看到,聲明如下所示:

            void glGenTextures(
            GLsizein,         
            GLuint *textures  
            );

            函數參數的含義:

            n—— 生成的紋理的名稱的個數;

            textures—— 生成的紋理名稱所存儲位置的指針,也就是一個紋理數組的內存地址,或者說是數組首元素的內存地址。

            函數被調用,會生成一系列紋理的名字,并存儲到指定的數組中。

            2、glBindTexture函數

            glBindTexture函數實現了將調用glGenTextures函數生成的紋理的名字綁定到對應的目標紋理上。該函數的聲明如下所示:

            void glBindTexture(
            GLenumtarget,  
            GLuinttexture  
            );

            函數參數的含義:

            target—— 紋理被綁定的目標,它只能取值GL_TEXTURE_1D或者GL_TEXTURE_2D;

            texture—— 紋理的名稱,并且,該紋理的名稱在當前的應用中不能被再次使用。

            3、glTexImage2D函數

            調用glTexImage2D函數,用來指定二維紋理圖像。該函數的聲明如下所示:

            void glTexImage2D(
            GLenumtarget,       
            GLintlevel,         
            GLintcomponents,    
            GLsizeiwidth,       
            GLsizeiheight,      
            GLintborder,        
            GLenumformat,       
            GLenumtype,         
            const GLvoid*pixels
            );

            函數參數的含義:

            target—— 指定目標紋理,必須為GL_TEXTURE_2D;

            level—— 指定圖像級別的編號,0表示基本圖像,其它可以參考MSDN;

            components—— 紋理中顏色組件的編號,可是是1或2或3或4;

            width—— 紋理圖像的寬度;

            height—— 紋理圖像的高度;

            border—— 紋理圖像的邊框寬度,必須是0或1;

            format—— 指定像素數據的格式,一共有9個取值:GL_COLOR_INDEX、GL_RED、GL_GREEN、GL_BLUE、GL_ALPHA、GL_RGB、GL_RGBA、GL_BGR_EXT、GL_BGRA_EXT、GL_LUMINANCE、GL_LUMINANCE_ALPHA ,具體含義可以參考MSDN;

            type—— 像素數據的數據類型,取值可以為GL_UNSIGNED_BYTE, GL_BYTE, GL_BITMAP, GL_UNSIGNED_SHORT, GL_SHORT, GL_UNSIGNED_INT, GL_INT, and GL_FLOAT;

            pixels—— 內存中像素數據的指針。

            4、glTexParameteri函數

            glTexParameteri函數或者glTexParameterf函數用來設置紋理參數,聲明如下所示:

            void glTexParameterf(
            GLenumtarget,
            GLenumpname,
            GLfloatparam
            );

            void glTexParameteri(
            GLenumtarget,
            GLenumpname,
            GLintparam   
            );

            函數參數的含義:

            target—— 目標紋理,必須為GL_TEXTURE_1D或GL_TEXTURE_2D;

            pname—— 用來設置紋理映射過程中像素映射的問題等,取值可以為:GL_TEXTURE_MIN_FILTER、GL_TEXTURE_MAG_FILTER、GL_TEXTURE_WRAP_S、GL_TEXTURE_WRAP_T,詳細含義可以查看MSDN;

            param—— 實際上就是pname的值,可以參考MSDN。

            另外,該類函數還有兩個:

            void glTexParameterfv(
            GLenumtarget,        
            GLenumpname,         
            const GLfloat*params
            );

            void glTexParameteriv(
            GLenumtarget,      
            GLenumpname,       
            const GLint*params
            );

            上述程序中調用如下:

                glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
                glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

            功能就是實現線形濾波的功能,當紋理映射到圖形表面以后,如果因為其它條件的設置導致紋理不能更好地顯示的時候,進行過濾,按照指定的方式進行顯示,可能會過濾掉顯示不正常的紋理像素。

            紋理映射過程

            紋理映射的過程是在DrawGLScene函數中實現的,也就是在繪制圖形的過程中,直接進行我呢里映射,或者稱為,為指定的平面貼紋理,DrawGLScene函數實現如下所示:

            int DrawGLScene(GLvoid)         
            {
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
            glLoadIdentity();         
            glTranslatef(0.0f,0.0f,-5.0f);

            glRotatef(xrot,1.0f,0.0f,0.0f);
            glRotatef(yrot,0.0f,1.0f,0.0f);
            glRotatef(zrot,0.0f,0.0f,1.0f);


              // Front Face
            glBindTexture(GL_TEXTURE_2D, texture[0]);//   選擇第一個紋理texture[0],進行貼紋理
            glBegin(GL_QUADS);
              glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
               glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
               glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
               glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
            glEnd();

              // Back Face
            glBindTexture(GL_TEXTURE_2D, texture[1]);//   選擇第二個紋理texture[1],進行貼紋理
            glBegin(GL_QUADS);
               glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
               glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
               glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
               glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
            glEnd();

              // Top Face
            glBindTexture(GL_TEXTURE_2D, texture[2]);//   選擇第三個紋理texture[2],進行貼紋理
            glBegin(GL_QUADS);
               glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
               glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
               glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
               glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
            glEnd();

              // Bottom Face
            glBindTexture(GL_TEXTURE_2D, texture[3]);//   選擇第四個紋理texture[3],進行貼紋理
            glBegin(GL_QUADS);
               glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
               glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
               glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
               glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
            glEnd();

              // Right face
            glBindTexture(GL_TEXTURE_2D, texture[4]);//   選擇第五個紋理texture[4],進行貼紋理
            glBegin(GL_QUADS);
               glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
               glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
               glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
               glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
            glEnd();

              // Left Face
            glBindTexture(GL_TEXTURE_2D, texture[5]);//   選擇第六個紋理texture[5],進行貼紋理
            glBegin(GL_QUADS);
               glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
               glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
               glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
               glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
            glEnd();

            xrot+=0.3f;
            yrot+=0.2f;
            zrot+=0.4f;
            return TRUE;          
            }

            因為,通過前面的過程,已經將位圖加載并創建和加載紋理成功,紋理數組已經存在于內存之中,調用上述函數實現紋理映射,即,從內存中取出指定的紋理,將其映射到立方體的指定的面上。

            上述函數中調用了glTexCoord2f函數,設置紋理坐標,該函數的聲明如下所示:

            void glTexCoord2f(
            GLfloats,
            GLfloatt
            );

            glTexCoord2f 的第一個參數是X坐標,當s=0.0f 時是紋理的左側,s=0.5f 時是紋理的中點,s=1.0f 時是紋理的右側。 glTexCoord2f 的第二個參數是Y坐標,t=0.0f 是紋理的底部,t=0.5f 是紋理的中點, t=1.0f 是紋理的頂部。

            上述函數在為前面那個面映射紋理的時候調用如下:

               // Front Face
            glBindTexture(GL_TEXTURE_2D, texture[0]);
            glBegin(GL_QUADS);
               glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
               glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
               glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
               glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
            glEnd();

            其中:

            glTexCoord2f(0.0f, 0.0f);表示將紋理texture[0]的左下角坐標(0.0f, 0.0f)映射到立方體前面那個面的頂點(-1.0f, -1.0f, 1.0)上;

            glTexCoord2f(1.0f, 0.0f);表示將紋理texture[0]的右下角坐標(1.0f, 0.0f)映射到立方體前面那個面的頂點(1.0f, -1.0f, 1.0f)上;

            glTexCoord2f(1.0f, 1.0f);表示將紋理texture[0]的右上角坐標(1.0f, 1.0f)映射到立方體前面那個面的頂點(1.0f, 1.0f, 1.0f)上;

            glTexCoord2f(0.0f, 1.0f);表示將紋理texture[0]的左上角坐標(0.0f, 1.0f)映射到立方體前面那個面的頂點(-1.0f, 1.0f, 1.0f)上。

            這樣,紋理texture[0]就被映射到了立方體前面那個面上。

            紋理映射結果

            為了使立方體能夠運動起來,對立方體進行累的旋轉變換,而且,定義了三個全局變量:

            GLfloat xrot;    // 沿著x旋轉的變量
            GLfloat yrot;    // 沿著y旋轉的變量
            GLfloat zrot;   // 沿著z旋轉的變量

            初始化都為0,然后,在每次調用DrawGLScene函數的時候,改變x、y、z的分量值,在DrawGLScene函數中如下所示:

            xrot+=0.3f;
            yrot+=0.2f;
            zrot+=0.4f;

            在DrawGLScene函數中還要執行旋轉變換:

            glRotatef(xrot,1.0f,0.0f,0.0f);
            glRotatef(yrot,0.0f,1.0f,0.0f);
            glRotatef(zrot,0.0f,0.0f,1.0f);

            每次重繪都在改變旋轉軸,所以我們繪制的立方體能夠動起來,看到各個進行紋理映射的面的效果,如圖所示




            久久久久久久久久久精品尤物| 99久久久精品免费观看国产| 欧美色综合久久久久久| 久久久久久无码国产精品中文字幕| 亚洲?V乱码久久精品蜜桃 | 国产精品久久久久jk制服| 久久免费精品一区二区| 久久亚洲精品无码观看不卡| 人妻久久久一区二区三区| 人人狠狠综合久久亚洲88| 成人综合久久精品色婷婷| 久久99精品久久久久久hb无码| 精品久久久久中文字幕一区| 久久久久久综合网天天| 很黄很污的网站久久mimi色| 亚洲va国产va天堂va久久| 久久综合久久伊人| 72种姿势欧美久久久久大黄蕉| 亚洲国产成人乱码精品女人久久久不卡 | 亚洲午夜久久久久久久久电影网| 99久久久国产精品免费无卡顿| 无夜精品久久久久久| 93精91精品国产综合久久香蕉| 久久精品国产亚洲AV不卡| 久久久久国产成人精品亚洲午夜| 国产欧美久久一区二区| 久久人人爽人人爽人人片av高请| 日产久久强奸免费的看| 久久久久无码精品| 亚洲国产成人久久精品影视| 777米奇久久最新地址| 久久精品亚洲一区二区三区浴池| 一本久久综合亚洲鲁鲁五月天| 麻豆国内精品久久久久久| 久久精品二区| 日本加勒比久久精品| 亚洲国产天堂久久久久久| 午夜视频久久久久一区 | 精品久久久无码21p发布| 2021国内久久精品| 国产精品久久久久蜜芽|