OpenGL 添加紋理

前言

在上一篇OpenGL 沒有紋理的星系試OpenGL 金字塔基礎上修改main.cpp文件,完成添加紋理的星系。bash

代碼以下

#include "GLMatrixStack.h"
#include "GLFrame.h"
#include "GLFrustum.h"
#include "GLBatch.h"
#include "GLGeometryTransform.h"
#include <math.h>
#include <GLUT/GLUT.h>
#include "GLTools.h"
#include "StopWatch.h"
#include <stdio.h>

GLShaderManager  shaderManager;
GLMatrixStack         modelViewMatrix;
GLMatrixStack         projectionMatrix;
//視景體
GLFrustum                   viewFrustum;
GLGeometryTransform transformPipeline;
GLFrame                       cameraFrame;

GLTriangleBatch sunBatch;
GLTriangleBatch earthBatch;
GLTriangleBatch otherStarsBatch;
GLBatch theMilkyWayBatch;

//紋理標記ID
GLuint uiTextures[3];

#define NUMBER_STARS 100

GLFrame stars[NUMBER_STARS];

static GLfloat vTheMilkyWayColor[] = {0.96f,0.92f,0.23f,0.6f};

//將TGA文件加載爲2D紋理
bool loadTGATexture(const char *szFileName, GLenum minFilter, GLenum magFileter, GLenum wrapMode) {
    
    GLbyte *pBits;
    int nWidth, nHeight, nComponents;
    GLenum eFormat;
    //讀取紋理 pBits:指向圖像數據的指針 arg2:紋理文件寬度地址 arg4:文件組件地址 arg5:文件格式地址
    pBits = gltReadTGABits(szFileName, &nWidth, &nHeight, &nComponents, &eFormat);
    
    if (pBits == NULL) {
        return false;
    }
    
    //設置過濾方式
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFileter);
    
    //設置環繞模式
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode);
    
    //載入紋理 arg2:mip貼圖層次 arg7:像素數據類型(GL_UNSIGNED_BYTE 每一個顏色份量都是一個8位無符號整型)
    glTexImage2D(GL_TEXTURE_2D, 0, nComponents, nWidth, nHeight, 0, eFormat, GL_UNSIGNED_BYTE, pBits);
    
    //釋放ppBits
    free(pBits);
    
    //只有minFilter 等於如下四種模式,才能夠生成Mip貼圖
    //GL_NEAREST_MIPMAP_NEAREST具備很是好的性能,而且閃爍現象很是弱
    //GL_LINEAR_MIPMAP_NEAREST經常用於對遊戲進行加速,它使用了高質量的線性過濾器
    //GL_LINEAR_MIPMAP_LINEAR 和GL_NEAREST_MIPMAP_LINEAR 過濾器在Mip層之間執行了一些額外的插值,以消除他們之間的過濾痕跡。
    //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)
    //加載Mip
    glGenerateMipmap(GL_TEXTURE_2D);
    
    return true;
}

void setupRC() {
    glClearColor(0.27f, 0.24f, 0.34f, 1.0f);
    shaderManager.InitializeStockShaders();
    cameraFrame.MoveForward(10.0f);
    glEnable(GL_DEPTH_TEST);
    //開啓正背面剔除,倒影時效果
    glEnable(GL_CULL_FACE);
    //星帶
    GLfloat texSize = 20.0f;
    theMilkyWayBatch.Begin(GL_TRIANGLE_FAN, 4,1);
    theMilkyWayBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
    theMilkyWayBatch.Vertex3f(-30.0f,-0.5f,30.0f);
    
    theMilkyWayBatch.MultiTexCoord2f(0, texSize, 0.0f);
    theMilkyWayBatch.Vertex3f(30.0f, -0.5f, 30.0f);
    
    theMilkyWayBatch.MultiTexCoord2f(0, texSize, texSize);
    theMilkyWayBatch.Vertex3f(30.0f, -0.5f, -30.0f);
    
    theMilkyWayBatch.MultiTexCoord2f(0, 0.0f, texSize);
    theMilkyWayBatch.Vertex3f(-30.0f, -0.5f, -30.0f);
    theMilkyWayBatch.End();
    
    //太陽
    gltMakeSphere(sunBatch, 0.4f, 50, 100);
    //地球
    gltMakeSphere(earthBatch, 0.1f, 50, 100);
    //其餘星體位置
    gltMakeSphere(otherStarsBatch, 0.1f, 50, 100);
    for (int i = 0; i < NUMBER_STARS; i++) {
        GLfloat x = ((GLfloat)(rand() % 500 -200)) * 0.12f;
        GLfloat z = ((GLfloat)(rand() % 500 -200)) * 0.12f;
        stars[i].SetOrigin(x, 0.0f, z);
    }
    
    //命名紋理對象
    glGenTextures(3, uiTextures);
    glBindTexture(GL_TEXTURE_2D, uiTextures[0]);
    loadTGATexture("milkey.tga", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_REPEAT);
    
    glBindTexture(GL_TEXTURE_2D, uiTextures[1]);
    loadTGATexture("sun.tga", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_REPEAT);
    
    glBindTexture(GL_TEXTURE_2D, uiTextures[2]);
    loadTGATexture("earth.tga", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_REPEAT);
}

void drawUniverse(GLfloat yRot) {
    //漫反射顏色
    static GLfloat vWhite[] = { 1.0f, 1.0f, 1.0f, 1.0f};
    static M3DMatrix44f vLightPos = {0.0f,20.0f,10.0f,1.0f};
    
    modelViewMatrix.Translate(0.0f, 0.0f, -5.0f);
    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,
                                 transformPipeline.GetModelViewMatrix(),
                                 transformPipeline.GetProjectionMatrix(),
                                 vLightPos,
                                 vWhite,
                                 0);
    sunBatch.Draw();
    modelViewMatrix.PopMatrix();
    
    //繪製地球
    modelViewMatrix.PushMatrix();
    //要先旋轉後平移,矩陣乘法不遵循交換律要將旋轉後的矩陣平移
    modelViewMatrix.Rotate(yRot * -2.0f, 0.0f, 1.0f, 0.0f);
    modelViewMatrix.Translate(0.7f, 0.0f, 0.0f);
    glBindTexture(GL_TEXTURE_2D, uiTextures[2]);
    shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,
                                 transformPipeline.GetModelViewMatrix(),
                                 transformPipeline.GetProjectionMatrix(),
                                 vLightPos,
                                 vWhite,
                                 0);
    earthBatch.Draw();
    modelViewMatrix.PopMatrix();
    
    //其餘星體
    glBindTexture(GL_TEXTURE_2D, uiTextures[1]);
    for (int i = 0; i < NUMBER_STARS; i++) {
        modelViewMatrix.PushMatrix();
        modelViewMatrix.MultMatrix(stars[i]);
       shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,
                                    transformPipeline.GetModelViewMatrix(),
                                    transformPipeline.GetProjectionMatrix(),
                                    vLightPos,
                                    vWhite,
                                    0);
        otherStarsBatch.Draw();
        modelViewMatrix.PopMatrix();
    }
}

void changeSize(int w, int h) {
    glViewport(0, 0, w, h);
    //設置透視投影
    viewFrustum.SetPerspective(25.0f, float(w) / float(h), 2.0f, 400.0f);
    
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}

void renderScene() {
    //清理緩衝區
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    
    static CStopWatch rotTimer;
    float yRot = rotTimer.GetElapsedSeconds() * 60.0f;
    
    //照相機矩陣
    modelViewMatrix.PushMatrix(cameraFrame);
    
    //倒影
    modelViewMatrix.PushMatrix();
    modelViewMatrix.Scale(1.0f, -1.0f, 1.0f);
    modelViewMatrix.Translate(0.0f, 1.0f, 0.0f);
    
    //設定順時針爲正面
    glFrontFace(GL_CW);
    drawUniverse(yRot);
    //回覆逆時針爲正面
    glFrontFace(GL_CCW);
    
    modelViewMatrix.PopMatrix();
    
    //theMilky
    glEnable(GL_BLEND);
    //顏色混合方程
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glBindTexture(GL_TEXTURE_2D, uiTextures[0]);
    /**紋理調整着色器(將一個基本色乘以一個取自紋理的單元nTextureUnit的紋理)
     arg1:GLT_SHADER_TEXTURE_MODULATE
     arg2:模型視圖投影矩陣
     arg3:顏色
     arg4:紋理單元(第0層的紋理單元)
     */
    shaderManager.UseStockShader(GLT_SHADER_TEXTURE_MODULATE,
                                 transformPipeline.GetModelViewProjectionMatrix(),
                                 vTheMilkyWayColor,
                                 0);
    theMilkyWayBatch.Draw();
    glDisable(GL_BLEND);
    
    drawUniverse(yRot);
    modelViewMatrix.PopMatrix();
    
    glutSwapBuffers();
    glutPostRedisplay();
}

void specialKeys(int key,int x,int y){
    float step = 0.4f;
    float angular = float(m3dDegToRad(2.0f));
    
    if (key == GLUT_KEY_UP) {
        cameraFrame.MoveForward(-step);
    }
    if (key == GLUT_KEY_DOWN) {
        cameraFrame.MoveForward(step);
    }
    if (key == GLUT_KEY_LEFT) {
        cameraFrame.RotateWorld(angular, 0.0f, 1.0f, 0.0f);
    }
    if (key == GLUT_KEY_RIGHT) {
        cameraFrame.RotateWorld(-angular, 0.0f, 1.0f, 0.0f);
    }
}


void shutdownRC(void)
{
    glDeleteTextures(3, uiTextures);
}

int main(int argc, char* argv[]) {
    
    gltSetWorkingDirectory(argv[0]);
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
    glutInitWindowSize(375, 750);
    glutCreateWindow("dowZhang");
    glutReshapeFunc(changeSize);
    glutDisplayFunc(renderScene);
    glutSpecialFunc(specialKeys);
    
    GLenum err = glewInit();
    if (GLEW_OK != err) {
        return 1;
    }
    
    setupRC();
    
    glutMainLoop();
    
    shutdownRC();
    
    return 0;
}

複製代碼

效果圖

補充

混合

當啓用混合功能時,參考以下方程:oop

Cf = (Cs * S) + (Cd * D)
Cf: 最終計算結果顏色
Cs: 源顏色
Cd: 目標顏色
S: 源混合因子
D:目標混合因子
複製代碼

設置混合因子方程:post

glBlendFunc(GLenum S,GLenum D)
複製代碼

混合因子參考表: 性能

相關文章
相關標籤/搜索