OpenGL使用紋理繪制金字塔

在前面的例子中我們繪制過金字塔重荠,但是我們填充的顏色是綠色的如下圖:


金字塔

今天我們將要在金字塔各個面上使用紋理繪制上相應(yīng)的像素?cái)?shù)據(jù),如下圖:


紋理填充金字塔

這次我們將要用到上節(jié)講的紋理相關(guān)APi了条篷。
首先看下執(zhí)行流程:

main函數(shù)——>SetupRC函數(shù)——>LoadTGATexture函數(shù)——>MakePyramid函數(shù)——>ChangeSize函數(shù)——>RenderScene函數(shù)——>ShutdownRC函數(shù)

在我們控制旋轉(zhuǎn)或者別的操作的時候會多次調(diào)用RenderScene函數(shù)來重新渲染:
簡單說下幾個函數(shù)的作用

main:這個不用多說侮叮,程序入口

int main(int argc, char* argv[])
{
    gltSetWorkingDirectory(argv[0]);
    
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
    glutInitWindowSize(800, 600);
    glutCreateWindow("Pyramid");
    glutReshapeFunc(ChangeSize);
    glutSpecialFunc(SpecialKeys);
    glutDisplayFunc(RenderScene);
    
    GLenum err = glewInit();
    if (GLEW_OK != err) {
        fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
        return 1;
    }
    
    
    SetupRC();
    
    glutMainLoop();
    
    ShutdownRC();
    
    return 0;
}

SetupRC:初始化數(shù)據(jù)

Void SetupRC()
{
    //1.
    glClearColor(0.7f, 0.7f, 0.7f, 1.0f );
    shaderManager.InitializeStockShaders();
    
    //2.
    glEnable(GL_DEPTH_TEST);
    
    //3.
    //分配紋理對象 參數(shù)1:紋理對象個數(shù),參數(shù)2:紋理對象指針
    glGenTextures(1, &textureID);
    
    //綁定紋理狀態(tài) 參數(shù)1:紋理狀態(tài)2D 參數(shù)2:紋理對象
    glBindTexture(GL_TEXTURE_2D, textureID);
    
    //將TGA文件加載為2D紋理寡润。
    //參數(shù)1:紋理文件名稱
    //參數(shù)2&參數(shù)3:需要縮小&放大的過濾器
    //參數(shù)4:紋理坐標(biāo)環(huán)繞模式
    LoadTGATexture("stone.tga", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR, GL_CLAMP_TO_EDGE);
    
    //4.創(chuàng)造金字塔pyramidBatch
    MakePyramid(pyramidBatch);
    
    //5.
    /**相機(jī)frame MoveForward(平移)
    參數(shù)1:Z我注,深度(屏幕到圖形的Z軸距離)
     */
    cameraFrame.MoveForward(-10);
}

LoadTGATexture:加載紋理

// 將TGA文件加載為2D紋理按咒。
bool LoadTGATexture(const char *szFileName, GLenum minFilter, GLenum magFilter, GLenum wrapMode)
{
    GLbyte *pBits;
    int nWidth, nHeight, nComponents;
    GLenum eFormat;
    
    //1、讀紋理位但骨,讀取像素
    //參數(shù)1:紋理文件名稱
    //參數(shù)2:文件寬度地址
    //參數(shù)3:文件高度地址
    //參數(shù)4:文件組件地址
    //參數(shù)5:文件格式地址
    //返回值:pBits,指向圖像數(shù)據(jù)的指針
    
    pBits = gltReadTGABits(szFileName, &nWidth, &nHeight, &nComponents, &eFormat);
    if(pBits == NULL)
        return false;
    
    //2励七、設(shè)置紋理參數(shù)
    //參數(shù)1:紋理維度
    //參數(shù)2:為S/T坐標(biāo)設(shè)置模式
    //參數(shù)3:wrapMode,環(huán)繞模式
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode);
    
    //參數(shù)1:紋理維度
    //參數(shù)2:線性過濾
    //參數(shù)3: 縮小/放大過濾方式.
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);
    

    //3.載入紋理
    //參數(shù)1:紋理維度
    //參數(shù)2:mip貼圖層次
    //參數(shù)3:紋理單元存儲的顏色成分(從讀取像素圖是獲得)
    //參數(shù)4:加載紋理寬
    //參數(shù)5:加載紋理高
    //參數(shù)6:加載紋理的深度
    //參數(shù)7:像素?cái)?shù)據(jù)的數(shù)據(jù)類型(GL_UNSIGNED_BYTE智袭,每個顏色分量都是一個8位無符號整數(shù))
    //參數(shù)8:指向紋理圖像數(shù)據(jù)的指針
    
    glTexImage2D(GL_TEXTURE_2D, 0, nComponents, nWidth, nHeight, 0,
                 eFormat, GL_UNSIGNED_BYTE, pBits);
    
    //使用完畢釋放pBits
    free(pBits);
    
    //只有minFilter 等于以下四種模式,才可以生成Mip貼圖
    //GL_NEAREST_MIPMAP_NEAREST具有非常好的性能掠抬,并且閃爍現(xiàn)象非常弱
    //GL_LINEAR_MIPMAP_NEAREST常常用于對游戲進(jìn)行加速吼野,它使用了高質(zhì)量的線性過濾器
    //GL_LINEAR_MIPMAP_LINEAR 和GL_NEAREST_MIPMAP_LINEAR 過濾器在Mip層之間執(zhí)行了一些額外的插值,以消除他們之間的過濾痕跡两波。
    //GL_LINEAR_MIPMAP_LINEAR 三線性Mip貼圖瞳步。紋理過濾的黃金準(zhǔn)則,具有最高的精度腰奋。
    if(minFilter == GL_LINEAR_MIPMAP_LINEAR ||
       minFilter == GL_LINEAR_MIPMAP_NEAREST ||
       minFilter == GL_NEAREST_MIPMAP_LINEAR ||
       minFilter == GL_NEAREST_MIPMAP_NEAREST)
    //4.紋理生成所有的Mip層
    //參數(shù):GL_TEXTURE_1D单起、GL_TEXTURE_2D、GL_TEXTURE_3D
    glGenerateMipmap(GL_TEXTURE_2D);
 
    return true;
}

MakePyramid:設(shè)置金字塔頂點(diǎn)數(shù)據(jù)及紋理坐標(biāo)

//繪制金字塔
void MakePyramid(GLBatch& pyramidBatch)
{
    /*1劣坊、通過pyramidBatch組建三角形批次
      參數(shù)1:類型
      參數(shù)2:頂點(diǎn)數(shù)
      參數(shù)3:這個批次中將會應(yīng)用1個紋理
      注意:如果不寫這個參數(shù)馏臭,默認(rèn)為0。
     */
    pyramidBatch.Begin(GL_TRIANGLES, 18, 1);
    
    /***前情導(dǎo)入
     
     2)設(shè)置紋理坐標(biāo)
     void MultiTexCoord2f(GLuint texture, GLclampf s, GLclampf t);
     參數(shù)1:texture讼稚,紋理層次,對于使用存儲著色器來進(jìn)行渲染绕沈,設(shè)置為0
     參數(shù)2:s:對應(yīng)頂點(diǎn)坐標(biāo)中的x坐標(biāo)
     參數(shù)3:t:對應(yīng)頂點(diǎn)坐標(biāo)中的y
     (s,t,r,q對應(yīng)頂點(diǎn)坐標(biāo)的x,y,z,w)
     
     pyramidBatch.MultiTexCoord2f(0,s,t);
     
     3)void Vertex3f(GLfloat x, GLfloat y, GLfloat z);
      void Vertex3fv(M3DVector3f vVertex);
     向三角形批次類添加頂點(diǎn)數(shù)據(jù)(x,y,z);
      pyramidBatch.Vertex3f(-1.0f, -1.0f, -1.0f);
    
     */
    
    //塔頂
    M3DVector3f vApex = { 0.0f, 1.0f, 0.0f };
    M3DVector3f vFrontLeft = { -1.0f, -1.0f, 1.0f };
    M3DVector3f vFrontRight = { 1.0f, -1.0f, 1.0f };
    M3DVector3f vBackLeft = { -1.0f,  -1.0f, -1.0f };
    M3DVector3f vBackRight = { 1.0f,  -1.0f, -1.0f };
    
    //金字塔底部
    //底部的四邊形 = 三角形X + 三角形Y
    //三角形X = (vBackLeft,vBackRight,vFrontRight)
    //vBackLeft
    pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
    pyramidBatch.Vertex3fv(vBackLeft);
    
    //vBackRight
    pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
    pyramidBatch.Vertex3fv(vBackRight);
    
    //vFrontRight
    pyramidBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
    pyramidBatch.Vertex3fv(vFrontRight);
    
    
    //三角形Y =(vFrontLeft,vBackLeft,vFrontRight)
    //vFrontLeft
    pyramidBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
    pyramidBatch.Vertex3fv(vFrontLeft);
    
    //vBackLeft
    pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
    pyramidBatch.Vertex3fv(vBackLeft);
    
    //vFrontRight
    pyramidBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
    pyramidBatch.Vertex3fv(vFrontRight);

    
    // 金字塔前面
    //三角形:(Apex锐想,vFrontLeft,vFrontRight)
    pyramidBatch.MultiTexCoord2f(0, 0.5f, 1.0f);
    pyramidBatch.Vertex3fv(vApex);

    pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
    pyramidBatch.Vertex3fv(vFrontLeft);

    pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
    pyramidBatch.Vertex3fv(vFrontRight);
    
    //金字塔左邊
    //三角形:(vApex, vBackLeft, vFrontLeft)
    pyramidBatch.MultiTexCoord2f(0, 0.5f, 1.0f);
    pyramidBatch.Vertex3fv(vApex);
    
    pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
    pyramidBatch.Vertex3fv(vBackLeft);
    
    pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
    pyramidBatch.Vertex3fv(vFrontLeft);
    
    //金字塔右邊
    //三角形:(vApex, vFrontRight, vBackRight)
    pyramidBatch.MultiTexCoord2f(0, 0.5f, 1.0f);
    pyramidBatch.Vertex3fv(vApex);
    
    pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
    pyramidBatch.Vertex3fv(vFrontRight);

    pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
    pyramidBatch.Vertex3fv(vBackRight);
    
    //金字塔后邊
    //三角形:(vApex, vBackRight, vBackLeft)
    pyramidBatch.MultiTexCoord2f(0, 0.5f, 1.0f);
    pyramidBatch.Vertex3fv(vApex);
    
    pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
    pyramidBatch.Vertex3fv(vBackRight);
    
    pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
    pyramidBatch.Vertex3fv(vBackLeft);
    
    //結(jié)束批次設(shè)置
    pyramidBatch.End();
}

在這函數(shù)中我們要把紋理坐標(biāo)和三角形坐標(biāo)相對應(yīng):


紋理坐標(biāo)和實(shí)際坐標(biāo)映射圖

因?yàn)榻鹱炙?個面乍狐,且底面是兩個三角形組成赠摇,所以上述代碼中我們設(shè)置了5個三角形對應(yīng)的紋理坐標(biāo);


金字塔的各個面與紋理的映射

RenderScene:渲染函數(shù)浅蚪,綁定紋理藕帜、繪制金字塔

void RenderScene(void)
{
    //1.顏色值&光源位置
    static GLfloat vLightPos [] = { 1.0f, 1.0f, 0.0f };
    static GLfloat vWhite [] = { 1.0f, 1.0f, 1.0f, 1.0f };
    
    //2.清理緩存區(qū)
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    
    //3.當(dāng)前模型視頻壓棧
    modelViewMatrix.PushMatrix();
    
    //添加照相機(jī)矩陣
    M3DMatrix44f mCamera;
    //從camraFrame中獲取一個4*4的矩陣
    cameraFrame.GetCameraMatrix(mCamera);
    //矩陣乘以矩陣堆棧頂部矩陣,相乘結(jié)果存儲到堆棧的頂部 將照相機(jī)矩陣 與 當(dāng)前模型矩陣相乘 壓入棧頂
    modelViewMatrix.MultMatrix(mCamera);
    
    //創(chuàng)建mObjectFrame矩陣
    M3DMatrix44f mObjectFrame;
    //從objectFrame中獲取矩陣惜傲,objectFrame保存的是特殊鍵位的變換矩陣
    objectFrame.GetMatrix(mObjectFrame);
    //矩陣乘以矩陣堆棧頂部矩陣洽故,相乘結(jié)果存儲到堆棧的頂部 將世界變換矩陣 與 當(dāng)前模型矩陣相乘 壓入棧頂
    modelViewMatrix.MultMatrix(mObjectFrame);
    
    //4.綁定紋理,因?yàn)槲覀兊捻?xiàng)目中只有一個紋理盗誊。如果有多個紋理时甚。綁定紋理很重要
    glBindTexture(GL_TEXTURE_2D, textureID);
    
    //5.紋理替換矩陣著色器
     /*
     參數(shù)1:GLT_SHADER_TEXTURE_REPLACE(著色器標(biāo)簽)
     參數(shù)2:模型視圖投影矩陣
     參數(shù)3:紋理層
     */
    
    shaderManager.UseStockShader(GLT_SHADER_TEXTURE_REPLACE, transformPipeline.GetModelViewProjectionMatrix(), 0);
    
    //pyramidBatch 繪制
    pyramidBatch.Draw();
    
    //模型視圖出棧,恢復(fù)矩陣(push一次就要pop一次)
    modelViewMatrix.PopMatrix();
    
    //6.交換緩存區(qū)
    glutSwapBuffers();
}

SpecialKeys:圖形根據(jù)特殊鍵位的出發(fā)進(jìn)行旋轉(zhuǎn)

void SpecialKeys(int key, int x, int y)
{
    if(key == GLUT_KEY_UP)
        objectFrame.RotateWorld(m3dDegToRad(-5.0f), 1.0f, 0.0f, 0.0f);
    
    if(key == GLUT_KEY_DOWN)
        objectFrame.RotateWorld(m3dDegToRad(5.0f), 1.0f, 0.0f, 0.0f);
    
    if(key == GLUT_KEY_LEFT)
        objectFrame.RotateWorld(m3dDegToRad(-5.0f), 0.0f, 1.0f, 0.0f);
    
    if(key == GLUT_KEY_RIGHT)
        objectFrame.RotateWorld(m3dDegToRad(5.0f), 0.0f, 1.0f, 0.0f);
    
    glutPostRedisplay();
}

ShutdownRC:清理數(shù)據(jù)哈踱,類似于iOS中的dealloc函數(shù)

// 清理…例如刪除紋理對象
void ShutdownRC(void)
{
    glDeleteTextures(1, &textureID);
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末荒适,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子开镣,更是在濱河造成了極大的恐慌刀诬,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件邪财,死亡現(xiàn)場離奇詭異陕壹,居然都是意外死亡质欲,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進(jìn)店門帐要,熙熙樓的掌柜王于貴愁眉苦臉地迎上來把敞,“玉大人,你說我怎么就攤上這事榨惠》茉纾” “怎么了?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵赠橙,是天一觀的道長耽装。 經(jīng)常有香客問我,道長期揪,這世上最難降的妖魔是什么掉奄? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮凤薛,結(jié)果婚禮上姓建,老公的妹妹穿的比我還像新娘。我一直安慰自己缤苫,他們只是感情好速兔,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著活玲,像睡著了一般涣狗。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上舒憾,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天镀钓,我揣著相機(jī)與錄音,去河邊找鬼镀迂。 笑死丁溅,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的探遵。 我是一名探鬼主播唧瘾,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼别凤!你這毒婦竟也來了饰序?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤规哪,失蹤者是張志新(化名)和其女友劉穎求豫,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蝠嘉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年最疆,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蚤告。...
    茶點(diǎn)故事閱讀 40,115評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡努酸,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出杜恰,到底是詐尸還是另有隱情获诈,我是刑警寧澤,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布心褐,位于F島的核電站舔涎,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏逗爹。R本人自食惡果不足惜亡嫌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望掘而。 院中可真熱鬧挟冠,春花似錦、人聲如沸袍睡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽女蜈。三九已至,卻和暖如春色瘩,著一層夾襖步出監(jiān)牢的瞬間伪窖,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工居兆, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留覆山,地道東北人。 一個月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓泥栖,卻偏偏與公主長得像簇宽,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子吧享,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評論 2 355