OpenGL初識之OpenGL渲染基礎(chǔ)概念傳送門http://www.reibang.com/p/d26879a736af
接著上一節(jié)我們學(xué)習(xí)了OpenGL渲染基礎(chǔ)许饿,現(xiàn)在我們來綜合使用一下,練習(xí)一下繪制OpenGL圖元并組合圖元:
一眼姐、繪制圖元點
二者蠕、繪制圖元線段/連續(xù)線段/線環(huán)
三窃祝、繪制金字塔
四、圖元渲染三角形帶/三角形扇
一踱侣、繪制圖元點
先上繪制的總結(jié)思路圖
開始準(zhǔn)備環(huán)境和對應(yīng)的函數(shù)(詳細介紹請移步我之前的文章,傳送門:基本函數(shù)解釋http://www.reibang.com/p/b98be0925051)
這里主要說明有區(qū)別的地方
1粪小、設(shè)置全局變量
GLShaderManager shaderManager;//著色器管理
GLMatrixStack modelViewMatrix;//模型視圖矩陣堆棧
GLMatrixStack projectViewMatrix;//投影矩陣堆棧
GLFrame cameraFrame;//觀察者
GLFrame objectFrame;
GLFrustum viewFrustum;//投影矩陣
//批次類(7種不同的圖元,對應(yīng)7種容器對象)
GLBatch pointBatch;//點
GLBatch lineBatch;//線
GLBatch lineStripBatch;//連線
GLBatch lineLoopBatch;//線環(huán)
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};
//設(shè)置按空格鍵來切換不同圖元展示
//記錄按了幾次空格
int nStep = 0;
2泻仙、設(shè)置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("Triangle");
glutReshapeFunc(ChangeSize);
glutDisplayFunc(RenderScene);
glutSpecialFunc(SpecialKeys);
//注冊點擊空格會調(diào)用的函數(shù)
glutKeyboardFunc(KeyPressFunc);
GLenum err = glewInit();
if(GLEW_OK != err) {
fprintf(stderr,"glew error:%s\n",glewGetErrorString(err));
return 1;
}
SetupRC();
glutMainLoop();
return 0;
}
3糕再、設(shè)置SetupRC函數(shù),注釋我都寫在里面了
//1、設(shè)置背景顏色
glClearColor(0.7f, 0.7f, 0.7f,1.0);
//2玉转、初始化著色器管理器
shaderManager.InitializeStockShaders();
//3突想、開啟深度測試
glEnable(GL_DEPTH_TEST);
//4、設(shè)置變換管道
transformPipeline.SetMatrixStacks(modelViewMatrix, projectViewMatrix);
//5究抓、設(shè)置觀察者位置猾担,便于觀察效果
cameraFrame.MoveForward(-15);
//6、設(shè)置一些點
//創(chuàng)建一維的六個點的數(shù)組
GLfloat vCoast[18] = {
3,3,0,
-3,3,0,
3,0,0,
-3,0,0,
3,-3,0,
-3,-3,0
};
//設(shè)置圖元渲染方式刺下,點
pointBatch.Begin(GL_POINTS, 6);
pointBatch.CopyVertexData3f(vCoast);
pointBatch.End();
4绑嘹、設(shè)置ChangeSize函數(shù),需要注意的是,這個函數(shù)的調(diào)用時機橘茉,就是窗口已更改大小工腋,或剛剛創(chuàng)建,無論是那種情況畅卓,我們都需要使用窗口維度設(shè)置視口和設(shè)置投影矩陣
//1擅腰、設(shè)置視口
glViewport(0, 0, w, h);
//2、投影矩陣: 需要設(shè)置縱橫比
viewFrustum.SetPerspective(35, floorf(w) / floorf(h), 1.0, 500);
//3翁潘、設(shè)置投影矩陣,加載投影矩陣
projectViewMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
//4趁冈、模型視圖視圖矩陣堆棧,加載單元矩陣
modelViewMatrix.LoadIdentity();
5、設(shè)置渲染RenderScence函數(shù)
//1渗勘、清除緩沖區(qū)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//2沐绒、模型視圖矩陣---壓棧
modelViewMatrix.PushMatrix();
M3DMatrix44f mCamera;
cameraFrame.GetCameraMatrix(mCamera);
modelViewMatrix.MultMatrix(mCamera);//矩陣相乘,得到變換后的新矩陣
M3DMatrix44f mObjectFrame;
objectFrame.GetMatrix(mObjectFrame);
modelViewMatrix.MultMatrix(mObjectFrame);//矩陣相乘旺坠,得到變換后的新矩陣
//3乔遮、挑選平面著色器渲染
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vGreen);
//4、容器類提交繪制
switch (nStep) {
case 0:
//設(shè)置點的大小
glPointSize(20.0f);
pointBatch.Draw();
glPointSize(1.0f);
break;
default:
break;
}
//5价淌、模型視圖矩陣---出棧申眼,還原到以前的模型視圖矩陣
modelViewMatrix.PopMatrix();
//6、交換緩沖區(qū)
glutSwapBuffers();
6蝉衣、設(shè)置特殊鍵位函數(shù)
void SpecialKeys (int key , int x, int y){
//點擊鍵盤上的上下左右鍵
if (key == GLUT_KEY_UP) {
//往上移動,圍繞X軸巷蚪,是順時針方向病毡,由于逆時針為正,所以是-5.0
//m3dDegToRad() 角度轉(zhuǎn)弧度函數(shù)
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);
}
//發(fā)生變化需要重新渲染
glutPostRedisplay();
}
7爹谭、設(shè)置空格切換函數(shù)KeyPressFunc(這個主要是用來切換不同圖元)
void KeyPressFunc(unsigned char key, int x, int y){
//不斷點擊空格修改nStep記錄步數(shù)
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();
}
二、繪制圖元線段/連續(xù)線段/線環(huán)
繪制圖元點的寫完后榛搔,設(shè)置繪制圖元線段/連續(xù)線段/線環(huán) 诺凡,只需要配置SetupRC里面設(shè)置對應(yīng)圖元,然后再RenderScence修改圖元繪制就行了践惑,對應(yīng)修改的位置如下
1腹泌、修改SetupRC部分代碼
//1/設(shè)置圖元渲染方式,點
pointBatch.Begin(GL_POINTS, 6);
pointBatch.CopyVertexData3f(vCoast);
pointBatch.End();
//2/設(shè)置圖元渲染方式,線段
lineBatch.Begin(GL_LINES, 6);
lineBatch.CopyVertexData3f(vCoast);
lineBatch.End();
//3/設(shè)置圖元渲染方式童本,連續(xù)線段
lineStripBatch.Begin(GL_LINE_STRIP, 6);
lineStripBatch.CopyVertexData3f(vCoast);
lineStripBatch.End();
//4/設(shè)置圖元渲染方式,線環(huán)
lineLoopBatch.Begin(GL_LINE_LOOP, 6);
lineLoopBatch.CopyVertexData3f(vCoast);
lineLoopBatch.End();
2真屯、修改RenderScence對應(yīng)部分代碼
switch (nStep) {
case 0:
//設(shè)置點的大小
glPointSize(20.0f);
pointBatch.Draw();
glPointSize(1.0f);
break;
case 1:
//設(shè)置線段寬度
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;
}
三、渲染圖元金字塔
接下來我們繪制金字塔穷娱,金字塔是由一個底面和四個側(cè)面組成绑蔫,金字塔沒有底面的話运沦,其實側(cè)面是由4個三角形組成的,如果有底面的話配深,底面是兩個三角形組成的携添,和上面不同圖元繪制的方式類似,只需要修改SetupRC和RenderScene對應(yīng)的代碼就行了
1篓叶、SetupRC函數(shù)中設(shè)置金字塔四個頂點坐標(biāo)數(shù)據(jù)和圖元裝配方式
//設(shè)置金字塔的頂點數(shù)據(jù)
//通過三角形創(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};
//GL_TRIANGLES 每3個頂點定義一個新的三角形
triangleBatch.Begin(GL_TRIANGLES, 12);
triangleBatch.CopyVertexData3f(vPyramid);
triangleBatch.End();
2烈掠、RenderScence繪制金字塔
case 4:
triangleBatch.Draw();
break;
四、圖元渲染三角形扇/圖元渲染三角形帶
1缸托、繪制六邊形三角形扇
修改SetupRC左敌,設(shè)置頂點數(shù)據(jù),該頂點的坐標(biāo)數(shù)據(jù)是通過半徑和角度求來的俐镐,下面這段代碼的循環(huán)矫限,就是為了求六邊形七個頂點的位置坐標(biāo),六個頂點和一個中心點
// 三角形扇形--六邊形
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個頂點(包括圓心)
//添加閉合的終點
//如果屏蔽173-177行代碼,并把繪制節(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();
2枢里、繪制六邊形三角形扇,修改RenderScence
case 6:
triangleFanBatch.Draw();
break;
3孽鸡、繪制三角形帶,配置頂點坐標(biāo)以及圖元裝配方式
//三角形條帶坡垫,一個小環(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)
//結(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();
4堡妒、繪制三角形帶,修改RenderScence
case 5:
triangleStripBatch.Draw();
break;
運行得到所有的樣式,如下圖: