OpenGL繪制三角形,金字塔和圓環(huán)

剛剛學(xué)習(xí)OpenGL,嘗試?yán)L制幾個圖形看下立體效果,不多說,直接上代碼。

1.導(dǎo)入需要用到的庫和定義全局變量

#include "GLTools.h"    
#include "GLMatrixStack.h"
#include "GLFrame.h"
#include "GLFrustum.h"
#include "GLBatch.h"
#include "GLGeometryTransform.h"

#include <math.h>
#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif

/*
 GLMatrixStack 變化管線使用矩陣堆棧
 
 GLMatrixStack 構(gòu)造函數(shù)允許指定堆棧的最大深度、默認(rèn)的堆棧深度為64.這個矩陣堆在初始化時已經(jīng)在堆棧中包含了單位矩陣。
 GLMatrixStack::GLMatrixStack(int iStackDepth = 64);
 
 //通過調(diào)用頂部載入這個單位矩陣
 void GLMatrixStack::LoadIndentiy(void);
 
 //在堆棧頂部載入任何矩陣
 void GLMatrixStack::LoadMatrix(const M3DMatrix44f m);
 */
// 各種需要的類
GLShaderManager     shaderManager;
GLMatrixStack       modelViewMatrix;
GLMatrixStack       projectionMatrix;
GLFrame             cameraFrame;
GLFrame             objectFrame;
//投影矩陣
GLFrustum           viewFrustum;

//容器類(7種不同的圖元對應(yīng)7種容器對象)
GLBatch             pointBatch;
GLBatch             lineBatch;
GLBatch             lineStripBatch;
GLBatch             lineLoopBatch;
GLBatch             triangleBatch;
GLBatch             triangleStripBatch;
GLBatch             triangleFanBatch;

//幾何變換的管道
GLGeometryTransform transformPipeline;

GLfloat vGreen[] = { 0.0f, 1.0f, 0.0f, 1.0f };
GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 1.0f };


// 跟蹤效果步驟
int nStep = 0;

2.在主函數(shù)中初始化和注冊各種回調(diào)函數(shù)

int main(int argc, char* argv[])
{
    gltSetWorkingDirectory(argv[0]);
    glutInit(&argc, argv);
    //申請一個顏色緩存區(qū)、深度緩存區(qū)、雙緩存區(qū)、模板緩存區(qū)
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
    //設(shè)置window 的尺寸
    glutInitWindowSize(800, 600);
    //創(chuàng)建window的名稱
    glutCreateWindow("GL_POINTS");
    //注冊回調(diào)函數(shù)(改變尺寸)
    glutReshapeFunc(ChangeSize);
    //點擊空格時,調(diào)用的函數(shù)
    glutKeyboardFunc(KeyPressFunc);
    //特殊鍵位函數(shù)(上下左右)
    glutSpecialFunc(SpecialKeys);
    //顯示函數(shù)
    glutDisplayFunc(RenderScene);
    
    //判斷一下是否能初始化glew庫,確保項目能正常使用OpenGL 框架
    GLenum err = glewInit();
    if (GLEW_OK != err) {
        fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
        return 1;
    }
    //繪制
    SetupRC();
    
    //runloop運行循環(huán)
    glutMainLoop();
    return 0;
}

1.1 ChangeSize函數(shù)用來監(jiān)聽窗口大小變化,讓圖形等比例縮放

// 窗口已更改大小,或剛剛創(chuàng)建。無論哪種情況,我們都需要
// 使用窗口維度設(shè)置視口和投影矩陣.
void ChangeSize(int w, int h)
{
    glViewport(0, 0, w, h);
    //創(chuàng)建投影矩陣,并將它載入投影矩陣堆棧中
    viewFrustum.SetPerspective(35.0f, float(w) / float(h), 1.0f, 500.0f);
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    
    //調(diào)用頂部載入單元矩陣
    modelViewMatrix.LoadIdentity();
}

1.2 KeyPressFunc函數(shù)用來監(jiān)聽點擊鍵盤空格后切換窗口標(biāo)題和重新渲染不同的形狀

//根據(jù)空格次數(shù)。切換不同的“窗口名稱”
void KeyPressFunc(unsigned char key, int x, int y)
{
    if(key == 32) //32為空格的ASCII碼
    {
        nStep++;
        if(nStep > 6)
            nStep = 0;
    }
    // 點擊空格切換窗口標(biāo)題
    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;
    }
    //告訴opengl重新渲染 根據(jù)nStep渲染哪種圖案
    glutPostRedisplay();
}

1.3 處理特殊鍵位(上下左右),旋轉(zhuǎn)圖形

//特殊鍵位處理(上、下、左、右移動)
void SpecialKeys(int key, int x, int y)
{
    
    if(key == GLUT_KEY_UP)
        //圍繞一個指定的X,Y,Z軸旋轉(zhuǎn)。m3dDegToRad(-5.0f)為每次旋轉(zhuǎn)角度,后面三個參數(shù)為X,Y,Z三個軸
        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();
}

1.4 初始化繪制圖形的各種容器和定點

// 此函數(shù)在呈現(xiàn)上下文中進(jìn)行任何必要的初始化。.
// 這是第一次做任何與opengl相關(guān)的任務(wù)。
void SetupRC()
{
    // 灰色的背景
    glClearColor(0.7f, 0.7f, 0.7f, 1.0f );
    shaderManager.InitializeStockShaders();
    glEnable(GL_DEPTH_TEST);
    //設(shè)置變換管線以使用兩個矩陣堆棧
    transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
    cameraFrame.MoveForward(-15.0f);
    
    /*
     常見函數(shù):
     void GLBatch::Begin(GLenum primitive,GLuint nVerts,GLuint nTextureUnits = 0);
      參數(shù)1:表示使用的圖元
      參數(shù)2:頂點數(shù)
      參數(shù)3:紋理坐標(biāo)(可選)
     
     //負(fù)責(zé)頂點坐標(biāo)
     void GLBatch::CopyVertexData3f(GLFloat *vNorms);
     
     //結(jié)束,表示已經(jīng)完成數(shù)據(jù)復(fù)制工作
     void GLBatch::End(void);
     
     
     */
    //定義一些點,三角形形狀。
   
    GLfloat vCoast[9] = {
        3,3,0,0,3,0,3,0,0
        
    };
    
    //用點的形式
    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
        
    };

//    GLfloat vPyramid[12][3] = {
//        -4.0f, 0.0f, -4.0f,
//        4.0f, 0.0f, -4.0f,
//        0.0f, 8.0f, 0.0f,
//
//        4.0f, 0.0f, -4.0f,
//        4.0f, 0.0f, 4.0f,
//        0.0f, 8.0f, 0.0f,
//
//        4.0f, 0.0f, 4.0f,
//        -4.0f, 0.0f, 4.0f,
//        0.0f, 8.0f, 0.0f,
//
//        -4.0f, 0.0f, 4.0f,
//        -4.0f, 0.0f, -4.0f,
//        0.0f, 8.0f, 0.0f};
    
    //GL_TRIANGLES 每3個頂點定義一個新的三角形
    triangleBatch.Begin(GL_TRIANGLES, 12);
    triangleBatch.CopyVertexData3f(vPyramid);
    triangleBatch.End();
    
    
    // 三角形扇形--六邊形
    GLfloat vPoints[100][3];    
    int nVerts = 0;
    //半徑
    GLfloat r = 3.0f;
    //原點(x,y,z) = (0,0,0);
    vPoints[nVerts][0] = 0.0f;
    vPoints[nVerts][1] = 0.0f;
    vPoints[nVerts][2] = 0.0f;
    
    
    //M3D_2PI 就是2Pi 的意思,就一個圓的意思。 繪制圓形
    for(GLfloat angle = 0; angle < M3D_2PI; angle += M3D_2PI / 6.0f) {
        
        //數(shù)組下標(biāo)自增(每自增1次就表示一個頂點)
        nVerts++;
        /*
         弧長=半徑*角度,這里的角度是弧度制,不是平時的角度制
         既然知道了cos值,那么角度=arccos,求一個反三角函數(shù)就行了
         */
        //x點坐標(biāo) cos(angle) * 半徑
        vPoints[nVerts][0] = float(cos(angle)) * r;
        //y點坐標(biāo) sin(angle) * 半徑
        vPoints[nVerts][1] = float(sin(angle)) * r;
        //z點的坐標(biāo)
        vPoints[nVerts][2] = -0.5f;
    }
    
    // 結(jié)束扇形 前面一共繪制7個頂點(包括圓心)
    //添加閉合的終點
    //課程添加演示:屏蔽177-180行代碼,并把繪制節(jié)點改為7.則三角形扇形是無法閉合的。
    nVerts++;
    vPoints[nVerts][0] = r;
    vPoints[nVerts][1] = 0;
    vPoints[nVerts][2] = 0.0f;
    
    // 加載!
    //GL_TRIANGLE_FAN 以一個圓心為中心呈扇形排列,共用相鄰頂點的一組三角形
    triangleFanBatch.Begin(GL_TRIANGLE_FAN, 8);
    triangleFanBatch.CopyVertexData3f(vPoints);
    triangleFanBatch.End();
    
    //三角形條帶,一個小環(huán)或圓柱段
    //頂點下標(biāo)
    int iCounter = 0;
    //半徑
    GLfloat radius = 3.0f;
    //從0度~360度,以0.3弧度為步長
    for(GLfloat angle = 0.0f; angle <= (2.0f*M3D_PI); angle += 0.3f)
    {
        //或許圓形的頂點的X,Y
        GLfloat x = radius * sin(angle);
        GLfloat y = radius * cos(angle);
        
        //繪制2個三角形(他們的x,y頂點一樣,只是z點不一樣)
        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("三角形帶的頂點數(shù):%d\n",iCounter);
    //結(jié)束循環(huán),在循環(huán)位置生成2個三角形
    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 共用一個條帶(strip)上的頂點的一組三角形
    triangleStripBatch.Begin(GL_TRIANGLE_STRIP, iCounter);
    triangleStripBatch.CopyVertexData3f(vPoints);
    triangleStripBatch.End();
}

1.5 召喚場景

// 召喚場景
void RenderScene(void)
{
    // Clear the window with current clearing color
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
   
    //壓棧
    modelViewMatrix.PushMatrix();
    M3DMatrix44f mCamera;
    cameraFrame.GetCameraMatrix(mCamera);
    
    //矩陣乘以矩陣堆棧的頂部矩陣,相乘的結(jié)果隨后簡存儲在堆棧的頂部
    modelViewMatrix.MultMatrix(mCamera);
    
    M3DMatrix44f mObjectFrame;
    //只要使用 GetMatrix 函數(shù)就可以獲取矩陣堆棧頂部的值,這個函數(shù)可以進(jìn)行2次重載。用來使用GLShaderManager 的使用?;蛘呤谦@取頂部矩陣的頂點副本數(shù)據(jù)
    objectFrame.GetMatrix(mObjectFrame);
    
    //矩陣乘以矩陣堆棧的頂部矩陣,相乘的結(jié)果隨后簡存儲在堆棧的頂部
    modelViewMatrix.MultMatrix(mObjectFrame);
    
    /* GLShaderManager 中的Uniform 值——平面著色器
     參數(shù)1:平面著色器
     參數(shù)2:運行為幾何圖形變換指定一個 4 * 4變換矩陣
     --transformPipeline.GetModelViewProjectionMatrix() 獲取的
     GetMatrix函數(shù)就可以獲得矩陣堆棧頂部的值
     參數(shù)3:顏色值(黑色)
     */
    shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);
    //根據(jù)點擊空格次數(shù)緩存的nStep來渲染哪個圖形
    switch(nStep) {
        case 0:
            //設(shè)置點的大小
            glPointSize(4.0f);
            pointBatch.Draw();
            glPointSize(1.0f);
            break;
        case 1:
            //設(shè)置線的寬度
            glLineWidth(2.0f);
            lineBatch.Draw();
            glLineWidth(1.0f);
            break;
        case 2:
            glLineWidth(2.0f);
            lineStripBatch.Draw();
            glLineWidth(1.0f);
            break;
        case 3:
            glLineWidth(2.0f);
            lineLoopBatch.Draw();
            glLineWidth(1.0f);
            break;
        case 4:
            DrawWireFramedBatch(&triangleBatch);
            break;
        case 5:
            DrawWireFramedBatch(&triangleStripBatch);
            break;
        case 6:
            DrawWireFramedBatch(&triangleFanBatch);
            break;
    }
    
    //還原到以前的模型視圖矩陣(單位矩陣)
    modelViewMatrix.PopMatrix();
    
    // 進(jìn)行緩沖區(qū)交換
    glutSwapBuffers();
}

1.5 繪制復(fù)雜圖形用平面著色器

//繪制復(fù)雜圖形用平面著色器
void DrawWireFramedBatch(GLBatch* pBatch)
{
    /*------------畫綠色部分----------------*/
    /* GLShaderManager 中的Uniform 值——平面著色器
     參數(shù)1:平面著色器
     參數(shù)2:運行為幾何圖形變換指定一個 4 * 4變換矩陣
          --transformPipeline 變換管線(指定了2個矩陣堆棧)
     參數(shù)3:顏色值
    */
    shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vGreen);
    pBatch->Draw();
    
    /*-----------邊框部分-------------------*/
    /*
        glEnable(GLenum mode); 用于啟用各種功能。功能由參數(shù)決定
        參數(shù)列表:http://blog.csdn.net/augusdi/article/details/23747081
        注意:glEnable() 不能寫在glBegin() 和 glEnd()中間
        GL_POLYGON_OFFSET_LINE  根據(jù)函數(shù)glPolygonOffset的設(shè)置,啟用線的深度偏移
        GL_LINE_SMOOTH          執(zhí)行后,過慮線點的鋸齒
        GL_BLEND                啟用顏色混合。例如實現(xiàn)半透明效果
        GL_DEPTH_TEST           啟用深度測試 根據(jù)坐標(biāo)的遠(yuǎn)近自動隱藏被遮住的圖形(材料
     
     
        glDisable(GLenum mode); 用于關(guān)閉指定的功能 功能由參數(shù)決定
     
     */
    
    //畫黑色邊框
    glPolygonOffset(-1.0f, -1.0f);// 偏移深度,在同一位置要繪制填充和邊線,會產(chǎn)生z沖突,所以要偏移
    glEnable(GL_POLYGON_OFFSET_LINE);
    
    // 畫反鋸齒,讓黑邊好看些
    glEnable(GL_LINE_SMOOTH);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    
    //繪制線框幾何黑色版 三種模式,實心,邊框,點,可以作用在正面,背面,或者兩面
    //通過調(diào)用glPolygonMode將多邊形正面或者背面設(shè)為線框模式,實現(xiàn)線框渲染
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    //設(shè)置線條寬度
    glLineWidth(2.5f);
    
    /* GLShaderManager 中的Uniform 值——平面著色器
     參數(shù)1:平面著色器
     參數(shù)2:運行為幾何圖形變換指定一個 4 * 4變換矩陣
         --transformPipeline.GetModelViewProjectionMatrix() 獲取的
          GetMatrix函數(shù)就可以獲得矩陣堆棧頂部的值
     參數(shù)3:顏色值(黑色)
     */
    
    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);
}

代碼全部寫完,直接編譯運行效果如下


aaaaa.gif
最后編輯于
?著作權(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)容