紋理在OpenGL中的實際運用

這次的案例我們在OpenGL綜合練習(xí)的基礎(chǔ)上配上紋理和鏡面效果,提升整理的視覺效果。
具體代碼如下:

#define NUM_SPHERES 50
GLFrame spheres[NUM_SPHERES];

GLShaderManager     shaderManager;          // 著色器管理器
GLMatrixStack       modelViewMatrix;        // 模型視圖矩陣
GLMatrixStack       projectionMatrix;       // 投影矩陣
GLFrustum           viewFrustum;            // 視景體
GLGeometryTransform transformPipeline;      // 幾何圖形變換管道

GLTriangleBatch     torusBatch;             // 大球批處理
GLBatch             floorBatch;             // 地板批處理

//**2、定義公轉(zhuǎn)球的批處理(公轉(zhuǎn)自轉(zhuǎn))**
GLTriangleBatch     sphereBatch;            //小球批處理

//**3、角色幀 照相機角色幀(全局照相機實例)
GLFrame             cameraFrame;

//**5、添加紋理
//紋理標記數(shù)組
GLuint uiTextures[3];

bool LoadTGATexture(const char *szFileName, GLenum minFilter, GLenum magFilter, GLenum wrapMode)
{

    GLbyte *pBits;
    int nWidth, nHeight, nComponents;
    GLenum eFormat;
    
    //1.讀取紋理數(shù)據(jù)
    pBits = gltReadTGABits(szFileName, &nWidth, &nHeight, &nComponents, &eFormat);
    if(pBits == NULL)
        return false;
    
    //2、設(shè)置紋理參數(shù)
    //參數(shù)1:紋理維度
    //參數(shù)2:為S/T坐標設(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:紋理單元存儲的顏色成分(從讀取像素圖是獲得)-將內(nèi)部參數(shù)nComponents改為了通用壓縮紋理格式GL_COMPRESSED_RGB
    //參數(shù)4:加載紋理寬
    //參數(shù)5:加載紋理高
    //參數(shù)6:   允許為紋理貼圖指定?個邊界寬度
    //參數(shù)7:   像素數(shù)據(jù)的顏色格式
    //參數(shù)8:像素數(shù)據(jù)的數(shù)據(jù)類型(GL_UNSIGNED_BYTE,每個顏色分量都是一個8位無符號整數(shù))
    //參數(shù)9:指向紋理圖像數(shù)據(jù)的指針
    glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB, nWidth, nHeight, 0,
                 eFormat, GL_UNSIGNED_BYTE, pBits);
    
    //使用完畢釋放pBits
    free(pBits);
    
    //只有minFilter 等于以下四種模式,才可以生成Mip貼圖
    //GL_NEAREST_MIPMAP_NEAREST具有非常好的性能,并且閃爍現(xiàn)象非常弱
    //GL_LINEAR_MIPMAP_NEAREST常常用于對游戲進行加速,它使用了高質(zhì)量的線性過濾器
    //GL_LINEAR_MIPMAP_LINEAR 和GL_NEAREST_MIPMAP_LINEAR 過濾器在Mip層之間執(zhí)行了一些額外的插值,以消除他們之間的過濾痕跡。
    //GL_LINEAR_MIPMAP_LINEAR 三線性Mip貼圖。紋理過濾的黃金準則,具有最高的精度。
    if(minFilter == GL_LINEAR_MIPMAP_LINEAR ||
       minFilter == GL_LINEAR_MIPMAP_NEAREST ||
       minFilter == GL_NEAREST_MIPMAP_LINEAR ||
       minFilter == GL_NEAREST_MIPMAP_NEAREST)
    //4.加載Mip,紋理生成所有的Mip層
    //參數(shù):GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D
    glGenerateMipmap(GL_TEXTURE_2D);
    
    
    return true;
}



void SetupRC()
{
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    shaderManager.InitializeStockShaders();
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);

    //設(shè)置大球
    gltMakeSphere(torusBatch, 0.4f, 40, 80);
    
    //設(shè)置小球
    gltMakeSphere(sphereBatch, 0.1f, 26, 13);
    
    //設(shè)置地板頂點數(shù)據(jù)&地板紋理
    GLfloat texSize = 10.0f;
    floorBatch.Begin(GL_TRIANGLE_FAN, 4,1);
    floorBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
    floorBatch.Vertex3f(-20.f, -0.41f, 20.0f);
    
    floorBatch.MultiTexCoord2f(0, texSize, 0.0f);
    floorBatch.Vertex3f(20.0f, -0.41f, 20.f);
    
    floorBatch.MultiTexCoord2f(0, texSize, texSize);
    floorBatch.Vertex3f(20.0f, -0.41f, -20.0f);
    
    floorBatch.MultiTexCoord2f(0, 0.0f, texSize);
    floorBatch.Vertex3f(-20.0f, -0.41f, -20.0f);
    floorBatch.End();
    
    //隨機小球頂點坐標
    for (int i = 0; i < NUM_SPHERES; i++) {
        GLfloat x = ((GLfloat)((rand() % 400) - 200 ) * 0.1f);
        GLfloat z = ((GLfloat)((rand() % 400) - 200 ) * 0.1f);
        
        //對spheres數(shù)組中的每一個頂點,設(shè)置頂點數(shù)據(jù)
        spheres[i].SetOrigin(x, 0.0f, z);
    }
    
    
    //命名紋理對象
    glGenTextures(3, uiTextures);
    
    //將TGA文件加載為2D紋理。
    //參數(shù)1:紋理文件名稱
    //參數(shù)2&參數(shù)3:需要縮小&放大的過濾器
    //參數(shù)4:紋理坐標環(huán)繞模式
    glBindTexture(GL_TEXTURE_2D, uiTextures[0]);
    LoadTGATexture("marble.tga", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_REPEAT);
    
    
    glBindTexture(GL_TEXTURE_2D, uiTextures[1]);
    LoadTGATexture("marslike.tga", GL_LINEAR_MIPMAP_LINEAR,
                   GL_LINEAR, GL_CLAMP_TO_EDGE);
    
    
    glBindTexture(GL_TEXTURE_2D, uiTextures[2]);
    LoadTGATexture("moonlike.tga", GL_LINEAR_MIPMAP_LINEAR,
                   GL_LINEAR, GL_CLAMP_TO_EDGE);
    
   
}

//刪除紋理
void ShutdownRC(void)
{
    glDeleteTextures(3, uiTextures);
}

// 屏幕更改大小或已初始化
void ChangeSize(int nWidth, int nHeight)
{
    //1.設(shè)置視口
    glViewport(0, 0, nWidth, nHeight);
    
    //2.設(shè)置投影方式
    viewFrustum.SetPerspective(35.0f, float(nWidth)/float(nHeight), 1.0f, 100.0f);
    
    //3.將投影矩陣加載到投影矩陣堆棧,
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    modelViewMatrix.LoadIdentity();
    
    //4.將投影矩陣堆棧和模型視圖矩陣對象設(shè)置到管道中
    transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}

void drawSomething(GLfloat yRot)
{
    //1.定義光源位置&漫反射顏色
    static GLfloat vWhite[] = { 1.0f, 1.0f, 1.0f, 1.0f };
    static GLfloat vLightPos[] = { 0.0f, 3.0f, 0.0f, 1.0f };
    
    //2.繪制懸浮小球
    glBindTexture(GL_TEXTURE_2D, uiTextures[2]);
    for(int i = 0; i < NUM_SPHERES; i++) {
        modelViewMatrix.PushMatrix();
        modelViewMatrix.MultMatrix(spheres[i]);
        shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,
                                     modelViewMatrix.GetMatrix(),
                                     transformPipeline.GetProjectionMatrix(),
                                     vLightPos,
                                     vWhite,
                                     0);
        sphereBatch.Draw();
        modelViewMatrix.PopMatrix();
    }
    
    //3.繪制大球
    modelViewMatrix.Translate(0.0f, 0.2f, -2.5f);
    modelViewMatrix.PushMatrix();
    modelViewMatrix.Rotate(yRot, 0.0f, 1.0f, 0.0f);
    glBindTexture(GL_TEXTURE_2D, uiTextures[1]);
    shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,
                                 modelViewMatrix.GetMatrix(),
                                 transformPipeline.GetProjectionMatrix(),
                                 vLightPos,
                                 vWhite,
                                 0);
    torusBatch.Draw();
    modelViewMatrix.PopMatrix();
    
    //4.繪制公轉(zhuǎn)小球球(公轉(zhuǎn)自轉(zhuǎn))
    modelViewMatrix.PushMatrix();
    modelViewMatrix.Rotate(yRot * -2.0f, 0.0f, 1.0f, 0.0f);
    modelViewMatrix.Translate(0.8f, 0.0f, 0.0f);
    glBindTexture(GL_TEXTURE_2D, uiTextures[2]);
    shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,
                                 modelViewMatrix.GetMatrix(),
                                 transformPipeline.GetProjectionMatrix(),
                                 vLightPos,
                                 vWhite,
                                 0);
    sphereBatch.Draw();
    modelViewMatrix.PopMatrix();
    
}

void RenderScene(void)
{
    static GLfloat vFloorColor[] = { 1.0f, 1.0f, 0.0f, 0.75f};
    
    //基于時間動畫
    static CStopWatch   rotTimer;
    float yRot = rotTimer.GetElapsedSeconds() * 60.0f;
    
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    //壓入棧(棧頂)
    modelViewMatrix.PushMatrix();
    
    //設(shè)置觀察者矩陣
    M3DMatrix44f mCamera;
    cameraFrame.GetCameraMatrix(mCamera);
    modelViewMatrix.MultMatrix(mCamera);
    
    //壓棧(鏡面)
    modelViewMatrix.PushMatrix();
    
    //翻轉(zhuǎn)Y軸
    modelViewMatrix.Scale(1.0f, -1.0f, 1.0f);
    //鏡面世界圍繞Y軸平移一定間距
    modelViewMatrix.Translate(0.0f, 0.8f, 0.0f);
    
    //指定順時針為正面
    glFrontFace(GL_CW);
  
    //繪制地面以外其他部分(鏡面)
    drawSomething(yRot);
   
    //恢復(fù)為逆時針為正面
    glFrontFace(GL_CCW);
    
    //繪制鏡面,恢復(fù)矩陣
    modelViewMatrix.PopMatrix();
    
    //開啟混合功能(繪制地板)
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    
    //綁定地面紋理
    glBindTexture(GL_TEXTURE_2D, uiTextures[0]);
    
    /*
     紋理調(diào)整著色器(將一個基本色乘以一個取自紋理的單元nTextureUnit的紋理)
     參數(shù)1:GLT_SHADER_TEXTURE_MODULATE
     參數(shù)2:模型視圖投影矩陣
     參數(shù)3:顏色
     參數(shù)4:紋理單元(第0層的紋理單元)
     */
    shaderManager.UseStockShader(GLT_SHADER_TEXTURE_MODULATE,
                                 transformPipeline.GetModelViewProjectionMatrix(),
                                 vFloorColor,
                                 0);
    //shaderManager.UseStockShader(GLT_SHADER_TEXTURE_REPLACE,transformPipeline.GetModelViewProjectionMatrix(),0);
    
    floorBatch.Draw();
    glDisable(GL_BLEND);
    
    //繪制地面以外其他部分
    drawSomething(yRot);
    
    modelViewMatrix.PopMatrix();
    glutSwapBuffers();
    glutPostRedisplay();
}


//**3.移動照相機參考幀,來對方向鍵作出響應(yīng)
void SpeacialKeys(int key,int x,int y)
{
    
    float linear = 0.1f;
    float angular = float(m3dDegToRad(5.0f));
    
    if (key == GLUT_KEY_UP) {
        
        //MoveForward 平移
        cameraFrame.MoveForward(linear);
    }
    
    if (key == GLUT_KEY_DOWN) {
        cameraFrame.MoveForward(-linear);
    }
    
    if (key == GLUT_KEY_LEFT) {
        //RotateWorld 旋轉(zhuǎn)
        cameraFrame.RotateWorld(angular, 0.0f, 1.0f, 0.0f);
    }
    
    if (key == GLUT_KEY_RIGHT) {
        cameraFrame.RotateWorld(-angular, 0.0f, 1.0f, 0.0f);
    }
    
    
    
}


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

主要模塊講解

1.地板,大球,小球

地板而言,相比之前的demo有所改變,上一個demo中跟我們是通過設(shè)置大量的頂點數(shù)據(jù)最后連接而成,這次我們只通過四個點,并且設(shè)置了10倍的紋理坐標大小,以獲得更細膩的地板效果。而大球與小球的構(gòu)造方式與之前的例子完全相同,這里就不多贅述。

    GLfloat texSize = 10.0f;
    floorBatch.Begin(GL_TRIANGLE_FAN, 4,1);
    floorBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
    floorBatch.Vertex3f(-20.f, -0.41f, 20.0f);
    
    floorBatch.MultiTexCoord2f(0, texSize, 0.0f);
    floorBatch.Vertex3f(20.0f, -0.41f, 20.f);
    
    floorBatch.MultiTexCoord2f(0, texSize, texSize);
    floorBatch.Vertex3f(20.0f, -0.41f, -20.0f);
    
    floorBatch.MultiTexCoord2f(0, 0.0f, texSize);
    floorBatch.Vertex3f(-20.0f, -0.41f, -20.0f);
    floorBatch.End();

紋理

紋理方面,我們首先定義了一個LoadTGATexture方法,在方法中我們執(zhí)行了一些紋理的初始化操作,然后在SetupRC中調(diào)用,把紋理所對應(yīng)的tga文件加載成2d紋理,在繪制時直接通過glBindTexture方法綁定即可,具體的注釋可參考上面的源碼。

鏡面效果

要實現(xiàn)鏡面效果,主要的操作分為兩步:
第一步:通過scale方法,將模型視圖進行翻轉(zhuǎn),到達鏡面位置,沿著y軸平移一定距離時效果更逼真,而且鏡面之后,y軸的前后移動會反向,原來正面為逆時針,現(xiàn)在為順時針。
第二步:開啟混合功能 ,綁定紋理,將地板繪制成類似鏡面的效果(在設(shè)置地板顏色的時候我們給的是一個帶透明度的顏色,為的就是在這邊使用)。

 //開啟混合功能(繪制地板)
    glEnable(GL_BLEND);
 //指定glBlendFunc 顏色混合方程式
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 //綁定地面紋理
    glBindTexture(GL_TEXTURE_2D, uiTextures[0]);
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容