OpenGL(四) OpenGL圖元繪制

效果圖

我們知道、三角形是OpenGL的基本圖元。

在繪制圖元之前,我們先來了解下OpenGL常見的圖元連接方式

圖元 名稱 描述
GL_POINTS 每個頂點在屏幕上都是單獨點
GL_LINES 每一對頂點定義一個線段
GL_LINE_STRIP 線段 一個從第一個頂點依次經(jīng)過每一個后續(xù)頂點?而繪制的線條
GL_LINE_LOOP 線環(huán) GL_LINE_STRIP相同,但是最后一個頂點和第一個頂點連接起來了
GL_TRIANGLES 三角形 每3個頂點定義一個新的三?角形
GL_TRIANGLE_STRIP 三角形帶 共?一個條帶(strip)上的頂點的一組三?形
GL_TRIANGLE_FAN 三角形扇 以一個圓點為中心呈扇形排列列,共?相鄰頂點的一組三?形
圖片來源于網(wǎng)絡(luò)

了解了圖元繪制方式之后,我們用OpenGL畫一個三角形,并且可以通過鍵盤方向鍵控制三角形旋轉(zhuǎn)。

畫三角形

首先先定義一些必要的類
GLShaderManager shaderManager; // 著色器管理類

GLMatrixStack modelViewMatrix; // 模型視圖矩陣
GLMatrixStack projectionMatrix; // 投影矩陣

GLFrame cameraFrame; // 觀察者
GLFrame objectFrame; // 物體

GLFrustum viewFrustum; // 投影

GLBatch lineLoopBatch; // 線環(huán)批次類(因為是三角形)


GLGeometryTransform transformPipeLine; // 幾何變換管道


// 定義3個點(三角形的三個點)
GLfloat vCoast[9] = {
    3, 3, 0,
    0, 3, 0,
    3, 0, 0
};

GLfloat vGreen[] = { 0.0f, 1.0f, 0.0f, 1.0f }; // 綠色
GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 1.0f }; // 黑色
方法 說明
GetProjectionMatrix() 投影矩陣
GetNormalMatrix() 法線矩陣
GetModelViewMatrix() 模型視圖矩陣,簡稱mv
GetModelViewProjectionMatrix() 模型視圖投影矩陣,簡稱mvp
自定義changeSize函數(shù)

changeSize主要是用來設(shè)置視口大小以及當視口發(fā)生變化時調(diào)用的,而本案例中立體圖形的繪制需要使用投影矩陣,因此還需要在該函數(shù)中設(shè)置投影矩陣。

  • 設(shè)置視口
// 設(shè)置視口
glViewport(0, 0, w, h);
  • 創(chuàng)建透視投影
// 創(chuàng)建透視投影
//參數(shù)1:垂直方向上的視場角度
//參數(shù)2:視口縱橫比 = w/h
//參數(shù)3:近裁剪面距離
//參數(shù)4:遠裁剪面距離
viewFrustum.SetPerspective(35.0, float(w) / float(h), 1.0, 500.0);
  • 通過設(shè)置的投影方式獲得投影矩陣,并將其存入投影矩陣中
// 通過設(shè)置的投影方式獲得投影矩陣,并將其存入投影矩陣中projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
  • 初始化模型視圖矩陣堆棧,壓入一個單元矩陣
// 初始化模型視圖矩陣堆棧,壓入一個單元矩陣
modelViewMatrix.LoadIdentity();
自定義setupRC函數(shù)

setupRC主要做一些初始化的準備工作。

  • 設(shè)置背景顏色
// 背景顏色
glClearColor(0.7, 0.7, 0.7, 1.0);
  • 初始化固定著色器
// 初始化固定著色器
shaderManager.InitializeStockShaders();
  • 設(shè)置變換管道中的模型視圖矩陣和投影矩陣
// 設(shè)置變換管道中的模型視圖矩陣和投影矩陣
transformPipeLine.SetMatrixStacks(modelViewMatrix, projectionMatrix);
  • 設(shè)置下觀察者的位置
// 設(shè)置下觀察者的位置
cameraFrame.MoveForward(-15.0);
  • 通過線環(huán)的形式
lineLoopBatch.Begin(GL_LINE_LOOP, 3);
lineLoopBatch.CopyVertexData3f(vCoast);
lineLoopBatch.End();
自定義renderScene函數(shù)

renderScene函數(shù)主要做渲染

  • 清理緩存區(qū)
// 清理緩存區(qū)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
  • 壓棧
// 壓棧
modelViewMatrix.PushMatrix();
  • 獲取觀察者矩陣,并將觀察者矩陣*矩陣堆棧的頂部矩陣,相乘的結(jié)果隨后存儲在堆棧的頂部
// 獲取觀察者矩陣
M3DMatrix44f mCamera;
cameraFrame.GetCameraMatrix(mCamera);
// 觀察者矩陣*矩陣堆棧的頂部矩陣,相乘的結(jié)果隨后存儲在堆棧的頂部
// 觀察者矩陣*棧頂單元矩陣 = 新觀察者矩陣,壓棧
modelViewMatrix.MultMatrix(mCamera);
  • 獲取物體的矩陣,并將物體矩陣*矩陣堆棧的頂部矩陣,相乘的結(jié)果隨后存儲在堆棧的頂部
// 獲取物體的矩陣
M3DMatrix44f mObjectFrame;
objectFrame.GetMatrix(mObjectFrame);
// 物體矩陣*矩陣堆棧的頂部矩陣,相乘的結(jié)果隨后存儲在堆棧的頂部
modelViewMatrix.MultMatrix(mObjectFrame);
  • 使用固定管線
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeLine.GetModelViewProjectionMatrix(), vGreen);
  • 設(shè)置線寬
glPointSize(10.0);
lineLoopBatch.Draw();
glLineWidth(10.0); 
  • 出棧
// 出棧
modelViewMatrix.PopMatrix();
  • 交換緩沖區(qū)
// 交換緩沖區(qū)
glutSwapBuffers();

這兒引用一下別人的一張圖


圖片來源于網(wǎng)絡(luò)
  • changeSize函數(shù)中向棧中初始化了一個單元矩陣
  • renderScene函數(shù)中再次向棧中壓入一個單元矩陣,主要是為了圖形繪制完成后,矩陣的復(fù)原,所以此時棧中有兩個單元矩陣
  • cameraFrame構(gòu)建為觀察者矩陣,將棧頂單元矩陣取出,與觀察者矩陣相乘,得到新的觀察者矩陣,再將其入棧
  • objectFrame構(gòu)建為物體矩陣,取出棧頂?shù)挠^察者矩陣,與物體矩陣相乘,得到模型視圖矩陣,并將其入棧
  • 然后利用固定管線渲染圖形,在圖像渲染完成后,將棧中模型視圖矩陣pop,恢復(fù)其初始狀態(tài)。

自定義specialKeys函數(shù),控制三角形方式

void specialKeys(int key, int x, int y) {
    if (key == GLUT_KEY_UP) {
        // 繞x軸旋轉(zhuǎn)
        objectFrame.RotateWorld(m3dDegToRad(-5.0), 1.0, 0.0, 0.0);
    }
    if (key == GLUT_KEY_DOWN) {
        // 繞x軸旋轉(zhuǎn)
        objectFrame.RotateWorld(m3dDegToRad(5.0), 1.0, 0.0, 0.0);
    }
    if (key == GLUT_KEY_LEFT) {
        // 繞y軸旋轉(zhuǎn)
        objectFrame.RotateWorld(m3dDegToRad(-5.0), 0.0, 1.0, 0.0);
    }
    if (key == GLUT_KEY_RIGHT) {
        // 繞y軸旋轉(zhuǎn)
        objectFrame.RotateWorld(m3dDegToRad(-5.0f), 0.0f, 1.0f, 0.0f);
    }
    glutPostRedisplay();
}

main函數(shù)

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("OpenGL圖元");

    glutReshapeFunc(changeSize);
    glutDisplayFunc(renderScene);
    glutSpecialFunc(specialKeys);
    
    GLenum status = glewInit();
    if (status != GLEW_OK) {
        printf("error: %s\n", glewGetString(status));
        return 1;
    }
    
    setupRC();
    
    glutMainLoop();
    
    return 0;
}

Demo

傳送門

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