實(shí)現(xiàn)金字塔紋理

在一個(gè)金字塔圖形貼上紋理蝠引,示例程序代碼如下:

#include "GLTools.h"
#include "GLShaderManager.h"
#include "GLMatrixStack.h"
#include "GLFrustum.h"
#include "GLGeometryTransform.h"

//在Mac 系統(tǒng)下,`#include<glut/glut.h>` 在Windows 和 Linux上蛀柴,我們使?freeglut的靜態(tài)庫版本并且需要添加?個(gè)宏
#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif


GLShaderManager shaderManager; //著色器管理器
GLMatrixStack modelViewMatrix; //模型視圖矩陣
GLMatrixStack projectionMatrix; //投影矩陣
GLFrustum viewFrustum; //視景體
GLGeometryTransform transformPipeline; //幾何圖形變換管道
GLFrame cameraFrame; //照相機(jī)角色幀
GLFrame objectFrame;

GLuint textureID; //紋理變量螃概,一般使用無符號(hào)整型

GLBatch pyramidBatch;



//ChangeSize 函數(shù):?定義函數(shù).通過glutReshaperFunc(函數(shù)名)注冊為重塑函數(shù).當(dāng)屏幕??發(fā)?變化/或者第?次創(chuàng)建窗?時(shí),會(huì)調(diào)?該函數(shù)調(diào)整窗???/視???.
void ChangeSize(int w ,int h)
{
    //設(shè)置視口窗口尺寸
    glViewport(0, 0, w, h);
    
    //創(chuàng)建投影矩陣,
    viewFrustum.SetPerspective(35.0f, float(w)/float(h), 1.0f, 100.0f);
    //加載到投影矩陣堆棧上
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    
    //設(shè)置變換管道以使用兩個(gè)矩陣堆棧
    transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}


//將TGA文件加載為2D紋理鸽疾。
bool LoadTGATexture(const char *szFileName, GLenum minFilter, GLenum magFilter, GLenum wrapMode)
{
    GLbyte * pBits;
    int nWidth,nHeight,nComponents;
    GLenum eFormat;
    
    //讀紋理位吊洼,讀取像素
    //參數(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;
    }
    
    //設(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);
    
    //載入紋理
    //參數(shù)1:紋理維度
    //參數(shù)2:mip貼圖層次
    //參數(shù)3:紋理單元存儲(chǔ)的顏色成分(從讀取像素圖是獲得)
    //參數(shù)4:加載紋理寬
    //參數(shù)5:加載紋理高
    //參數(shù)6:加載紋理的深度
    //參數(shù)7:像素?cái)?shù)據(jù)的數(shù)據(jù)類型(GL_UNSIGNED_BYTE,每個(gè)顏色分量都是一個(gè)8位無符號(hào)整數(shù))
    //參數(shù)8:指向紋理圖像數(shù)據(jù)的指針
    glTexImage2D(GL_TEXTURE_2D, 0, nComponents, nWidth, nHeight, 0, eFormat, GL_UNSIGNED_BYTE, pBits);
    
    //使用完畢釋放pBits
    free(pBits);
    
    //加載Mip,紋理生成所有的Mip層
    //參數(shù):GL_TEXTURE_1D制肮、GL_TEXTURE_2D冒窍、GL_TEXTURE_3D
    glGenerateMipmap(GL_TEXTURE_2D);
    
    return true;
}


//繪制金字塔
void MakePyramid(GLBatch& pyramidBatch)
{
    /*1递沪、通過pyramidBatch組建三角形批次
     參數(shù)1:類型
     參數(shù)2:頂點(diǎn)數(shù)
     參數(shù)3:這個(gè)批次中將會(huì)應(yīng)用1個(gè)紋理
     注意:如果不寫這個(gè)參數(shù),默認(rèn)為0综液。
    */
    pyramidBatch.Begin(GL_TRIANGLES, 18, 1);
    
    /*
    1)設(shè)置法線
    void Normal3f(GLfloat x, GLfloat y, GLfloat z);
    Normal3f:添加一個(gè)表面法線(法線坐標(biāo) 與 Vertex頂點(diǎn)坐標(biāo)中的Y軸一致)
    表面法線是有方向的向量款慨,代表表面或者頂點(diǎn)面對的方向(相反的方向)。在多數(shù)的關(guān)照模式下是必須使用谬莹。
    
    pyramidBatch.Normal3f(X,Y,Z);
    
    2)設(shè)置紋理坐標(biāo)
    void MultiTexCoord2f(GLuint texture, GLclampf s, GLclampf t);
    參數(shù)1:texture檩奠,紋理層次,對于使用存儲(chǔ)著色器來進(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);
    
    
    4)獲取從三點(diǎn)找到一個(gè)法線坐標(biāo)(三點(diǎn)確定一個(gè)面)
    void m3dFindNormal(result,point1, point2,point3);
    參數(shù)1:結(jié)果
    參數(shù)2-4:3個(gè)頂點(diǎn)數(shù)據(jù)
    */
    
    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 };
    M3DVector3f n;
    
    //金字塔底部
    //底部的四邊形 = 三角形X + 三角形Y
    //三角形X = (vBackLeft,vBackRight,vFrontRight)
    
    //找到三角形X法線
    m3dFindNormal(n, vBackLeft, vBackRight, vFrontRight);
    
    //vBackLeft
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
    pyramidBatch.Vertex3fv(vBackLeft);
    
    //vBackRight
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
    pyramidBatch.Vertex3fv(vBackRight);
    
    //vFrontRight
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
    pyramidBatch.Vertex3fv(vFrontRight);
    
    //三角形Y =(vFrontLeft,vBackLeft,vFrontRight)
    
    //找到三角形Y法線
    m3dFindNormal(n, vFrontLeft, vBackLeft, vFrontRight);
    
    //vFrontLeft
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
    pyramidBatch.Vertex3fv(vFrontLeft);
    
    //vBackLeft
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
    pyramidBatch.Vertex3fv(vBackLeft);
    
    //vFrontRight
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
    pyramidBatch.Vertex3fv(vFrontRight);
    
    
    //金字塔前面
    //三角形:(Apex埠戳,vFrontLeft,vFrontRight)
    m3dFindNormal(n, vApex, vFrontLeft, vFrontRight);
    
    //Apex
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 0.5f, 1.0f);
    pyramidBatch.Vertex3fv(vApex);
    
    //vFrontLeft
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
    pyramidBatch.Vertex3fv(vFrontLeft);
    
    //vFrontRight
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
    pyramidBatch.Vertex3fv(vFrontRight);
    
    
    //金字塔左邊
    //三角形:(vApex, vBackLeft, vFrontLeft)
    m3dFindNormal(n, vApex, vBackLeft, vFrontLeft);
    
    //vApex
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 0.5f, 1.0f);
    pyramidBatch.Vertex3fv(vApex);
    
    //vBackLeft
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
    pyramidBatch.Vertex3fv(vBackLeft);
    
    //vFrontLeft
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
    pyramidBatch.Vertex3fv(vFrontLeft);
    
    
    //金字塔右邊
    //三角形:(vApex, vFrontRight, vBackRight)
    m3dFindNormal(n, vApex, vFrontRight, vBackRight);
    
    //vApex
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 0.5f, 1.0f);
    pyramidBatch.Vertex3fv(vApex);
    
    //vFrontRight
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
    pyramidBatch.Vertex3fv(vFrontRight);
    
    //vBackRight
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
    pyramidBatch.Vertex3fv(vBackRight);
    
    
    //金字塔后邊
    //三角形:(vApex, vBackRight, vBackLeft)
    m3dFindNormal(n, vApex, vBackRight, vBackLeft);
    
    //vApex
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 0.5f, 1.0f);
    pyramidBatch.Vertex3fv(vApex);
    
    //vBackRight
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
    pyramidBatch.Vertex3fv(vBackRight);
    
    //vBackLeft
    pyramidBatch.Normal3fv(n);
    pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
    pyramidBatch.Vertex3fv(vBackLeft);
    
    
    //結(jié)束批次設(shè)置
    pyramidBatch.End();
}


void SetupRC()
{
    glClearColor(0.7f, 0.7f, 0.7f, 1.0f );
    shaderManager.InitializeStockShaders();
    
    //開啟深度測試
    glEnable(GL_DEPTH_TEST);
    
    //分配紋理對象 參數(shù)1:紋理對象個(gè)數(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);
    
    //創(chuàng)造金字塔pyramidBatch
    MakePyramid(pyramidBatch);
    
    /*
     相機(jī)frame MoveForward(平移)
     參數(shù)1:Z,深度(屏幕到圖形的Z軸距離)
     */
    cameraFrame.MoveForward(-10);
    
}

//刪除紋理對象
void ShutdownRC(void)
{
    glDeleteTextures(1, &textureID);
}

//上下左右鍵位控制移動(dòng)
void SpecialKeys(int key, int x, int y)
{
    
    //旋轉(zhuǎn)度數(shù)
    float angular = float(m3dDegToRad(5.0f));
    

    if (key == GLUT_KEY_UP)
    {
        objectFrame.RotateWorld(-angular, 1.0f, 0.0f, 0.0f);
    }
    
    if (key == GLUT_KEY_DOWN)
    {
        objectFrame.RotateWorld(angular, 1.0f, 0.0f, 0.0f);
    }
    
    if (key == GLUT_KEY_LEFT)
    {
        objectFrame.RotateWorld(-angular, 0.0f, 1.0f, 0.0f);
    }
    
    if (key == GLUT_KEY_RIGHT)
    {
        objectFrame.RotateWorld(angular, 0.0f, 1.0f, 0.0f);
    }
    
    glutPostRedisplay();
}

//RenderScene 函數(shù):?定義函數(shù).通過glutDisplayFunc(函數(shù)名)注冊為顯示渲染函數(shù).當(dāng)屏幕發(fā)?變化/或者開發(fā)者主動(dòng)渲染會(huì)調(diào)?此函數(shù),?來實(shí)現(xiàn)數(shù)據(jù)->渲染過程
void RenderScene(void)
{
    
    //1.顏色值&光源位置
    static GLfloat vLightPos [] = { 1.0f, 1.0f, 0.0f };
    static GLfloat vWhite [] = { 1.0f, 1.0f, 1.0f, 1.0f };
    
    //清理緩存區(qū)(顏?,深度,模板緩存區(qū)等)
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    
    modelViewMatrix.PushMatrix();
    
    //添加照相機(jī)矩陣
    M3DMatrix44f mCamera;
    //從camraFrame中獲取一個(gè)4*4的矩陣
    cameraFrame.GetCameraMatrix(mCamera);
    //矩陣乘以矩陣堆棧頂部矩陣喳钟,相乘結(jié)果存儲(chǔ)到堆棧的頂部 將照相機(jī)矩陣 與 當(dāng)前模型矩陣相乘 壓入棧頂
    modelViewMatrix.MultMatrix(mCamera);
    
    //創(chuàng)建mObjectFrame矩陣
    M3DMatrix44f mObjectFrame;
    //從objectFrame中獲取矩陣屁使,objectFrame保存的是特殊鍵位的變換矩陣
    objectFrame.GetMatrix(mObjectFrame);
    //矩陣乘以矩陣堆棧頂部矩陣,相乘結(jié)果存儲(chǔ)到堆棧的頂部 將世界變換矩陣 與 當(dāng)前模型矩陣相乘 壓入棧頂
    modelViewMatrix.MultMatrix(mObjectFrame);
  
    //綁定紋理
    glBindTexture(GL_TEXTURE_2D, textureID);


    /*
     點(diǎn)光源著色器
     參數(shù)1:GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF(著色器標(biāo)簽)
     參數(shù)2:模型視圖矩陣
     參數(shù)3:投影矩陣
     參數(shù)4:視點(diǎn)坐標(biāo)系中的光源位置
     參數(shù)5:基本漫反射顏色
     參數(shù)6:圖形顏色(用紋理就不需要設(shè)置顏色荚藻。設(shè)置為0)
     */
    shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,
                                 transformPipeline.GetModelViewMatrix(),
                                 transformPipeline.GetProjectionMatrix(),
                                 vLightPos,vWhite,0);
    
    //pyramidBatch繪制
    pyramidBatch.Draw();
    
    //模型視圖出棧
    modelViewMatrix.PopMatrix();
    
    //交換緩存區(qū)
    glutSwapBuffers();
    
    
}


//main 函數(shù): 程序??.OpenGL 是?向過程編程.所以你會(huì)發(fā)現(xiàn)利?OpenGL處理圖形/圖像都是鏈?zhǔn)叫问?以及基于OpenGL封裝的圖像處理框架也是鏈?zhǔn)骄幊?int main(int argc, char* argv[])
{
    gltSetWorkingDirectory(argv[0]);
    glutInit(&argc, argv);
    //申請一個(gè)顏色緩存區(qū)屋灌、雙緩存區(qū)洁段、深度緩存區(qū)应狱、模板緩存區(qū)
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
    //設(shè)置窗口的尺寸
    glutInitWindowSize(800, 800);
    //設(shè)置窗口的名稱
    glutCreateWindow("金字塔紋理貼圖");
    //注冊回調(diào)函數(shù)(改變尺寸)
    glutReshapeFunc(ChangeSize);
    //注冊顯示函數(shù)
    glutDisplayFunc(RenderScene);
    
    glutSpecialFunc(SpecialKeys);
    
    GLenum err = glewInit();
    if (GLEW_OK != err)
    {
        fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
        return 1;
    }
    
    SetupRC();
   
    //runloop運(yùn)行循環(huán)
    glutMainLoop();
    
    ShutdownRC();
    
    return 0;
}

運(yùn)行效果如下:
金字塔紋理.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市祠丝,隨后出現(xiàn)的幾起案子疾呻,更是在濱河造成了極大的恐慌,老刑警劉巖写半,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件岸蜗,死亡現(xiàn)場離奇詭異,居然都是意外死亡叠蝇,警方通過查閱死者的電腦和手機(jī)璃岳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來悔捶,“玉大人铃慷,你說我怎么就攤上這事⊥筛茫” “怎么了犁柜?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長堂淡。 經(jīng)常有香客問我馋缅,道長扒腕,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任萤悴,我火速辦了婚禮瘾腰,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘覆履。我一直安慰自己居灯,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布内狗。 她就那樣靜靜地躺著怪嫌,像睡著了一般。 火紅的嫁衣襯著肌膚如雪柳沙。 梳的紋絲不亂的頭發(fā)上岩灭,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天,我揣著相機(jī)與錄音赂鲤,去河邊找鬼噪径。 笑死,一個(gè)胖子當(dāng)著我的面吹牛数初,可吹牛的內(nèi)容都是我干的找爱。 我是一名探鬼主播,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼泡孩,長吁一口氣:“原來是場噩夢啊……” “哼车摄!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起仑鸥,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤吮播,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后眼俊,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體意狠,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年疮胖,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了环戈。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,716評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡澎灸,死狀恐怖院塞,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情击孩,我是刑警寧澤迫悠,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站巩梢,受9級特大地震影響创泄,放射性物質(zhì)發(fā)生泄漏艺玲。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一鞠抑、第九天 我趴在偏房一處隱蔽的房頂上張望饭聚。 院中可真熱鬧,春花似錦搁拙、人聲如沸秒梳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽酪碘。三九已至,卻和暖如春盐茎,著一層夾襖步出監(jiān)牢的瞬間兴垦,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工字柠, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留探越,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓窑业,卻偏偏與公主長得像钦幔,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子常柄,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評論 2 350