視頻特效學(xué)習(xí)02- 在存儲(chǔ)著色器的情況下渲染圖形并能通過鍵盤控制Demo

頭文件介紹:
#include "GLFrustum.h":矩陣工具類,用來(lái)快速設(shè)置正/透視投影矩陣。完成坐標(biāo)3D->2D映射過程。
#include "GLTools.h":頭文件包含了大部分GLTool中類似C語(yǔ)言的獨(dú)立函數(shù)。
#include "GLMatrixStack.h":矩陣工具類??梢岳肎LMatrixStack加載單元矩陣、矩陣相乘、壓棧、出棧、平移、縮放、旋轉(zhuǎn)。
#include "GLFrame.h":矩陣工具類。表示位置。
#include "GLGeometryTransform.h":變換管道類。用來(lái)快速在代碼中傳輸視圖矩陣、投影矩陣、視圖投影變換矩陣等。
#include "GLBatch.h":三角形批次類,可以傳輸頂點(diǎn)、光照、紋理、顏色數(shù)據(jù)到存儲(chǔ)著色器中。

#include <stdio.h>
#include "GLShaderManager.h"
#include "GLTools.h"
#include <GLUT/GLUT.h>
#include "GLFrame.h"
#include "GLFrustum.h"
#include "GLMatrixStack.h"
#include <math.h>
#include "GLBatch.h"
#include "GLGeometryTransform.h"
//存儲(chǔ)著色器管理工具類
GLShaderManager     shaderManager;
//模型視圖矩陣
GLMatrixStack       modelViewMatrix;
//投影矩陣
GLMatrixStack       projectionMatrix;
//觀察者坐標(biāo)
GLFrame             cameraFrame;
//視圖坐標(biāo)
GLFrame             objectFrame;
//投影設(shè)置
GLFrustum           viewFrustum;
//幾何變換的管道 方便計(jì)算矩陣
GLGeometryTransform transformPipeline;
//容器類(7種不同的圖元對(duì)應(yīng)7種容器對(duì)象)
GLBatch             pointBatch;
GLBatch             lineBatch;
GLBatch             lineStripBatch;
GLBatch             lineLoopBatch;
GLBatch             triangleBatch;
GLBatch             triangleStripBatch;
GLBatch             triangleFanBatch;
GLfloat vGreen[] = { 0.0f, 1.0f, 0.0f, 1.0f };
GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 1.0f };
//跟蹤效果步驟
int  nStep = 0;

//重塑函數(shù)
void changeSize(int w, int h){
    glViewport(0, 0, w, h);
    //由于在這里能夠拿到寬高,所以在這里創(chuàng)建投影矩陣,并將其加載到投影矩陣堆棧中
    viewFrustum.SetPerspective(45.0f, float(w) / float(h), 1.0f, 500.0f);
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    
    //載入模型視圖矩陣,設(shè)置為單元矩陣,可以不寫
    modelViewMatrix.LoadIdentity();

    //設(shè)置變換管線 把變換管線通道添加進(jìn)去
    transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}

//設(shè)置點(diǎn)的大小
void drawPoint(){
    glPointSize(4.0f);
    pointBatch.Draw();
    glPointSize(1.0f);
}

//設(shè)置線的寬度
void drawLine(){
    glLineWidth(2.0f);
    lineBatch.Draw();
    glLineWidth(1.0f);
}


//設(shè)置線條的寬度
void drawLines(){
    glLineWidth(2.0f);
    lineStripBatch.Draw();
    glLineWidth(1.0f);
}

//設(shè)置環(huán)線的寬度
void drawLoopLines(){
    glLineWidth(2.0f);
    lineLoopBatch.Draw();
    glLineWidth(1.0f);
}

//金字塔
void DrawWireFramedBatch(GLBatch* pBatch)
{
 
    shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vGreen);
    pBatch->Draw();
 
    //畫黑色邊框
    glPolygonOffset(-1.0f, -1.0f);// 偏移深度,在同一位置要繪制填充和邊線,會(huì)產(chǎn)生z沖突,所以要偏移
    glEnable(GL_POLYGON_OFFSET_LINE);
    
    // 畫反鋸齒,讓黑邊好看些
    glEnable(GL_LINE_SMOOTH);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    
    //繪制線框幾何黑色版 三種模式,實(shí)心,邊框,點(diǎn),可以作用在正面,背面,或者兩面
    //通過調(diào)用glPolygonMode將多邊形正面或者背面設(shè)為線框模式,實(shí)現(xiàn)線框渲染
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    //設(shè)置線條寬度
    glLineWidth(2.5f);
    

    shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);
    pBatch->Draw();

    // 復(fù)原原本的設(shè)置
    ////通過調(diào)用glPolygonMode將多邊形正面或者背面設(shè)為全部填充模式
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    glDisable(GL_POLYGON_OFFSET_LINE);
    glLineWidth(1.0f);
    glDisable(GL_BLEND);
    glDisable(GL_LINE_SMOOTH);
    
    
}
//顯示函數(shù)
void renderScene(void){
    //清空緩沖區(qū)
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    //壓棧 為了每一次變化相互獨(dú)立(可以理解為復(fù)制了一份,棧頂長(zhǎng)度+1) 不影響后面的變化 此處有兩個(gè)modelViewMatrix
    modelViewMatrix.PushMatrix();
    
    M3DMatrix44f mCamera;
    cameraFrame.GetCameraMatrix(mCamera);
    //矩陣乘以矩陣堆棧的頂部矩陣,相乘的結(jié)果存儲(chǔ)在矩陣堆棧頂部
    modelViewMatrix.MultMatrix(mCamera);
    
    M3DMatrix44f mObjectFrame;
    objectFrame.GetMatrix(mObjectFrame);
    //此處的modelViewMatrix的矩陣值 = modelViewMatrix * mCamera * mObjectFrame,經(jīng)過了兩次相乘
    modelViewMatrix.MultMatrix(mObjectFrame);
    
    //核心方法 使用存儲(chǔ)著色器-平面著色器 參數(shù)2為4*4變換矩陣,通過transformPipeline.GetModelViewProjectionMatrix直接獲得模型視圖投影變換矩陣,不需要我們計(jì)算
    shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeline.GetModelViewProjectionMatrix(),vBlack);
    //根據(jù)空格鍵 切換繪制的圖形
    switch (nStep) {
        case 0:
            //設(shè)置點(diǎn)的大小
            drawPoint();
            break;
        case 1:
            //設(shè)置線的寬度
            drawLine();
            break;
        case 2:
            //設(shè)置線條的寬度
            drawLines();
            break;
        case 3:
            //設(shè)置環(huán)線的寬度
            drawLoopLines();
            break;
        case 4:
            DrawWireFramedBatch(&triangleBatch);
            break;
        case 5:
            DrawWireFramedBatch(&triangleStripBatch);
            break;
        case 6:
            DrawWireFramedBatch(&triangleFanBatch);
            break;
            break;
    }
    //出棧 還原到以前的模型視圖矩陣
    modelViewMatrix.PopMatrix();
    
    //緩沖區(qū)交換
    glutSwapBuffers();
}

//設(shè)置渲染環(huán)境
void setupRC(void){
    //設(shè)置背景顏色
    glClearColor(0.8f, 0.6f, 0.8f, 1);
    //.初始化著色器
    shaderManager.InitializeStockShaders();
    //開啟深度測(cè)試 立體
    glEnable(GL_DEPTH_TEST);
    
    //設(shè)置觀察距離 也就是觀察者和圖形的距離
    cameraFrame.MoveForward(-15.0f);
    //定義一些點(diǎn),三角形形狀
    GLfloat vCoast[9] = {
        3,3,0,
        0,3,0,
        3,0,0
    };
    //批次類繪制 Begin-Copy-End 三件套
    pointBatch.Begin(GL_POINTS, 3);
    pointBatch.CopyVertexData3f(vCoast);
    pointBatch.End();
    
    //通過線的形式
    lineBatch.Begin(GL_LINES, 3);
    lineBatch.CopyVertexData3f(vCoast);
    lineBatch.End();
    
    //通過線段的形式
    lineStripBatch.Begin(GL_LINE_STRIP, 3);
    lineStripBatch.CopyVertexData3f(vCoast);
    lineStripBatch.End();
    
    //通過線環(huán)的形式
    lineLoopBatch.Begin(GL_LINE_LOOP, 3);
    lineLoopBatch.CopyVertexData3f(vCoast);
    lineLoopBatch.End();
    
    //通過三角形創(chuàng)建金字塔
    GLfloat vPyramid[12][3] = {
        -2.0f, 0.0f, -2.0f,
        2.0f, 0.0f, -2.0f,
        0.0f, 4.0f, 0.0f,
        
        2.0f, 0.0f, -2.0f,
        2.0f, 0.0f, 2.0f,
        0.0f, 4.0f, 0.0f,
        
        2.0f, 0.0f, 2.0f,
        -2.0f, 0.0f, 2.0f,
        0.0f, 4.0f, 0.0f,
        
        -2.0f, 0.0f, 2.0f,
        -2.0f, 0.0f, -2.0f,
        0.0f, 4.0f, 0.0f};
    
    
    //GL_TRIANGLES 每3個(gè)頂點(diǎn)定義一個(gè)新的三角形
    triangleBatch.Begin(GL_TRIANGLES, 12);
    triangleBatch.CopyVertexData3f(vPyramid);
    triangleBatch.End();
    
    
    // 三角形扇形--六邊形
       GLfloat vPoints[100][3];
       int nVerts = 0;
       //半徑
       GLfloat r = 3.0f;
       //原點(diǎn)(x,y,z) = (0,0,0);
       vPoints[nVerts][0] = 0.0f;
       vPoints[nVerts][1] = 0.0f;
       vPoints[nVerts][2] = 0.0f;
       
       //M3D_2PI 就是2Pi 的意思,就一個(gè)圓的意思。 繪制圓形
       for(GLfloat angle = 0; angle < M3D_2PI; angle += M3D_2PI / 6.0f) {
           
           //數(shù)組下標(biāo)自增(每自增1次就表示一個(gè)頂點(diǎn))
           nVerts++;
           /*
            弧長(zhǎng)=半徑*角度,這里的角度是弧度制,不是平時(shí)的角度制
            既然知道了cos值,那么角度=arccos,求一個(gè)反三角函數(shù)就行了
            */
           //x點(diǎn)坐標(biāo) cos(angle) * 半徑
           vPoints[nVerts][0] = float(cos(angle)) * r;
           //y點(diǎn)坐標(biāo) sin(angle) * 半徑
           vPoints[nVerts][1] = float(sin(angle)) * r;
           //z點(diǎn)的坐標(biāo)
           vPoints[nVerts][2] = -0.5f;
       }
       
       // 結(jié)束扇形 前面一共繪制7個(gè)頂點(diǎn)(包括圓心)
       //添加閉合的終點(diǎn)
       //課程添加演示:屏蔽177-180行代碼,并把繪制節(jié)點(diǎn)改為7.則三角形扇形是無(wú)法閉合的。
       nVerts++;
       vPoints[nVerts][0] = r;
       vPoints[nVerts][1] = 0;
       vPoints[nVerts][2] = 0.0f;
       
       // 加載!
       //GL_TRIANGLE_FAN 以一個(gè)圓心為中心呈扇形排列,共用相鄰頂點(diǎn)的一組三角形
       triangleFanBatch.Begin(GL_TRIANGLE_FAN, 8);
       triangleFanBatch.CopyVertexData3f(vPoints);
       triangleFanBatch.End();
       
       //三角形條帶,一個(gè)小環(huán)或圓柱段
       //頂點(diǎn)下標(biāo)
       int iCounter = 0;
       //半徑
       GLfloat radius = 3.0f;
       //從0度~360度,以0.3弧度為步長(zhǎng)
       for(GLfloat angle = 0.0f; angle <= (2.0f*M3D_PI); angle += 0.3f)
       {
           //或許圓形的頂點(diǎn)的X,Y
           GLfloat x = radius * sin(angle);
           GLfloat y = radius * cos(angle);
           
           //繪制2個(gè)三角形(他們的x,y頂點(diǎn)一樣,只是z點(diǎn)不一樣)
           vPoints[iCounter][0] = x;
           vPoints[iCounter][1] = y;
           vPoints[iCounter][2] = -0.5;
           iCounter++;
           
           vPoints[iCounter][0] = x;
           vPoints[iCounter][1] = y;
           vPoints[iCounter][2] = 0.5;
           iCounter++;
       }
       
       // 關(guān)閉循環(huán)
       printf("三角形帶的頂點(diǎn)數(shù):%d\n",iCounter);
       //結(jié)束循環(huán),在循環(huán)位置生成2個(gè)三角形
       vPoints[iCounter][0] = vPoints[0][0];
       vPoints[iCounter][1] = vPoints[0][1];
       vPoints[iCounter][2] = -0.5;
       iCounter++;
       
       vPoints[iCounter][0] = vPoints[1][0];
       vPoints[iCounter][1] = vPoints[1][1];
       vPoints[iCounter][2] = 0.5;
       iCounter++;
       
       // GL_TRIANGLE_STRIP 共用一個(gè)條帶(strip)上的頂點(diǎn)的一組三角形
       triangleStripBatch.Begin(GL_TRIANGLE_STRIP, iCounter);
       triangleStripBatch.CopyVertexData3f(vPoints);
       triangleStripBatch.End();
}

//特殊鍵位函數(shù)(上、下、左、右移動(dòng))
void specialKeys(int key, int x, int y){
    //由于需要多方位觀察圖形,不能每一個(gè)頂點(diǎn)坐標(biāo)都進(jìn)行旋轉(zhuǎn),所以只能通過改變觀察者的坐標(biāo)來(lái)進(jìn)行。
    if (key == GLUT_KEY_UP) {
        //此處的1.0表示true
        objectFrame.RotateWorld(m3dDegToRad(-5.0f), 1.0f, 0.0f, 0.0f);
    } else if (key == GLUT_KEY_DOWN){
        objectFrame.RotateWorld(m3dDegToRad(5.0f), 1.0f, 0.0f, 0.0f);
    }else if (key == GLUT_KEY_LEFT){
        objectFrame.RotateWorld(m3dDegToRad(-5.0f), 0.0f, 1.0f, 0.0f);
    }else if (key == GLUT_KEY_RIGHT){
        objectFrame.RotateWorld(m3dDegToRad(5.0f), 0.0f, 1.0f, 0.0f);
    }
     glutPostRedisplay();
}

//根據(jù)空格次數(shù)。切換不同的“窗口名稱”
void keyPressFunc(unsigned char key, int x, int y){
    if (key == 32) { //判斷是否是空格
        nStep ++;
        if (nStep > 6) {
            nStep = 0;
        }
    }
    switch(nStep)
    {
        case 0:
            glutSetWindowTitle("GL_POINTS");
            break;
        case 1:
            glutSetWindowTitle("GL_LINES");
            break;
        case 2:
            glutSetWindowTitle("GL_LINE_STRIP");
            break;
        case 3:
            glutSetWindowTitle("GL_LINE_LOOP");
            break;
        case 4:
            glutSetWindowTitle("GL_TRIANGLES");
            break;
        case 5:
            glutSetWindowTitle("GL_TRIANGLE_STRIP");
            break;
        case 6:
            glutSetWindowTitle("GL_TRIANGLE_FAN");
            break;
    }
    //發(fā)送重新渲染請(qǐng)求
    glutPostRedisplay();
}

//檢查OpenGL API是否安全可用
int checkOpenGLInit(void){
   GLenum status = glewInit();
    if(status != GLEW_OK){
        printf("GLEW Error:%s\n",glewGetErrorString(status));
        return 1;
    }
    return 0;
}


int main(int argc,char *argv[])
{
    gltSetWorkingDirectory(argv[0]);
    glutInit(&argc, argv);
    glutInitWindowSize(600, 600);
    //申請(qǐng)一個(gè)雙緩存區(qū)、顏色緩存區(qū)、深度緩存區(qū)、模板緩存區(qū)
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
    //創(chuàng)建window的名稱
    glutCreateWindow("Title");
    
    //注冊(cè)回調(diào)函數(shù)(改變尺寸)
    glutReshapeFunc(changeSize);
    //點(diǎn)擊空格時(shí),調(diào)用的函數(shù)
    glutKeyboardFunc(keyPressFunc);
    //特殊鍵位函數(shù)(上下左右)
    glutSpecialFunc(specialKeys);
    //顯示函數(shù)
    glutDisplayFunc(renderScene);
    //判斷一下是否能初始化glew庫(kù),確保項(xiàng)目能正常使用OpenGL 框架
    checkOpenGLInit();
    //繪制
    setupRC();
    //runloop運(yùn)行循環(huán)
    glutMainLoop();
    
    return 0;
}

核心是UseStockShader方法,參數(shù)1使用的是平面著色器,參數(shù)2要傳入mvp,也就是模型視圖投影矩陣。通過transformPipeline.GetModelViewProjectionMatrix方法快速獲得mvp。而transformPipeline的設(shè)置需要 SetMatrixStacks(modelViewMatrix, projectionMatrix)方法,modelViewMatrix的矩陣需要相乘獲得,projectionMatrix需要LoadMatrix方法獲得。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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