绘制一个矩形

在上一篇文章中,我们使用 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 就与之关联。

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

相关推荐
cccccc语言我来了4 分钟前
【C++---unordered_set/map底层封装】个不拘一格的集合。它不似有序集合那般循规蹈矩,而是以一种洒脱不羁的方式,将元素们随意地散落其中。每一个元素都是独一无二的。
开发语言·c++·哈希算法
Zfox_4 分钟前
C++ IO流全解析:标准库中的数据处理与文件读写艺术
开发语言·c++
tankeven25 分钟前
动态规划专题(03):区间动态规划从原理到实践(未完待续)
c++·算法·动态规划
天若有情67330 分钟前
【C++原创开源】formort.h:一行头文件,实现比JS模板字符串更爽的链式拼接+响应式变量
开发语言·javascript·c++·git·github·开源项目·模版字符串
大前端下的小角色1 小时前
UE5.6 Cesium 插件编译踩坑记录(UE 5.6 + MSVC 14.38 + CMake 3.31)
c++
feng_you_ying_li2 小时前
c++之哈希表的介绍与实现
开发语言·c++·散列表
xh didida2 小时前
C++ -- string
开发语言·c++·stl·sring
m晴朗3 小时前
测试覆盖率从35%到80%:我用AI批量生成C++单元测试的完整方案
c++·gpt·ai
无限进步_3 小时前
【C++&string】大数相乘算法详解:从字符串加法到乘法实现
java·开发语言·c++·git·算法·github·visual studio
苏纪云3 小时前
蓝桥杯考前突击
c++·算法·蓝桥杯