持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第6天,点击查看活动详情
- Swift Optional
- Swift Enum
- iOS开发 做一个三角形
- Swfit 指针类型
- Swift 属性(下)
- Swift 属性
- Swift 小结
- Swift 类与结构体(下)
- Swift 类的生命周期
- Swift 类的初始化器
- Swift 类与结构体
- OpenGL 压缩纹理
- OpenGL 隧道坐标计算
- 0penGL 像素格式及数据类型
- OpenGL 纹理对象
- OpenGL 纹理
- OpenGL 模型变化
- OpenGL 视图
- OpenGL 矩阵
- OpenGL 向量
- OpenGL 颜色混合
- OpenGL 深度测试的潜在风险
- OpenGL 浅析深度测试
- OpenGL 浅析隐藏面消除
- OpenGL 图元连接方式
- 记WKWebView与HTML完成交互两三事
- OpenGL 渲染流程图解析
- OpenGL 控制你的正方形
- OpenGL 专业名词解释
- OpenGL 环境搭建 - MacOS
今天我们一起总结下OpenGL中的图元连接方式都是有哪些。
OpenGL基本图元连接方式
图元 | 描述 |
---|---|
GL_POINTS | 每个顶点在屏幕上都是单独点 |
GL_LINES | 每一对顶点定义一个线段 |
GL_LINE_STRIP | 一个从第一个顶点依次经过每一个后续顶点而绘制的线条 |
GL LINE LOOP | 和GL LINE_ STRIP相同,但是最后一个顶点和第一个顶点连接起来了 |
GL_TRIANGLES | 每3个顶点定义一个新的三角形 |
GL_TRIANGLE _STRIP | 共用一个条带(strip)上的顶点的一组三角形 |
GL_TRIANGLE_FAN | 以一个圆点为中心呈扇形排列,共用相邻顶点的一组三角形 |
用一张图片来更加直观的解释下上面的几种连接方式:
使用流程
我们在测试使用图元连接方式的时候,应该重点了解 对 模型视图矩阵 的使用:
-
清空缓冲区之后,通过 压栈(记录一些状态参数,可以进行撤回操作)
modelViewMatrix.PushMatrix();
-
观察者矩阵拿到之后 记录起来
cameraFrame.GetCameraMatrix();
-
物体矩阵拿到之后,也做记录
objectFrame.GetMatrix();
-
使用模型视图矩阵 对 观察者举证和物体矩阵进行多矩阵混合计算
modelViewMatrix.MultMatrix(mCamera);
+objectFrame.GetMatrix(mObjectFrame);
-
对模型视图矩阵进行绘制
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);
-
之后,我们可以自定义点或线的一些参数,画完之后要还原;
-
最后,我们要 出栈
modelViewMatrix.PopMatrix();
这就是绘制以上图元连接的核心流程内容。
下面我们完成一个案例来实践一下上面点流程:
按键控制旋转
还是之前我们处理过的四个按键的监听处理:
GLfloat p = 10.f;
// 键盘按键回调 (上下左右)
void KeyboardCallback( int key, int x, int y ) {
// 1、旋转这个物体
//
if (key == GLUT_KEY_UP) {
objectFrame.RotateWorld(m3dDegToRad(-p), 1.0f, 0.0f, 0.0f);
}
if (key == GLUT_KEY_DOWN) {
objectFrame.RotateWorld(m3dDegToRad(p), 1.0f, 0.0f, 0.0f);
}
if (key == GLUT_KEY_LEFT) {
objectFrame.RotateWorld(m3dDegToRad(-p), 0.0f, 1.0f, 0.0f);
}
if (key == GLUT_KEY_RIGHT) {
objectFrame.RotateWorld(m3dDegToRad(p), 0.0f, 1.0f, 0.0f);
}
//提交渲染 之后会执行 RenderScene 方法
glutPostRedisplay();
}
定义我们需要用到的 矩阵和容器以及几何变换管道
//定义一个,着色管理器
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;
按键控制切换窗口名称
在这里,我们通过 nStep
来区分当前的图元链接方式的切换;
// 空格键回调,切换不同的窗口名称
void KeyPressFunc(unsigned char key, int x, int y) {
if (key == 32) {
nStep++;
if (nStep > 6) {
nStep = 0;
}
}
switch (nStep) {
case 0:
glutSetWindowTitle("OpenGL 图元连接形式 - GL_POINTS");
break;
case 1:
glutSetWindowTitle("OpenGL 图元连接形式 - GL_LINES");
break;
case 2:
glutSetWindowTitle("OpenGL 图元连接形式 - GL_LINE_STRIP");
break;
case 3:
glutSetWindowTitle("OpenGL 图元连接形式 - GL_LINE_LOOP");
break;
case 4:
glutSetWindowTitle("OpenGL 图元连接形式 - GL_TRIANGLES");
break;
case 5:
glutSetWindowTitle("OpenGL 图元连接形式 - GL_TRIANGLE_STRIP");
break;
case 6:
glutSetWindowTitle("OpenGL 图元连接形式 - GL_TRIANGLE_FAN");
break;
}
//提交渲染 之后会执行 RenderScene 方法
glutPostRedisplay();
}
初始化我们7个例子中的顶点数据
将我们例子中的顶点数据定义并存储起来,在切换的时候,来直接使用,切换至对应的顶点数据;
//为程序作一次性的设置
void SetupRC() {
//设置背影颜色
glClearColor(0.3f,0.5f,0.8f,1.0f);
//初始化着色管理器
shaderManager.InitializeStockShaders();
// 平面着色器
//投影变换(矩阵),移动变换(矩阵)
transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
//修改观察者的位置
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();
//画一条线 --------------------------------------
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,
};
//画一个金字塔 --------------------------------------
// 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;
float din = 10.0f;
//M3D_2PI 就是2Pi 的意思,就一个圆的意思。 绘制圆形
for(GLfloat angle = 0; angle < M3D_2PI; angle += M3D_2PI / din) {
//数组下标自增(每自增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] = -0.6f;
}
// 结束扇形 前面一共绘制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, din+2);
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("三角形带的顶点数:%d\n",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();
}
按照我们的使用流程来渲染我们的矩阵
承接上面方法的顶点数据,我们来对应的渲染对应的图形
//开始渲染
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(5.0f);
pointBatch.Draw();
glPointSize(1.0f);
break;
case 1:
//设置线宽度
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;
case 4:
DrawWireFramedBatch(&triangleBatch);
break;
case 5:
DrawWireFramedBatch(&triangleFanBatch);
break;
case 6:
DrawWireFramedBatch(&triangleStripBatch);
break;
default:
break;
}
//还原到以前的模型视图矩阵(单位矩阵)
modelViewMatrix.PopMatrix();
// 进行缓冲区交换
glutSwapBuffers();
}