該案例主要是對常見的圖元連接方式的運用,常見的基本圖元連接方式見常見圖元的連接方式
最終實現(xiàn)的效果如圖所示:
要實現(xiàn)上面的效果挨队,我們先看一下OpenGL的繪制流程,如下圖:
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);
//設置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;
}
首先程序從main函數(shù)(設置基本參數(shù))開始運行----> changeSize函數(shù)(設置視口大小腾夯、設置投影方式)----> SetupRC函數(shù)(初始化著色器颊埃,設置管線使用模型視圖矩陣和投影矩陣、圖元數(shù)據(jù)配置)----> RenderScene函數(shù)(清空緩沖區(qū)蝶俱、使用著色器開始繪制) 班利。
在程序主運行mainLop中會繼續(xù)執(zhí)行以下函數(shù):
——————————————————mainLoop—————————————————>
[點擊空格] [特殊鍵位] [窗口改變] [繪制信息]
| | | |
[KeyPressFunc] [SpecialKeys] [ChangeSize] [RenderScene]
changeSize函數(shù)
1、設置視口的大小
2榨呆、創(chuàng)建投影矩陣(GLFrustum viewFrustum; viewFrustum.SetPerspective(<#float fFov#>, <#float fAspect#>, <#float fNear#>, <#float fFar#>))
fFov:視場角度 罗标,fAspect;橫縱比 w/h 积蜻, fNear:近裁剪面距離 , fFar: 遠裁剪面距離
3闯割、投影視圖矩陣棧加載當前投影矩陣。
4竿拆、模型視圖矩陣載入單元矩陣
// 窗口已更改大小宙拉,或剛剛創(chuàng)建。無論哪種情況丙笋,我們都需要
// 使用窗口維度設置視口和投影矩陣.
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();
}
SetupRC()函數(shù)
1、設置背景顏色御板。
2锥忿、著色器初始化
3、設置變換管線來使用模型視圖矩陣棧和投影視圖矩陣棧怠肋。
transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
其中敬鬓,變換管道通過get可獲得的矩陣有4種:
GetProjectionMatrix() :投影矩陣
GetNormalMatrix() :法線矩陣
GetModelViewMatrix() :模型視圖矩陣,簡稱mv
GetModelViewProjectionMatrix() :模型視圖投影矩陣,簡稱mvp
4列林、調(diào)整觀察者瑞你。(也可以調(diào)整物體)
cameraFrame.MoveForward(-15.0f);
觀察者位置的設置有三種:
void MoveForward(float fDelta) :向外移動的像素點,修改z
void MoveUp(float fDelta) :向上移動的像素點希痴,修改y
void MoveRight(float fDelta) :向右移動的像素點者甲,修改x
5、初始化相應的圖元信息砌创,并提交到相應的批次類虏缸。
// 此函數(shù)在呈現(xiàn)上下文中進行任何必要的初始化。.
// 這是第一次做任何與opengl相關(guān)的任務嫩实。
void SetupRC()
{
// 灰色的背景
glClearColor(0.7f, 0.7f, 0.7f, 1.0f );
shaderManager.InitializeStockShaders();
glEnable(GL_DEPTH_TEST);
//設置變換管線以使用兩個矩陣堆棧
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:紋理坐標(可選)
//負責頂點坐標
void GLBatch::CopyVertexData3f(GLFloat *vNorms);
//結(jié)束刽辙,表示已經(jīng)完成數(shù)據(jù)復制工作
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ù)組下標自增(每自增1次就表示一個頂點)
nVerts++;
/*
弧長=半徑*角度,這里的角度是弧度制,不是平時的角度制
既然知道了cos值,那么角度=arccos,求一個反三角函數(shù)就行了
*/
//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;
}
// 結(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)或圓柱段
//頂點下標
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();
}
RenderScene函數(shù)
我們通過glutDisplayFunc函數(shù)自己注冊的渲染函數(shù)。
1镊尺、清空緩沖區(qū)朦佩。
2、模型視圖矩陣堆棧壓棧鹅心、將獲得的模型矩陣和視圖矩陣依次壓棧(該矩陣與取出的堆棧頂部矩陣相乘然后壓入堆棧)
3吕粗、通過變換管線獲得模型視圖矩陣來配置著色器纺荧。
4旭愧、根據(jù)一些參數(shù)來更改繪制圖元的樣式進行繪制。
5宙暇、模型視圖矩陣堆棧出棧(恢復初始值输枯,用完即恢復)
6、進行緩沖區(qū)交換
// 召喚場景
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ù)可以進行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);
switch(nStep) {
case 0:
//設置點的大小
glPointSize(4.0f);
pointBatch.Draw();
glPointSize(1.0f);
break;
case 1:
//設置線的寬度
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();
// 進行緩沖區(qū)交換
glutSwapBuffers();
}
SpecialKeys函數(shù)
我們自己注冊的特殊鍵位函數(shù)
/特殊鍵位處理(上、下螟深、左谐宙、右移動)
void SpecialKeys(int key, int x, int y)
{
if(key == GLUT_KEY_UP)
//圍繞一個指定的X,Y,Z軸旋轉(zhuǎn)。
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();
}
KeyPressFunc函數(shù)
我們自己注冊的空格鍵位函數(shù)用來更改繪制的圖形
//根據(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;
}
glutPostRedisplay();
}
在繪制金字塔凡蜻、圓環(huán)、扇形的過程中分別使用了對應的批次類(triangleBatch垢箕、triangleStripBatch划栓、triangleFanBatch)進行繪制即可,但是為了更好的體現(xiàn)出效果条获,我們可以在圖形上加上描邊忠荞。
/*------------畫綠色部分----------------*/
/* 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的設置帅掘,啟用線的深度偏移
GL_LINE_SMOOTH 執(zhí)行后钻洒,過慮線點的鋸齒
GL_BLEND 啟用顏色混合。例如實現(xiàn)半透明效果
GL_DEPTH_TEST 啟用深度測試 根據(jù)坐標的遠近自動隱藏被遮住的圖形(材料
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將多邊形正面或者背面設為線框模式鲫惶,實現(xiàn)線框渲染
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
//設置線條寬度
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();
// 復原原本的設置
//通過調(diào)用glPolygonMode將多邊形正面或者背面設為全部填充模式
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glDisable(GL_POLYGON_OFFSET_LINE);
glLineWidth(1.0f);
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);