058c3c3bcfda2f5550462124146db8ba
Learn OpenGL 2-2. “优雅地”地画一个长方形

预备知识

从上一节的结尾中,我们通过了数组缓冲对象的方式画了一个长方形。可以从顶点数组中发现,其中有两个顶点数据是重复的,那在数据的存储和传输都造成了浪费。在这一节中,我们通过索引缓冲对象的方式来尝试解决这个问题。

Element Buffer Object

Element Buffer Object: 索引缓冲对象,EBO,Index Buffer Object,IBO

设想一下,假设我们需要画一个长方体,一共 8 个顶点。如果通过顶点数组来表示需要传入 32 个顶点数据(一个面需要 2 个三角形,一个三角形 3 个顶点,一共 6 个面)。实际上,我们需要的只是 8 个顶点数据的不同组合。这时候,索引数组就派上用场了。

动手画画

定义顶点数组

可以看到,我们渲染一个长方形,仅仅需要 4 个顶点。

// 顶点数组
private let vertices: [L2Vertex] = [
    // 长方形
    L2Vertex(position: (0.5, -0.6, 0)),
    L2Vertex(position: (0.5, -0.8, 0)),
    L2Vertex(position: (-0.5, -0.6, 0)),
    L2Vertex(position: (-0.5, -0.8, 0)),
]

定义索引数组

在上一节中,我们需要的 6 个顶点实际上就是上面数组中的索引(下标)为 012 和 123 的组合。所以我们定义的索引数组如下。

// 索引数组
private let indices: [GLubyte] = [
    0, 1, 2,
    1, 2, 3
]

将索引数组输入缓冲区

这里和上一节的缓冲区初始化三部曲实际上是差不多的。注意到,我们这里 glBindBuffer 的类型也相应变为 GL_ELEMENT_ARRAY_BUFFER

// element buffer object
private var EBO: GLuint = 0

private func setupBuffer() {
    ...

    // 设置 VBO 数据
    // 还是按照三部曲走
    glGenBuffers(1, &EBO)
    glBindBuffer(GLenum(GL_ELEMENT_ARRAY_BUFFER), EBO)
    glBufferData(
        GLenum(GL_ELEMENT_ARRAY_BUFFER),
        indices.elementsSize,
        indices,
        GLenum(GL_STATIC_DRAW)
    )
}

渲染

我们只需要把 glDrawArrays 换成 glDrawElements 即可。

override func glkView(_ view: GLKView, drawIn rect: CGRect) {
    glClearColor(0, 0, 0, 1)
    glClear(GLenum(GL_COLOR_BUFFER_BIT))

    // 调用执行的着色器
    effect.prepareToDraw()

    // 绘制长方形
    glDrawElements(
        GLenum(GL_TRIANGLES),
        GLsizei(indices.count),
        GLenum(GL_UNSIGNED_BYTE),
        nil
    )
}

效果

如果我们的代码一切都正常,那我们就会看到下面这样的效果。上面的代码可以在 https://github.com/xurunkang/learnopengl 中找到。
<img src="https://images.xiaozhuanlan.com/photo/2019/3420f57d37bf3c3aba61bbe315671ee2.png" width = "400" alt="坐标系" align=center/>

实验

可以尝试自己画一个长方体。(提示:定义 8 个顶点数组,然后索引数组传入对应的 36 个数据。)

小结

  • 了解到如何通过 EBO 来优化代码。
© 著作权归作者所有
这个作品真棒,我要支持一下!
🧀 专栏介绍 - 记录日常开发和学习中遇到的知识/问题 🚀 专栏方向 目前专注于 - OpenGL - ...
0条评论
top Created with Sketch.