
效果圖
我們知道點、線、三角形是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;
}