绘制一个矩形

在上一篇文章中,我们使用 glDrawArrays(GL_TRIANGLES, 0, 3) 绘制了一个三角形;其中,GL_TRIANGLES 表示我们要绘制的是三角形,那么,我们要怎么绘制矩形呢?把 GL_TRIANGLES 改为 GL_RECTANGLES ?那么绘制五边形,六边形, n 边形呢?显然这样是行不通的。我们先来看下 glDrawArrays 的第一个参数。

OpenGL 支持的图元类型

glDrawArrays 的第一个参数描述的是绘制图元的类型,它有以下几种选项。

  • GL_POINTS 点,每个顶点渲染为一个单独的点。
  • GL_LINES 线段,每两个顶点构成一条线段。示例:(0, 1)、(2, 3)、(4, 5)...
  • GL_LINE_STRIP 折线,相邻顶点构成一条线段。示例:(0, 1)、(1, 2)、(2, 3)...
  • GL_LINE_LOOP -封闭折线,相邻顶点构成一条线段,首尾相连。示例:(0, 1)、(1, 2)、(2, 3)...(n - 1, n) (n, 0)
  • GL_TRIANGLES - 独立三角形,每三个顶点组成一个三角形。示例:(0, 1, 2)、 (3, 4, 5) ...
  • GL_TRIANGLE_STRIP 三角形带,三个顶点组成一个三角形,后面的三角形复用前面两个顶点。示例:(0, 1, 2)、 (1, 2, 3) ...
  • GL_TRIANGLE_FAN 三角形扇,相邻两个顶点和第一个顶点组成三角形。示例:(0, 1, 2)、 (0, 2, 3)
    原来的 OpenGL 确实是可以画四边形的,但是核心模式废弃了,因为三个点可以确定一个平面,而一个平面上的多边形可以划分成多个三角形。
    所以我们要绘制一个矩形,只需要把这个矩形拆成两个三角形即可。
cpp 复制代码
float vertices[] = {
    // 第一个三角形
    0.5f, 0.5f, 0.0f,   // 右上角
    0.5f, -0.5f, 0.0f,  // 右下角
    -0.5f, 0.5f, 0.0f,  // 左上角
    // 第二个三角形
    0.5f, -0.5f, 0.0f,  // 右下角
    -0.5f, -0.5f, 0.0f, // 左下角
    -0.5f, 0.5f, 0.0f   // 左上角
};

然后使用独立三角形模式,绘制 6 个顶点

cpp 复制代码
glDrawArrays(GL_TRIANGLES, 0, 6);

但是这带来了新的问题,一个矩形只有 4 个顶点,但是我们需要用 6 个顶点去存储它,这会带来额外的开销。我们可以通过 EBO 来优化这个问题。

EBO

元素缓冲对象:Element Buffer Object,EBO 或 索引缓冲对象 Index Buffer Object,IBO,它存储的是顶点的索引。

cpp 复制代码
float vertices[] = {
    0.5f, 0.5f, 0.0f,   // 右上角
    0.5f, -0.5f, 0.0f,  // 右下角
    -0.5f, -0.5f, 0.0f, // 左下角
    -0.5f, 0.5f, 0.0f   // 左上角
};

unsigned int indices[] = {
    0, 1, 3, // 第一个三角形
    1, 2, 3  // 第二个三角形
};

在这个例子中其实并没有很好地体现了这个优化,但在实际 3D 模型中,顶点通常包含:

位置、法线、纹理坐标、切线、副切线等数据,使用索引来绘制比起直接复制顶点数据往往是更优的选择。

VBO 的使用和 EBO 很相似,创建一个 EBO 对象,绑定,赋值。

cpp 复制代码
unsigned int EBO;
glGenBuffers(1, &EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

需要注意的是 EBO 需要在 glEnableVertexAttribArray 之后绑定,在 VAO 解绑之后解绑。

图片源于https://learnopengl-cn.github.io

当调用 glVertexAttribPointer 时,该函数会查询当前绑定到 GL_ARRAY_BUFFER 目标的缓冲对象,将该缓冲对象的 ID 连同其他参数一起存储到当前绑定的 VAO 中,这是一次性的快照操作,之后 VBO 的绑定状态可以改变,不影响已记录的 VAO。GL_ELEMENT_ARRAY_BUFFER 目标的绑定状态直接是 VAO 状态的一部分,当绑定 VAO 后,任何对 GL_ELEMENT_ARRAY_BUFFER 的绑定操作都会直接修改该 VAO 的状态,这是持续的关联,只要 VAO 保持绑定,EBO 就与之关联。

由于笔者水平有限,错误不足之处,烦请各位读者斧正。

相关推荐
rainbow68894 小时前
EffectiveC++入门:四大习惯提升代码质量
c++
秋邱4 小时前
用 Python 写出 C++ 的性能?用CANN中PyPTO 算子开发硬核上手指南
开发语言·c++·python
我在人间贩卖青春4 小时前
C++之析构函数
c++·析构函数
我在人间贩卖青春4 小时前
C++之数据类型的扩展
c++·字符串·数据类型
wangjialelele5 小时前
平衡二叉搜索树:AVL树和红黑树
java·c语言·开发语言·数据结构·c++·算法·深度优先
苏宸啊5 小时前
C++栈和队列
c++
森G5 小时前
七、04ledc-sdk--------makefile有变化
linux·c语言·arm开发·c++·ubuntu
橘颂TA6 小时前
【测试】高效浏览器操作:基础功能与优化设置大全
c++·功能测试·职场和发展·测试·web测试
一只小小的芙厨6 小时前
寒假集训笔记·以点为对象的树形DP
c++·算法
艾莉丝努力练剑6 小时前
hixl vs NCCL:昇腾生态通信库的独特优势分析
运维·c++·人工智能·cann