六、OpenGL初探之OpenGL渲染基礎綜合實戰

OpenGL初識之OpenGL渲染基礎概念傳送門 juejin.im/post/5d67e5…數組

接着上一節咱們學習了OpenGL渲染基礎,如今咱們來綜合使用一下,練習一下繪製OpenGL圖元並組合圖元:bash

1、繪製圖元點
2、繪製圖元線段/連續線段/線環
3、繪製金字塔
4、圖元渲染三角形帶/三角形扇
複製代碼

1、繪製圖元點


先上繪製的總結思路圖 函數

OpenGL渲染業務介紹.png

開始準備環境和對應的函數(詳細介紹請移步我以前的文章,傳送門:基本函數解釋 juejin.im/post/5d67e4… 這裏主要說明有區別的地方)oop

一、設置全局變量post

GLShaderManager shaderManager;//着色器管理
GLMatrixStack modelViewMatrix;//模型視圖矩陣堆棧
GLMatrixStack projectViewMatrix;//投影矩陣堆棧
GLFrame cameraFrame;//觀察者
GLFrame objectFrame;

GLFrustum viewFrustum;//投影矩陣

//批次類(7種不一樣的圖元,對應7種容器對象)
GLBatch pointBatch;//點
GLBatch lineBatch;//線
GLBatch lineStripBatch;//連線
GLBatch lineLoopBatch;//線環
GLBatch triangleBatch;//三級形
GLBatch triangleStripBatch;//三角形帶
GLBatch triangleFanBatch;//三角形扇

//幾何變換管道
GLGeometryTransform transformPipeline;
//顏色RGBA
GLfloat vGreen[] = {0.0f, 1.0f, 0.0f, 1.0f};
GLfloat vYellow[] = {1.0f,1.0f, 0.0f, 1.0f};
//設置按空格鍵來切換不一樣圖元展現
//記錄按了幾回空格
int nStep = 0;

複製代碼

二、設置main函數學習

int main(int argc,char* argv[]){
    
    gltSetWorkingDirectory(argv[0]);
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL);
    glutInitWindowSize(800,600);
    glutCreateWindow("Triangle");
    
    glutReshapeFunc(ChangeSize);
    glutDisplayFunc(RenderScene);
    glutSpecialFunc(SpecialKeys);
    
    //註冊點擊空格會調用的函數
    glutKeyboardFunc(KeyPressFunc);
    
    GLenum err = glewInit();
    if(GLEW_OK != err) {
        fprintf(stderr,"glew error:%s\n",glewGetErrorString(err));
        return 1;
    }
    
    SetupRC();
    glutMainLoop();
    return 0;
}

複製代碼

三、設置SetupRC函數,註釋我都寫在裏面了測試

//一、設置背景顏色
    glClearColor(0.7f, 0.7f, 0.7f,1.0);
    //二、初始化着色器管理器
    shaderManager.InitializeStockShaders();
    //三、開啓深度測試
    glEnable(GL_DEPTH_TEST);
    //四、設置變換管道
    transformPipeline.SetMatrixStacks(modelViewMatrix, projectViewMatrix);
    //五、設置觀察者位置,便於觀察效果
    cameraFrame.MoveForward(-15);
    
    //六、設置一些點
    //建立一維的六個點的數組
    GLfloat vCoast[18] = {
        3,3,0,
        -3,3,0,
        3,0,0,
        -3,0,0,
        3,-3,0,
        -3,-3,0
    };

    //設置圖元渲染方式,點
    pointBatch.Begin(GL_POINTS, 6);
    pointBatch.CopyVertexData3f(vCoast);
    pointBatch.End();

複製代碼

四、設置ChangeSize函數,須要注意的是,這個函數的調用時機,就是窗口已更改大小,或剛剛建立,不管是那種狀況,咱們都須要使用窗口維度設置視口和設置投影矩陣ui

//一、設置視口
    glViewport(0, 0, w, h);
    //二、投影矩陣: 須要設置縱橫比
    viewFrustum.SetPerspective(35, floorf(w) / floorf(h), 1.0, 500);
    //三、設置投影矩陣,加載投影矩陣
projectViewMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    //四、模型視圖視圖矩陣堆棧,加載單元矩陣
    modelViewMatrix.LoadIdentity();

複製代碼

五、設置渲染RenderScence函數spa

//一、清除緩衝區
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    //二、模型視圖矩陣---壓棧
    modelViewMatrix.PushMatrix();
    M3DMatrix44f mCamera;
    cameraFrame.GetCameraMatrix(mCamera);
    modelViewMatrix.MultMatrix(mCamera);//矩陣相乘,獲得變換後的新矩陣
    
    M3DMatrix44f mObjectFrame;
    objectFrame.GetMatrix(mObjectFrame);    
    modelViewMatrix.MultMatrix(mObjectFrame);//矩陣相乘,獲得變換後的新矩陣

    //三、挑選平面着色器渲染
    shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vGreen);
    
    
    //四、容器類提交繪製
    switch (nStep) {
        case 0:
            //設置點的大小
            glPointSize(20.0f);
            pointBatch.Draw();
            glPointSize(1.0f);
            break;
            
                default:
            break;
    }
    
    //五、模型視圖矩陣---出棧,還原到之前的模型視圖矩陣
    modelViewMatrix.PopMatrix();
    //六、交換緩衝區
    glutSwapBuffers();

複製代碼

六、設置特殊鍵位函數3d

void SpecialKeys (int key , int x, int y){
    //點擊鍵盤上的上下左右鍵
    if (key == GLUT_KEY_UP) {
        //往上移動,圍繞X軸,是順時針方向,因爲逆時針爲正,因此是-5.0
        //m3dDegToRad() 角度轉弧度函數
        objectFrame.RotateWorld(m3dDegToRad(-5.0), 1.0, 0, 0);//其中的1.0表示YES,0.0表示NO
    }else if (key == GLUT_KEY_DOWN) {
        //往下移動,圍繞X軸,是逆時針方向,因爲逆時針爲正,因此是5.0
        objectFrame.RotateWorld(m3dDegToRad(5.0), 1.0, 0, 0);
    }else if (key == GLUT_KEY_LEFT) {
        //往左移動,圍繞Y軸,是順時針方向,因爲逆時針爲正,因此是-5.0
        objectFrame.RotateWorld(m3dDegToRad(-5.0), 0.0, 1.0, 0);
    }else if (key == GLUT_KEY_RIGHT) {
        //往右移動,圍繞Y軸,是逆時針方向,因爲逆時針爲正,因此是5.0
        objectFrame.RotateWorld(m3dDegToRad(5.0), 0.0, 1.0, 0);
    }
   
    //發生變化須要從新渲染
    glutPostRedisplay();
}

複製代碼

七、設置空格切換函數KeyPressFunc(這個主要是用來切換不一樣圖元)

void KeyPressFunc(unsigned char key, int x, int y){
    //不斷點擊空格修改nStep記錄步數
    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;
    }
    
    glutPostRedisplay();
}


複製代碼

2、繪製圖元線段/連續線段/線環


繪製圖元點的寫完後,設置繪製圖元線段/連續線段/線環 ,只須要配置SetupRC裏面設置對應圖元,而後再RenderScence修改圖元繪製就好了,對應修改的位置以下

一、修改SetupRC部分代碼

//1/設置圖元渲染方式,點
    pointBatch.Begin(GL_POINTS, 6);
    pointBatch.CopyVertexData3f(vCoast);
    pointBatch.End();
    
    //2/設置圖元渲染方式,線段
    lineBatch.Begin(GL_LINES, 6);
    lineBatch.CopyVertexData3f(vCoast);
    lineBatch.End();
    
    //3/設置圖元渲染方式,連續線段
    lineStripBatch.Begin(GL_LINE_STRIP, 6);
    lineStripBatch.CopyVertexData3f(vCoast);
    lineStripBatch.End();
    
    //4/設置圖元渲染方式,線環
    lineLoopBatch.Begin(GL_LINE_LOOP, 6);
    lineLoopBatch.CopyVertexData3f(vCoast);
    lineLoopBatch.End();

複製代碼

二、修改RenderScence對應部分代碼

switch (nStep) {
        case 0:
            //設置點的大小
            glPointSize(20.0f);
            pointBatch.Draw();
            glPointSize(1.0f);
            break;
            
        case 1:
            //設置線段寬度
            glLineWidth(5.0f);
            lineBatch.Draw();
            glLineWidth(1.0f);
            break;
            
        case 2:
            //
            glLineWidth(5.0f);
            lineStripBatch.Draw();
            glLineWidth(1.0f);
            break;
        case 3:
            glLineWidth(5.0f);
            lineLoopBatch.Draw();
            glLineWidth(1.0f);
            
            break;
            
        default:
            break;
    }


複製代碼

3、渲染圖元金字塔


接下來咱們繪製金字塔,金字塔是由一個底面和四個側面組成,金字塔沒有底面的話,其實側面是由4個三角形組成的,若是有底面的話,底面是兩個三角形組成的,和上面不一樣圖元繪製的方式相似,只須要修改SetupRC和RenderScene對應的代碼就好了

一、SetupRC函數中設置金字塔四個頂點座標數據和圖元裝配方式

//設置金字塔的頂點數據
	//經過三角形建立金字塔
    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個頂點定義一個新的三角形
    triangleBatch.Begin(GL_TRIANGLES, 12);
    triangleBatch.CopyVertexData3f(vPyramid);
    triangleBatch.End();


複製代碼

二、RenderScence繪製金字塔

case 4:
        triangleBatch.Draw();
        break;

複製代碼

4、圖元渲染三角形扇/圖元渲染三角形帶


一、繪製六邊形三角形扇 修改SetupRC,設置頂點數據,該頂點的座標數據是經過半徑和角度求來的,下面這段代碼的循環,就是爲了求六邊形七個頂點的位置座標,六個頂點和一箇中心點

// 三角形扇形--六邊形
    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) {
        
        //數組下標自增(每自增1次就表示一個頂點)
        nVerts++;
        /*
         弧長=半徑*角度,這裏的角度是弧度制,不是平時的角度制
         既然知道了cos值,那麼角度=arccos,求一個反三角函數就好了
         */
        //x點座標 cos(angle) * 半徑
        vPoints[nVerts][0] = float(cos(angle)) * r;
        //y點座標 sin(angle) * 半徑
        vPoints[nVerts][1] = float(sin(angle)) * r;
        //z點的座標
        vPoints[nVerts][2] = -0.5f;
    }
    
    // 結束扇形 前面一共繪製7個頂點(包括圓心)
    //添加閉合的終點
    //若是屏蔽173-177行代碼,並把繪製節點改成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();

複製代碼

二、繪製六邊形三角形扇,修改RenderScence

case 6:   
        triangleFanBatch.Draw();
        break;

複製代碼

三、繪製三角形帶,配置頂點座標以及圖元裝配方式

//三角形條帶,一個小環或圓柱段
    //頂點下標
    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++;
    }
    
    // 關閉循環
    //結束循環,在循環位置生成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();

複製代碼

四、繪製三角形帶,修改RenderScence

case 5:
        triangleStripBatch.Draw();
        break;

複製代碼

運行獲得全部的樣式,以下圖:

圖元繪製實戰.png
相關文章
相關標籤/搜索