OpenGL 基本图元绘制案例及解析
点、线、线路、闭合线路、金字塔、三角形带、三角形扇
案例结构
一、切换绘制场景
这些图形的绘制流程都是一样的:
初始化 -> 设置顶点坐标 -> 设置渲染参数 -> 渲染
为了方便学习,我们在同一个工程里面进行绘制。
设置一个参数 nStep, 点击空格的时候,修改其值,手动触发重新渲染。
在渲染参数设置方法里,设置 nStep 对应的图形渲染参数。
初始化 -> 设置顶点坐标(所有图形需要的顶点坐标) -> 设置渲染参数(根据 nStep 进行不同设置) -> 渲染
// 跟踪效果步骤int nStep = 0;
// 空格键(32)切换绘制场景参数
voidKeyPressFunc(unsignedchar key, int x, int y){
if(key == 32) {
nStep++;
if(nStep > 6)
nStep = 0;
}
switch(nStep) {
case0:
glutSetWindowTitle("GL_POINTS");
break;
case1:
glutSetWindowTitle("GL_LINES");
break;
...
// 设置不同的窗口标题,篇幅原因 case 2~6 不写,可自行实现
}
// 图形类型切换,手动触发重新渲染
glutPostRedisplay();
}
// 注意,需要在 main 函数注册此方法
//点击空格时,调用的函数
glutKeyboardFunc(KeyPressFunc);
二、旋转物体
金字塔、三角形带、三角形扇都是立体图形,为了便于观察,我们还需要设置一个旋转操作,可以全方位查看绘制的图形。
// 物体坐标系GLFrame objectFrame;
voidSpecialKeys(int key, int x, int y){
if(key == GLUT_KEY_UP)
//围绕一个指定的X,Y,Z轴旋转。
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();
}
// 注意,需要在 main 函数注册此方法
// 特殊键位函数(上下左右)
glutSpecialFunc(SpecialKeys);
三、设置窗口修改函数
GLMatrixStack modelViewMatrix;GLMatrixStack projectionMatrix;
// 投影矩阵,本案例需要绘制 3D 图形,因此使用透视投影效果更好
GLFrustum viewFrustum;
// 窗口已更改大小,或刚刚创建。无论哪种情况,我们都需要
// 使用窗口维度设置视口和投影矩阵.
voidChangeSize(int w, int h){
glViewport(0, 0, w, h);
// 创建视锥体
viewFrustum.SetPerspective(35.0f, float(w) / float(h), 1.0f, 500.0f);
// 使用视锥体生成投影矩阵,并存储在 projectionMatrix 变量
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
// 初始化模型矩阵:载入一个单元矩阵
modelViewMatrix.LoadIdentity();
}
透视投影 图片来源: LearnOpenGL-CN
- 创建一个投影矩阵
// Calculates the corners of the Frustum and sets the projection matrix.// Perspective Matrix Projection
voidSetPerspective(float fFov, float fAspect, float fNear, float fFar){...}
参数 | 含义 |
---|---|
fFov | 视锥体的角度,即视野 |
fAspect | 宽高比,由视口的宽除以高所得 |
fNear | 视点距离近平面的距离 |
fFar | 视点距离远平面的距离 |
近平面和远平面切割四棱锥,形成一个锥台,其间的物体会被观测到
当你把透视矩阵的 near 值设置太大时(如10.0f),OpenGL会将靠近摄像机的坐标(在0.0f和10.0f之间)都裁剪掉,这会导致一个你在游戏中很熟悉的视觉效果:在太过靠近一个物体的时候你的视线会直接穿过去。
现在我们的准备工作已经做好了,开始进行图形绘制流程。
四、设置顶点
在本次案例中,我们不需要修改顶点数据,只在初始化函数设置一次即可。
// 着色器管理类GLShaderManager shaderManager;
// 几何变换的管道
GLGeometryTransform transformPipeline;
// 为点图形 创建批次类
GLBatch pointBatch;
// 此函数在呈现上下文中进行任何必要的初始化。.
// 这是第一次做任何与opengl相关的任务。
voidSetupRC(){
// 灰色的背景
glClearColor(0.7f, 0.7f, 0.7f, 1.0f );
shaderManager.InitializeStockShaders();
// 设置变换管道以使用两个矩阵堆栈
// ⚠️变换管线存储不是这两个变量的值,而是指针,当这两个矩阵重新赋值,变换管线读到的值也会变化
transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
// 设置视点,摄像机(视点)相对于物体,在z轴移动的距离。
// 在物体坐标系中,z轴正方向是向屏幕内的,所以设置为负值,值越小,距离物体越远,物体投影后,在整个视口下越小。
// 默认为0,在上面我们设置了视锥体的近平面距离是1,视角是35度。如果不移动摄像机,就无法看到物体。如果移动的距离不够,就看不到物体的全貌。如果距离太远,物体就变成很小的一点了。
cameraFrame.MoveForward(-15.0f);
// 设置三个顶点数据
GLfloat vCoast[9] = {
3,3,0,
0,3,0,
3,0,0
};
// 用点的形式
pointBatch.Begin(GL_POINTS, 3);
pointBatch.CopyVertexData3f(vCoast);
pointBatch.End();
// 为了流程清晰,其他图形顶点的设置,参见文末完整代码,此处省略
}
五、设置渲染参数
// 相机(观察者)角色帧GLFrame cameraFrame;
// 对象角色帧
GLFrame objectFrame;
// 召唤场景
voidRenderScene(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);
// 栈顶上的单元矩阵 * 摄像机矩阵 = newMatrix
modelViewMatrix.MultMatrix(mCamera);
M3DMatrix44f mObjectFrame;
// 只要使用 GetMatrix 函数就可以获取矩阵堆栈顶部的值,这个函数可以进行2次重载。用来使用 GLShaderManager 的使用。或者是获取顶部矩阵的顶点副本数据
objectFrame.GetMatrix(mObjectFrame);
// 栈顶上的 newMatrix * 对象矩阵 = newMatrix
modelViewMatrix.MultMatrix(mObjectFrame);
/* GLShaderManager 中的Uniform 值——平面着色器
参数1:平面着色器
参数2:运行为几何图形变换指定一个 4 * 4变换矩阵
--transformPipeline.GetModelViewProjectionMatrix() 获取的
GetMatrix函数就可以获得矩阵堆栈顶部的值
参数3:颜色值(黑色)
*/
/*
transformPipeline 存储了 &modelViewMatrix、&projectionMatrix。调用 GetModelViewProjectionMatrix 函数,会取出最新的值进行矩阵变换,得到一个 模型视图投影矩阵(mvp)
*/
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);
switch(nStep) {
case0:
//设置点的大小
glPointSize(4.0f);
pointBatch.Draw();
glPointSize(1.0f);
break;
// case 1,2,3 类似 case 0, 此处省略,参见文末完整代码
case4:
DrawWireFramedBatch(&triangleBatch);
break;
// case 5,6 类似 case 4,此处省略,参见文末完整代码
}
// 渲染参数已经设置完毕,清除栈顶的矩阵
modelViewMatrix.PopMatrix();
// 进行缓冲区交换
glutSwapBuffers();
}
// 除了平面绘制,增加了边框绘制,不然看不清图片拼接
voidDrawWireFramedBatch(GLBatch* pBatch)
{
/*------------画绿色部分----------------*/
/* GLShaderManager 中的Uniform 值——平面着色器
参数1:平面着色器
参数2:运行为几何图形变换指定一个 4 * 4变换矩阵
--transformPipeline 变换管线(指定了2个矩阵堆栈)
参数3:颜色值
*/
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vGreen);
pBatch->Draw();
/*-----------边框部分-------------------*/
/*
glEnable(GLenum mode); 用于启用各种功能。功能由参数决定
参数列表:http://blog.csdn.net/augusdi/article/details/23747081
注意:glEnable() 不能写在glBegin() 和 glEnd()中间
GL_POLYGON_OFFSET_LINE 根据函数glPolygonOffset的设置,启用线的深度偏移
GL_LINE_SMOOTH 执行后,过虑线点的锯齿
GL_BLEND 启用颜色混合。例如实现半透明效果
GL_DEPTH_TEST 启用深度测试 根据坐标的远近自动隐藏被遮住的图形(材料
glDisable(GLenum mode); 用于关闭指定的功能 功能由参数决定
*/
//画黑色边框
glPolygonOffset(-1.0f, -1.0f);// 偏移深度,在同一位置要绘制填充和边线,会产生z冲突,所以要偏移
glEnable(GL_POLYGON_OFFSET_LINE);
// 画反锯齿,让黑边好看些
glEnable(GL_LINE_SMOOTH);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//绘制线框几何黑色版 三种模式,实心,边框,点,可以作用在正面,背面,或者两面
//通过调用glPolygonMode将多边形正面或者背面设为线框模式,实现线框渲染
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
//设置线条宽度
glLineWidth(2.5f);
/* GLShaderManager 中的Uniform 值——平面着色器
参数1:平面着色器
参数2:运行为几何图形变换指定一个 4 * 4变换矩阵
--transformPipeline.GetModelViewProjectionMatrix() 获取的
GetMatrix函数就可以获得矩阵堆栈顶部的值
参数3:颜色值(黑色)
*/
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);
pBatch->Draw();
// 复原原本的设置
//通过调用glPolygonMode将多边形正面或者背面设为全部填充模式
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glDisable(GL_POLYGON_OFFSET_LINE);
glLineWidth(1.0f);
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
}
注意:矩阵变换的时候,必须先乘上观察者矩阵,然后再乘对象矩阵。矩阵没有交换律,必须先明确观察者,对象矩阵的变换才是正确的,否则就是刻舟求剑。
GLFrame 角色帧,是拿来做变化用的。可以用来产生模型视图矩阵。来产生位置的移动。本案例用到了相机(观察者)角色帧和对象角色帧
GLTools-GLFrame概念
矩阵变换流程图
完整代码
#include"GLTools.h"#include"GLMatrixStack.h"
#include"GLFrame.h"
#include"GLFrustum.h"
#include"GLBatch.h"
#include"GLGeometryTransform.h"
#include<math.h>
#ifdef __APPLE__
#include<glut/glut.h>
#else
#define FREEGLUT_STATIC
#include<GL/glut.h>
#endif
/*
GLMatrixStack 变化管线使用矩阵堆栈
GLMatrixStack 构造函数允许指定堆栈的最大深度、默认的堆栈深度为64.这个矩阵堆在初始化时已经在堆栈中包含了单位矩阵。
GLMatrixStack::GLMatrixStack(int iStackDepth = 64);
//通过调用顶部载入这个单位矩阵
void GLMatrixStack::LoadIndentiy(void);
//在堆栈顶部载入任何矩阵
void GLMatrixStack::LoadMatrix(const M3DMatrix44f m);
*/
// 各种需要的类
GLShaderManager shaderManager;
GLMatrixStack modelViewMatrix;
GLMatrixStack projectionMatrix;
GLFrame cameraFrame;
GLFrame objectFrame;
//投影矩阵
GLFrustum viewFrustum;
//容器类(7种不同的图元对应7种容器对象)
GLBatch pointBatch;
GLBatch lineBatch;
GLBatch lineStripBatch;
GLBatch lineLoopBatch;
GLBatch triangleBatch;
GLBatch triangleStripBatch;
GLBatch triangleFanBatch;
//几何变换的管道
GLGeometryTransform transformPipeline;
GLfloat vGreen[] = { 0.0f, 1.0f, 0.0f, 1.0f };
GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 1.0f };
// 跟踪效果步骤
int nStep = 0;
// 窗口已更改大小,或刚刚创建。无论哪种情况,我们都需要
// 使用窗口维度设置视口和投影矩阵.
voidChangeSize(int w, int h)
{
glViewport(0, 0, w, h);
//创建投影矩阵,并将它载入投影矩阵堆栈中
viewFrustum.SetPerspective(35.0f, float(w) / float(h), 1.0f, 100.0f);
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
//调用顶部载入单元矩阵
modelViewMatrix.LoadIdentity();
}
// 此函数在呈现上下文中进行任何必要的初始化。.
// 这是第一次做任何与opengl相关的任务。
voidSetupRC()
{
// 灰色的背景
glClearColor(0.7f, 0.7f, 0.7f, 1.0f );
shaderManager.InitializeStockShaders();
glEnable(GL_DEPTH_TEST);
//设置变换管线以使用两个矩阵堆栈,存储不是值,是指针,当这两个矩阵重新复制,变换管线读到的值也会变化
transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
cameraFrame.MoveForward(-15.0f);
/*
常见函数:
void GLBatch::Begin(GLenum primitive,GLuint nVerts,GLuint nTextureUnits = 0);
参数1:表示使用的图元
参数2:顶点数
参数3:纹理坐标(可选)
//负责顶点坐标
void GLBatch::CopyVertexData3f(GLFloat *vNorms);
//结束,表示已经完成数据复制工作
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();
//通过线环的形式
lineLoopBatch.Begin(GL_LINE_LOOP, 3);
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
};
// 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) {
//数组下标自增(每自增1次就表示一个顶点)
nVerts++;
/*
弧长=半径*角度,这里的角度是弧度制,不是平时的角度制
既然知道了cos值,那么角度=arccos,求一个反三角函数就行了
*/
//x点坐标 cos(angle) * 半径
vPoints[nVerts][0] = float(cos(angle)) * r;
//y点坐标 sin(angle) * 半径
vPoints[nVerts][1] = float(sin(angle)) * r;
//z点的坐标
vPoints[nVerts][2] = -1.5f;
}
// 结束扇形 前面一共绘制7个顶点(包括圆心)
//添加闭合的终点
//课程添加演示:屏蔽177-180行代码,并把绘制节点改为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();
//三角形条带,一个小环或圆柱段
//顶点下标
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++;
}
// 关闭循环
printf("三角形带的顶点数:%dn",iCounter);
//结束循环,在循环位置生成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();
}
// 除了平面绘制,增加了边框绘制,不然看不清图片拼接
voidDrawWireFramedBatch(GLBatch* pBatch)
{
/*------------画绿色部分----------------*/
/* GLShaderManager 中的Uniform 值——平面着色器
参数1:平面着色器
参数2:运行为几何图形变换指定一个 4 * 4变换矩阵
--transformPipeline 变换管线(指定了2个矩阵堆栈)
参数3:颜色值
*/
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vGreen);
pBatch->Draw();
/*-----------边框部分-------------------*/
/*
glEnable(GLenum mode); 用于启用各种功能。功能由参数决定
参数列表:http://blog.csdn.net/augusdi/article/details/23747081
注意:glEnable() 不能写在glBegin() 和 glEnd()中间
GL_POLYGON_OFFSET_LINE 根据函数glPolygonOffset的设置,启用线的深度偏移
GL_LINE_SMOOTH 执行后,过虑线点的锯齿
GL_BLEND 启用颜色混合。例如实现半透明效果
GL_DEPTH_TEST 启用深度测试 根据坐标的远近自动隐藏被遮住的图形(材料
glDisable(GLenum mode); 用于关闭指定的功能 功能由参数决定
*/
//画黑色边框
glPolygonOffset(-1.0f, -1.0f);// 偏移深度,在同一位置要绘制填充和边线,会产生z冲突,所以要偏移
glEnable(GL_POLYGON_OFFSET_LINE);
// 画反锯齿,让黑边好看些
glEnable(GL_LINE_SMOOTH);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//绘制线框几何黑色版 三种模式,实心,边框,点,可以作用在正面,背面,或者两面
//通过调用glPolygonMode将多边形正面或者背面设为线框模式,实现线框渲染
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
//设置线条宽度
glLineWidth(2.5f);
/* GLShaderManager 中的Uniform 值——平面着色器
参数1:平面着色器
参数2:运行为几何图形变换指定一个 4 * 4变换矩阵
--transformPipeline.GetModelViewProjectionMatrix() 获取的
GetMatrix函数就可以获得矩阵堆栈顶部的值
参数3:颜色值(黑色)
*/
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);
pBatch->Draw();
// 复原原本的设置
//通过调用glPolygonMode将多边形正面或者背面设为全部填充模式
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glDisable(GL_POLYGON_OFFSET_LINE);
glLineWidth(1.0f);
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
}
// 召唤场景
voidRenderScene(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);
//矩阵乘以矩阵堆栈的顶部矩阵,相乘的结果随后简存储在堆栈的顶部
modelViewMatrix.MultMatrix(mCamera);
M3DMatrix44f mObjectFrame;
//只要使用 GetMatrix 函数就可以获取矩阵堆栈顶部的值,这个函数可以进行2次重载。用来使用GLShaderManager 的使用。或者是获取顶部矩阵的顶点副本数据
objectFrame.GetMatrix(mObjectFrame);
//矩阵乘以矩阵堆栈的顶部矩阵,相乘的结果随后简存储在堆栈的顶部
modelViewMatrix.MultMatrix(mObjectFrame);
/* GLShaderManager 中的Uniform 值——平面着色器
参数1:平面着色器
参数2:运行为几何图形变换指定一个 4 * 4变换矩阵
--transformPipeline.GetModelViewProjectionMatrix() 获取的
GetMatrix函数就可以获得矩阵堆栈顶部的值
参数3:颜色值(黑色)
*/
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);
switch(nStep) {
case0:
//设置点的大小
glPointSize(4.0f);
pointBatch.Draw();
glPointSize(1.0f);
break;
case1:
//设置线的宽度
glLineWidth(2.0f);
lineBatch.Draw();
glLineWidth(1.0f);
break;
case2:
glLineWidth(2.0f);
lineStripBatch.Draw();
glLineWidth(1.0f);
break;
case3:
glLineWidth(2.0f);
lineLoopBatch.Draw();
glLineWidth(1.0f);
break;
case4:
DrawWireFramedBatch(&triangleBatch);
break;
case5:
DrawWireFramedBatch(&triangleStripBatch);
break;
case6:
DrawWireFramedBatch(&triangleFanBatch);
break;
}
//还原到以前的模型视图矩阵(单位矩阵)
modelViewMatrix.PopMatrix();
// 进行缓冲区交换
glutSwapBuffers();
}
//特殊键位处理(上、下、左、右移动)
voidSpecialKeys(int key, int x, int y)
{
if(key == GLUT_KEY_UP)
//围绕一个指定的X,Y,Z轴旋转。
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();
}
//根据空格次数。切换不同的“窗口名称”
voidKeyPressFunc(unsignedchar key, int x, int y)
{
if(key == 32)
{
nStep++;
if(nStep > 6)
nStep = 0;
}
switch(nStep)
{
case0:
glutSetWindowTitle("GL_POINTS");
break;
case1:
glutSetWindowTitle("GL_LINES");
break;
case2:
glutSetWindowTitle("GL_LINE_STRIP");
break;
case3:
glutSetWindowTitle("GL_LINE_LOOP");
break;
case4:
glutSetWindowTitle("GL_TRIANGLES");
break;
case5:
glutSetWindowTitle("GL_TRIANGLE_STRIP");
break;
case6:
glutSetWindowTitle("GL_TRIANGLE_FAN");
break;
}
glutPostRedisplay();
}
intmain(int argc, char* argv[])
{
gltSetWorkingDirectory(argv[0]);
glutInit(&argc, argv);
//申请一个颜色缓存区、深度缓存区、双缓存区、模板缓存区
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
//设置window 的尺寸
glutInitWindowSize(800, 600);
//创建window的名称
glutCreateWindow("GL_POINTS");
//注册回调函数(改变尺寸)
glutReshapeFunc(ChangeSize);
//点击空格时,调用的函数
glutKeyboardFunc(KeyPressFunc);
//特殊键位函数(上下左右)
glutSpecialFunc(SpecialKeys);
//显示函数
glutDisplayFunc(RenderScene);
//判断一下是否能初始化glew库,确保项目能正常使用OpenGL 框架
GLenum err = glewInit();
if (GLEW_OK != err) {
fprintf(stderr, "GLEW Error: %sn", glewGetErrorString(err));
return1;
}
//绘制
SetupRC();
//runloop运行循环
glutMainLoop();
return0;
}
以上是 OpenGL 基本图元绘制案例及解析 的全部内容, 来源链接: utcz.com/a/31771.html