OpenGL基本圖元繪制實(shí)操
基于Mac OS系統(tǒng),我們需要新建一個(gè)mac OS的app,并且導(dǎo)入OpenGL的框架還有平臺(tái)工具框架OpenGL.framework
和GLUT.framework
!
接著我們需要導(dǎo)入其它東西,例如GLTools.h
和glew.h
等(這些東西會(huì)包含在后面的demo里面)豺妓。接著,設(shè)置頭文件的search就好了,打開(kāi)Build Settings
搜索Header Search Paths
,拖入我們include下的上面兩個(gè)頭文件的路徑就OK了,至此,配置就ojbk了!開(kāi)始干活...
需要用到的庫(kù)和頭文件
#include "GLTools.h"
#include "GLMatrixStack.h" //矩陣的工具類,可以利于GLMatrixStack 加載單元矩陣/矩陣相乘/壓棧/出棧/縮放/平移/旋轉(zhuǎn)
#include "GLFrame.h" //矩陣工具類,表示位置,通過(guò)設(shè)置vOrigin, vForward, vUp等
#include "GLFrustum.h" //矩陣工具類,用來(lái)快速設(shè)置 正/透視投影矩陣,完成坐標(biāo)從3D->2D映射過(guò)程
#include "GLBatch.h" // 三角形批次類,幫助類,利用它可以傳輸頂點(diǎn)/光照/紋理/顏色數(shù)據(jù)到存儲(chǔ)著色器中
#include "GLGeometryTransform.h" //變換管道類,用來(lái)快速在代碼中傳輸視圖矩陣/投影矩陣/視圖投影變換矩陣等
#include <math.h>
#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif
需要定義的屬性和類
#pragma mark ---- 定義屬性
//存儲(chǔ)著色器管理器
GLShaderManager shaderManager;
//模型視圖矩陣
GLMatrixStack modelViewMatrix;
//投影矩陣
GLMatrixStack projectionMatrix;
//管擦著視圖坐標(biāo)
GLFrame cameraFrame;
//設(shè)置圖形環(huán)繞時(shí),視圖坐標(biāo)
GLFrame objectFrame;
//設(shè)置圖元繪制時(shí)的投影方式
GLFrustum viewFrustum;
//點(diǎn)圖元容器
GLBatch pointBatch;
//線段圖元容器
GLBatch lineBatch;
//連線圖元容器
GLBatch lineStripBatch;
//閉合連線圖元容器
GLBatch lineLoopBatch;
//三角形圖元容器
GLBatch triangleBatch;
//共用頂點(diǎn)的三角形圖元容器
GLBatch triangleStripBatch;
//圍繞一個(gè)圓點(diǎn),共用相鄰頂點(diǎn)的三角形圖元容器
GLBatch triangleFanBatch;
//幾何變換管道
GLGeometryTransform transformPipeline;
GLfloat vGreen[] = {0.0f, 1.0f, 0.0f, 1.0f};//綠色
GLfloat vRed[] = {1.0f, 0.0f, 0.0f, 1.0f};//紅色
GLfloat vBlack[] = {0.0f, 0.0f, 0.0f, 1.0f};//黑色
//跟蹤效果步驟 ,記錄用戶按空格的次數(shù),用來(lái)顯示渲染不同的圖形
int nStep = 0;
編寫需要注冊(cè)的函數(shù),幾個(gè)重要的函數(shù)
-
void SetupRC()
:自定義函數(shù),設(shè)置你需要渲染的圖形的相關(guān)頂點(diǎn)數(shù)據(jù)/顏色數(shù)據(jù)等數(shù)據(jù)裝備工作
/// 此函數(shù)在呈現(xiàn)上下文中進(jìn)行任何必要的初始化
void SetupRC()
{
//設(shè)置灰色背景
glClearColor(0.7f, 0.7f, 0.7f, 1.0f);
//初始化管理器
shaderManager.InitializeStockShaders();
//開(kāi)啟深度測(cè)試
glEnable(GL_DEPTH_TEST);
//設(shè)置變換管線以下使用兩個(gè)矩陣堆棧
transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
//設(shè)置視角
cameraFrame.MoveForward(-15.0f);
// 定義三個(gè)頂點(diǎn)
GLfloat vCoast[9] = {
3, 3, 0,
0, 3, 0,
3, 0, 0
};
//用點(diǎn)的方式
//參數(shù)1 :表示使用的圖元樣式
//參數(shù)2 :頂點(diǎn)數(shù)
//參數(shù)3 :紋理坐標(biāo)(可選)...
pointBatch.Begin(GL_POINTS, 3);
//復(fù)制頂點(diǎn)坐標(biāo)進(jìn)內(nèi)存
pointBatch.CopyVertexData3f(vCoast);
//結(jié)束,表示已經(jīng)完成數(shù)據(jù)復(fù)制工作
pointBatch.End();
//通過(guò)線的方式
lineBatch.Begin(GL_LINES, 3);
lineBatch.CopyVertexData3f(vCoast);
lineBatch.End();
//通過(guò)線段的形式
lineStripBatch.Begin(GL_LINE_STRIP, 3);
lineStripBatch.CopyVertexData3f(vCoast);
lineStripBatch.End();
//通過(guò)線環(huán)的樣式
lineLoopBatch.Begin(GL_LINE_LOOP, 3);
lineLoopBatch.CopyVertexData3f(vCoast);
lineLoopBatch.End();
//通過(guò)三角形創(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
};
//通過(guò)GL_TRIANGLES 每三個(gè)頂點(diǎn)定義一個(gè)新的三角形
triangleBatch.Begin(GL_TRIANGLES, 12);
triangleBatch.CopyVertexData3f(vPyramid);
triangleBatch.End();
//三角形扇形--六邊形
GLfloat vPoints[100][3];
int nVerts = 0;
//設(shè)置半徑
GLfloat r = 3.0f;
//設(shè)置原點(diǎn)
vPoints[nVerts][0] = 0.0f;
vPoints[nVerts][1] = 0.0f;
vPoints[nVerts][2] = 0.0f;
for (GLfloat angle = 0; angle < M3D_2PI; angle += M3D_2PI / 6.0f) {
//數(shù)組下標(biāo)自增(每自增一次就表示一個(gè)頂點(diǎn))
nVerts++;
/*
弧長(zhǎng)=半徑*角度,這里的角度是弧度制,不是平時(shí)的角度制
既然知道了cos值,那么角度=arccos,求一個(gè)反三角函數(shù)就行了
*/
//x點(diǎn)坐標(biāo) cos(angle) * 半徑
vPoints[nVerts][0] = float(cos(angle)) * r;
//y點(diǎn)坐標(biāo) sin(angle) * 半徑
vPoints[nVerts][1] = float(sin(angle)) * r;
//z點(diǎn)的坐標(biāo)
vPoints[nVerts][2] = -1.0f;
}
//結(jié)束扇形,前面一共繪制7個(gè)頂點(diǎn)(包含圓心),不添加閉合點(diǎn),則三角扇形是無(wú)法閉合的波势。
nVerts++;
vPoints[nVerts][0] = r;
vPoints[nVerts][1] = 0;
vPoints[nVerts][2] = 0.0f;
//加載,GL_TRIANGLE_FAN,以一個(gè)圓心為中心呈扇形排列,共用相鄰頂點(diǎn)的一組三角形
triangleFanBatch.Begin(GL_TRIANGLE_FAN, 8);
triangleFanBatch.CopyVertexData3f(vPoints);
triangleFanBatch.End();
//三角形條帶,圓柱環(huán)
//頂點(diǎn)下標(biāo)
int iCounter = 0;
//半徑
GLfloat radius = 3.0f;
//從 0 度~ 360度,以0.3弧度為步長(zhǎng)
for (GLfloat angle = 0.0f; angle <= (2.0f * M3D_PI); angle += 0.3f) {
//獲取圓形的頂點(diǎn)X,Y
GLfloat x = radius *sin(angle);
GLfloat y = radius *cos(angle);
//繪制拼接的兩個(gè)三角形(它們的想,y頂點(diǎn)一樣,只有z點(diǎn)不一樣)
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++;
}
//結(jié)束循環(huán),在循環(huán)末尾生成兩個(gè)拼接三角形
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 共用一個(gè)條帶上的頂點(diǎn)的一組三角形
triangleStripBatch.Begin(GL_TRIANGLE_STRIP, iCounter);
triangleStripBatch.CopyVertexData3f(vPoints);
triangleStripBatch.End();
}
-
void RenderScene()
:自定義函數(shù),通過(guò)glutDisplayFunc(函數(shù)名)
注冊(cè)為顯示渲染函數(shù),當(dāng)屏幕發(fā)生變化/或者開(kāi)發(fā)者主動(dòng)渲染會(huì)調(diào)用此函數(shù),用來(lái)實(shí)現(xiàn)數(shù)據(jù)->渲染過(guò)程
/// 召喚渲染,每次有改變都要重新渲染
void RenderScene()
{
//清空當(dāng)前畫布,每次渲染之前必須做
//GL_COLOR_BUFFER_BIT :顏色
//GL_DEPTH_BUFFER_BIT :深度
//GL_STENCIL_BUFFER_BIT :模版
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
//壓棧
modelViewMatrix.PushMatrix();
M3DMatrix44f mCamera;
//獲取視角矩陣
cameraFrame.GetCameraMatrix(mCamera);
//矩陣乘以矩陣堆棧的頂部矩陣,相乘的結(jié)果隨后就存儲(chǔ)在堆棧的頂部
modelViewMatrix.MultMatrix(mCamera);
M3DMatrix44f mObjectFrame;
//只要使用 GetMatrix 函數(shù)就可以可以獲取矩陣堆棧頂部的值,這個(gè)海曙可以進(jìn)行二次重載。
//可以用來(lái)給GLShaderManager的使用
//可以獲取頂部矩陣的頂點(diǎn)副本數(shù)據(jù)
objectFrame.GetCameraMatrix(mObjectFrame);
modelViewMatrix.MultMatrix(mObjectFrame);
/*
參數(shù)1:平面著色器
參數(shù)2:運(yùn)行為幾何圖形變換指定一個(gè)4 * 4變換矩陣
參數(shù)3:顏色值,紅色
*/
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(),vRed);
switch (nStep) {
case 0:
glPointSize(10.0f);//設(shè)置點(diǎn)大小
pointBatch.Draw();
glPointSize(1.0f);//恢復(fù)原來(lái)大小
break;
case 1:
glLineWidth(5.0f);//設(shè)置線寬
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;
case 4:
DrawWireFrameBatch(&triangleBatch);
break;
case 5:
DrawWireFrameBatch(&triangleStripBatch);
break;
case 6:
DrawWireFrameBatch(&triangleFanBatch);
break;
default:
break;
}
//出棧,還原到以前的視圖模型矩陣(單位矩陣)
modelViewMatrix.PopMatrix();
//進(jìn)行緩沖區(qū)交換
glutSwapBuffers();
}
-
void ChangeSize(int w, int h)
窗口改變大小,或者剛剛創(chuàng)建,都需要使用窗口設(shè)置視口和投影矩陣
//窗口更改大小,或者剛剛創(chuàng)建,無(wú)論哪種情況,我們都需要
//使用窗口維度設(shè)置視口和投影矩陣
void ChangeSize(int w, int h)
{
glViewport(0, 0, w, h);
//創(chuàng)建投影矩陣,并將它載入投影矩陣堆棧中
viewFrustum.SetPerspective(35.0f, float(w)/float(h), 1.0f, 500.f);
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
//調(diào)用頂部載入單元矩陣
modelViewMatrix.LoadIdentity();
}
-
void SpecialKeys(int key, int x, int y)
:監(jiān)聽(tīng)特殊鍵位操作(上下左右等)
/// 特殊鍵位處理(上,下,左,右移動(dòng))
void SpecialKeys(int key, int x, int y)
{
if (key == GLUT_KEY_UP) {
//圍繞一個(gè)指定的X,Y,Z軸旋轉(zhuǎn)
objectFrame.RotateWorld(m3dDegToRad(-5.0f), 1.0f, 0.0f, 0.0f);
}
if (key == GLUT_KEY_DOWN) {
//圍繞一個(gè)指定的X,Y,Z軸旋轉(zhuǎn)
objectFrame.RotateWorld(m3dDegToRad(5.0f), 1.0f, 0.0f, 0.0f);
}
if (key == GLUT_KEY_LEFT) {
//圍繞一個(gè)指定的X,Y,Z軸旋轉(zhuǎn)
objectFrame.RotateWorld(m3dDegToRad(-5.0f), 0.0f, 1.0f, 0.0f);
}
if (key == GLUT_KEY_RIGHT) {
//圍繞一個(gè)指定的X,Y,Z軸旋轉(zhuǎn)
objectFrame.RotateWorld(m3dDegToRad(5.0f), 0.0f, 1.0f, 0.0f);
}
glutPostRedisplay();//開(kāi)啟重繪
}
-
void KeyPressFunc(unsigned char key, int x, int y)
監(jiān)聽(tīng)空格按鈕
//根據(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();
}
抽離繪制復(fù)雜圖元的函數(shù)
-
void DrawWireFrameBatch(GLBatch *vBatch)
根據(jù)圖元容器,繪制圖元
void DrawWireFrameBatch(GLBatch *vBatch)
{
//參數(shù)列表參考:http://blog.csdn.net/augusdi/article/details/23747081
shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeline.GetModelViewProjectionMatrix(),vGreen);
vBatch->Draw();
//畫黑色邊框
//偏移深度,在同一位置要繪制填充和邊線,會(huì)在z產(chǎn)生沖突,所以要偏移
glPolygonOffset(-1.0f, -1.0f);
glEnable(GL_POLYGON_OFFSET_LINE);
//畫反鋸齒,讓黑邊絲滑
glEnable(GL_LINE_SMOOTH);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//繪制線框幾何黑色版,三種模式,實(shí)心,邊框,點(diǎn),可以作用在正面,背面,或者兩面
//通過(guò)調(diào)用glPolygonMode將多邊形正面或者背面設(shè)為線框模式,實(shí)現(xiàn)線框渲染
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
//設(shè)置線條寬度
glLineWidth(5.0f);
//繪制平面著色
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(),vBlack);
vBatch->Draw();
//復(fù)原原本的設(shè)置
//通過(guò)調(diào)用glPolygonMode將多邊形正面或者背面設(shè)為全部填充模式
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glDisable(GL_POLYGON_OFFSET_LINE);
glLineWidth(1.0f);
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
}
main函數(shù)調(diào)用,里面需要初始化GLUT的環(huán)境,確認(rèn)glew庫(kù)是否能初始化,配置項(xiàng)目能正常使用OpenGL框架
int main(int argc, char* argv[])
{
gltSetWorkingDirectory(argv[0]);
glutInit(&argc, argv);
//申請(qǐng)一個(gè)顏色緩存區(qū),深度緩存區(qū),雙緩存區(qū),模版緩存區(qū)
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL);
//設(shè)置window的尺寸
glutInitWindowSize(900, 600);
//創(chuàng)建window名稱
glutCreateWindow("GL_POINTS");
//注冊(cè)尺寸改變的回調(diào)函數(shù)
glutReshapeFunc(ChangeSize);
//注冊(cè)點(diǎn)擊空格的回調(diào)函數(shù)
glutKeyboardFunc(KeyPressFunc);
//注冊(cè)特殊鍵位回調(diào)函數(shù)(上下左右)
glutSpecialFunc(SpecialKeys);
//注冊(cè)渲染刷新顯示函數(shù)
glutDisplayFunc(RenderScene);
//判斷是否能初始化glew庫(kù),確保項(xiàng)目能正常使用OpenGL框架
GLenum err = glewInit();
if (GLEW_OK != err) {
fprintf(stderr, "GLEW Error: %s\n",glewGetErrorString(err));
return -999;
}
//初始化繪制
SetupRC();
//開(kāi)始runloop運(yùn)行循環(huán)
glutMainLoop();
return 0;
}
各種圖元繪制效果
-
點(diǎn)陣
-
線
-
連線不閉合
-
連線閉合
-
三角形金字塔(三角錐)
-
三角組合圓環(huán)
-
三角組合六邊扇
-
大合集