基本图元有 GL_POINTS GL_LINES GL_LINE_STRIP GL_LINE_LOOP GL_TRIANGLES GL_TRIANGLE_LOOP GL_TRIANGLE_FAN.
后面将一 一对其进行简单的介绍
1.GL_POINTS
I. 创建点集
GLfloat vCoast[24][3] = { { 2.80, 1.20, 0.0 },{ 2.0, 1.20, 0.0 },
{ 2.0, 1.08, 0.0 },{ 2.0, 1.08, 0.0 },
{ 0.0, 0.80, 0.0 },{ -.32, 0.40, 0.0 },
{ -.48, 0.2, 0.0 },{ -.40, 0.0, 0.0 },
{ -.60, -.40, 0.0 },{ -.80, -.80, 0.0 },
{ -.80, -1.4, 0.0 },{ -.40, -1.60, 0.0 },
{ 0.0, -1.20, 0.0 },{ .2, -.80, 0.0 },
{ .48, -.40, 0.0 },{ .52, -.20, 0.0 },
{ .48, .20, 0.0 },{ .80, .40, 0.0 },
{ 1.20, .80, 0.0 },{ 1.60, .60, 0.0 },
{ 2.0, .60, 0.0 },{ 2.2, .80, 0.0 },
{ 2.40, 1.0, 0.0 },{ 2.80, 1.0, 0.0 } };
II. 加载点图
GLBatch pointBatch;
pointBatch.Begin(GL_POINTS, 24);
pointBatch.CopyVertexData3f(vCoast);
pointBatch.End();
III. 改变点的大小
glPointSize(4.0f);
IV. 绘制
pointBatch.Draw();
V效果图
2.GL_LINES
这是线段,把数组里面的0-1相连 2-3相连 ,以此类推。
绝大部分操作都和上面一样的,只需替换GL_POINTS成GL_LINES即可,
效果图如下:
3.GL_LINE_STRIP GL_LINE_LOOP
GL_LINE_STRIP是把数组中的端点依次连接起来,但是首尾不相连,而GL_LINE_LOOP首尾相连。
效果图分别如下:
4.GL_TRIANGLES
绘制立体图形的时候如果边缘部分不能显示出来会很没有立体感,如下图所示
因此,需要绘制出来边缘部分,其主要代码如下:
//通过偏移值绘制边缘部分
void DrawWireFramedBatch(GLBatch* pBatch)
{
// Draw the batch solid green
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vGreen);
pBatch->Draw();
// Draw black outline
glPolygonOffset(-1.0f, -1.0f); // 设置偏移值
glEnable(GL_POLYGON_OFFSET_LINE);//开启偏移
// Draw lines antialiased
glEnable(GL_LINE_SMOOTH);//对直线进行抗锯齿处理
glEnable(GL_BLEND);//开启混合
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);//设置混合参数
// Draw black wireframe version of geometry
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);//用线来绘制多边形
glLineWidth(2.5f);//线宽
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);//选择着色器
pBatch->Draw();//开始绘制
// Put everything back the way we found it
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);//还原填充模式
glDisable(GL_POLYGON_OFFSET_LINE);//关闭线性偏移
glLineWidth(1.0f);//还原线宽
glDisable(GL_BLEND);//关闭混合
glDisable(GL_LINE_SMOOTH);//关闭直线的抗锯齿处理
}
然后我们创建好三角形坐标
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 };
//加载好三角形
triangleBatch.Begin(GL_TRIANGLES, 12);
triangleBatch.CopyVertexData3f(vPyramid);
triangleBatch.End();
通过DrawWireFramedBatch(&triangleBatch);绘制出来图形,效果如下:
5.GL_TRIANGLE_LOOP
上面绘制多个三角形的时候,每个三角形都使用了三个顶点,而实际上,相邻的三角形之间还存在着重复边,而GL_TRIANGLE_LOOP会绘制数组中连续的三个点作为三角形 0,1,2 1,2,3 2,3,4…
我们创建好三角形的坐标
int iCounter = 0;
GLfloat radius = 3.0f;
for (GLfloat angle = 0.0f; angle <= (2.0f*M3D_PI); angle += 0.3f)
{
GLfloat x = radius * sin(angle);
GLfloat y = radius * cos(angle);
// Specify the point and move the Z value up a little
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++;
}
// Close up the loop
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++;
//加载扇形带的图元
triangleStripBatch.Begin(GL_TRIANGLE_STRIP, iCounter);
triangleStripBatch.CopyVertexData3f(vPoints);
triangleStripBatch.End();
绘制三角形带 DrawWireFramedBatch(&triangleStripBatch);
效果图如下:
6.GL_TRIANGLE_FAN
原理和上面一样,但是三角形的应对规则变了,变为 0,1,2 0,2,3 0,3,4 0,4,5… 看起来就是以第一个点为中心的扇形环
创建三角形扇的坐标
GLfloat vPoints[100][3]; // Scratch array, more than we need
int nVerts = 0;
GLfloat r = 3.0f;
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) {
nVerts++;
vPoints[nVerts][0] = float(cos(angle)) * r;//每个点的坐标就是cosr和sinr
vPoints[nVerts][1] = float(sin(angle)) * r;
vPoints[nVerts][2] = -0.5f;
}
// 保证闭合
nVerts++;
vPoints[nVerts][0] = r;
vPoints[nVerts][1] = 0;
vPoints[nVerts][2] = 0.0f;
// 加载三角形扇,顶点+6个端点+最后一个保证闭合的初始点=8个点
triangleFanBatch.Begin(GL_TRIANGLE_FAN, 8);
triangleFanBatch.CopyVertexData3f(vPoints);
triangleFanBatch.End();
绘制三角形扇
DrawWireFramedBatch(&triangleFanBatch);
效果图如下:
完整代码还加入了按键控制旋转,以及空格切换图形,具体代码和注释如下:
#include <GLTools.h> // OpenGL toolkit
#include <GLMatrixStack.h>
#include <GLFrame.h>
#include <GLFrustum.h>
#include <GLBatch.h>
#include <GLGeometryTransform.h>
#define FREEGLUT_STATIC //在windows和linux上,使用freeglut静态版本,需要添加这一行,否则会出现错误
#include <glut.h>
#pragma comment(lib,"gltools.lib")//要加上这一行链接一下gltools库
GLShaderManager shaderManager;
GLMatrixStack modelViewMatrix;
GLMatrixStack projectionMatrix;
GLFrame cameraFrame;//存储了位置和两个方向向量
GLFrame objectFrame;
GLFrustum viewFrustum;
GLBatch pointBatch;
GLBatch lineBatch;
GLBatch lineStripBatch;
GLBatch lineLoopBatch;
GLBatch triangleBatch;
GLBatch triangleStripBatch;
GLBatch triangleFanBatch;
GLGeometryTransform transformPipeline;
M3DMatrix44f shadowMatrix;
GLfloat vGreen[] = { 0.0f, 1.0f, 0.0f, 1.0f };
GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 1.0f };
// Keep track of effects step
int nStep = 0;
///////////////////////////////////////////////////////////////////////////////
// This function does any needed initialization on the rendering context.
// This is the first opportunity to do any OpenGL related tasks.
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);//把摄像机往后挪一挪,否则看不到图像
//////////////////////////////////////////////////////////////////////
// 一系列点的坐标
GLfloat vCoast[24][3] = { { 2.80, 1.20, 0.0 },{ 2.0, 1.20, 0.0 },
{ 2.0, 1.08, 0.0 },{ 2.0, 1.08, 0.0 },
{ 0.0, 0.80, 0.0 },{ -.32, 0.40, 0.0 },
{ -.48, 0.2, 0.0 },{ -.40, 0.0, 0.0 },
{ -.60, -.40, 0.0 },{ -.80, -.80, 0.0 },
{ -.80, -1.4, 0.0 },{ -.40, -1.60, 0.0 },
{ 0.0, -1.20, 0.0 },{ .2, -.80, 0.0 },
{ .48, -.40, 0.0 },{ .52, -.20, 0.0 },
{ .48, .20, 0.0 },{ .80, .40, 0.0 },
{ 1.20, .80, 0.0 },{ 1.60, .60, 0.0 },
{ 2.0, .60, 0.0 },{ 2.2, .80, 0.0 },
{ 2.40, 1.0, 0.0 },{ 2.80, 1.0, 0.0 } };
// 加载好点图
pointBatch.Begin(GL_POINTS, 24);
pointBatch.CopyVertexData3f(vCoast);
pointBatch.End();
// 加载好线段图
lineBatch.Begin(GL_LINES, 24);
lineBatch.CopyVertexData3f(vCoast);
lineBatch.End();
// 加载好连续的线的图
lineStripBatch.Begin(GL_LINE_STRIP, 24);
lineStripBatch.CopyVertexData3f(vCoast);
lineStripBatch.End();
// 加载好首尾相连的连续的线的图
lineLoopBatch.Begin(GL_LINE_LOOP, 24);
lineLoopBatch.CopyVertexData3f(vCoast);
lineLoopBatch.End();
// 金字塔的点的坐标 ,四个面
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 };
//加载好三角形
triangleBatch.Begin(GL_TRIANGLES, 12);
triangleBatch.CopyVertexData3f(vPyramid);
triangleBatch.End();
//初始化三角形扇的坐标
GLfloat vPoints[100][3]; // Scratch array, more than we need
int nVerts = 0;
GLfloat r = 3.0f;
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) {
nVerts++;
vPoints[nVerts][0] = float(cos(angle)) * r;//每个点的坐标就是cosr和sinr
vPoints[nVerts][1] = float(sin(angle)) * r;
vPoints[nVerts][2] = -0.5f;
}
// 保证闭合
nVerts++;
vPoints[nVerts][0] = r;
vPoints[nVerts][1] = 0;
vPoints[nVerts][2] = 0.0f;
// 加载三角形扇,顶点+6个端点+最后一个保证闭合的初始点=8个点
triangleFanBatch.Begin(GL_TRIANGLE_FAN, 8);
triangleFanBatch.CopyVertexData3f(vPoints);
triangleFanBatch.End();
// 创建一个环装的三角形带
int iCounter = 0;
GLfloat radius = 3.0f;
for (GLfloat angle = 0.0f; angle <= (2.0f*M3D_PI); angle += 0.3f)
{
GLfloat x = radius * sin(angle);
GLfloat y = radius * cos(angle);
// Specify the point and move the Z value up a little
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++;
}
// Close up the loop
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++;
//加载扇形带的图元
triangleStripBatch.Begin(GL_TRIANGLE_STRIP, iCounter);
triangleStripBatch.CopyVertexData3f(vPoints);
triangleStripBatch.End();
}
/////////////////////////////////////////////////////////////////////////
//通过偏移值绘制边缘部分
void DrawWireFramedBatch(GLBatch* pBatch)
{
// Draw the batch solid green
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vGreen);
pBatch->Draw();
// Draw black outline
glPolygonOffset(-1.0f, -1.0f); // 设置偏移值
glEnable(GL_POLYGON_OFFSET_LINE);//开启偏移
// Draw lines antialiased
glEnable(GL_LINE_SMOOTH);//对直线进行抗锯齿处理
glEnable(GL_BLEND);//开启混合
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);//设置混合参数
// Draw black wireframe version of geometry
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);//用线来绘制多边形
glLineWidth(2.5f);//线宽
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);//选择着色器
pBatch->Draw();//开始绘制
// Put everything back the way we found it
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);//还原填充模式
glDisable(GL_POLYGON_OFFSET_LINE);//关闭线性偏移
glLineWidth(1.0f);//还原线宽
glDisable(GL_BLEND);//关闭混合
glDisable(GL_LINE_SMOOTH);//关闭直线的抗锯齿处理
}
///////////////////////////////////////////////////////////////////////////////
// Called to draw scene
void RenderScene(void)
{
// 用之前设置好的背景色来清除三个缓冲区
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);//颜色缓冲区,深度缓冲区,模板缓冲区
modelViewMatrix.PushMatrix();//保存当前的模型视图矩阵,默认为单位矩阵
M3DMatrix44f mCamera;
cameraFrame.GetCameraMatrix(mCamera);
modelViewMatrix.MultMatrix(mCamera);
M3DMatrix44f mObjectFrame;
objectFrame.GetMatrix(mObjectFrame);
modelViewMatrix.MultMatrix(mObjectFrame);
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();
// Flush drawing commands
glutSwapBuffers();
}
// Respond to arrow keys by moving the camera frame of reference
void SpecialKeys(int key, int x, int y)
{
if (key == GLUT_KEY_UP)
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();//强制刷新屏幕
}
///////////////////////////////////////////////////////////////////////////////
// A normal ASCII key has been pressed.
// In this case, advance the scene when the space bar is pressed
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();//刷新窗口的标题
}
///////////////////////////////////////////////////////////////////////////////
// Window has changed size, or has just been created. In either case, we need
// to use the window dimensions to set the viewport and the projection matrix.
void ChangeSize(int w, int h)
{
glViewport(0, 0, w, h);//设置视口为窗口大小,可以调整这里的值来看结果有什么不同
viewFrustum.SetPerspective(30.0f, float(w) / float(h), 1.0f, 500.0f);//设置透视投影矩阵,参数分别为,从顶点方向看去的视场角度,高宽比,到近裁减面和远裁减面的距离
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());//获得投影矩阵
modelViewMatrix.LoadIdentity();//加载单位矩阵
}
///////////////////////////////////////////////////////////////////////////////
// Main entry point for GLUT based programs
int main(int argc, char* argv[])
{
gltSetWorkingDirectory(argv[0]);//设置工作目录,argv[0]为当前的程序名
glutInit(&argc, argv);//初始化glut
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);//设置显示模式 双缓冲 RGBA颜色格式 深度缓冲区 模板缓冲区
glutInitWindowSize(800, 600);//建立一个800*600大小的窗口
glutCreateWindow("GL_POINTS");//窗口的标题为GL_POINTS
glutReshapeFunc(ChangeSize);//注册窗口大小改变时候的函数
glutKeyboardFunc(KeyPressFunc);//注册按键消息
glutSpecialFunc(SpecialKeys);//注册特殊按键消息(上下左右)
glutDisplayFunc(RenderScene);//注册场景渲染函数
GLenum err = glewInit();//初始化glew
if (GLEW_OK != err) {//处理glew出错的情况
fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
return 1;
}
SetupRC();//做好场景渲染的准备工作
glutMainLoop();//绘制主窗口
return 0;
}