Learn OpenGL 2-3. “优雅地”地画一个三角形和一个长方形

## Vertex Array Object

Vertex Array Object: 顶点数组对象，VAO

## 动手画画

<p align="center">
<video id="video" controls="" preload="auto" poster="https://images.xiaozhuanlan.com/photo/2019/afc9fa64a34bd0f02085036016786e90.png">
<source id="mp4" src="https://images.xiaozhuanlan.com/photo/2019/4defcfb92b12a74c4685f1fd5e2af67c.mp4" type="video/mp4"></video>
</p>

## 不使用 VAO 的情况

### 定义顶点数组以及索引数组

private let rectangleVertices: [L2Vertex] = [
// 长方形
L2Vertex(position: (0.5, 0, 0)),
L2Vertex(position: (-0.5, 0, 0)),
L2Vertex(position: (-0.5, -0.5, 0)),
L2Vertex(position: (0.5, -0.5, 0)),
]

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

private let triganleVertices: [L2Vertex] = [
// 三角形
L2Vertex(position: (1, 0, 0)),
L2Vertex(position: (0, 0.5, 0)),
L2Vertex(position: (-1, 0, 0)),
]

private let triganleIndices: [GLubyte] = [
0, 1, 2,
]

### 将顶点数组和索引数组输入缓冲区

// vertex buffer object
private var VBO1: GLuint = 0
// element buffer object
private var EBO1: GLuint = 0

// vertex buffer object
private var VBO2: GLuint = 0
// element buffer object
private var EBO2: GLuint = 0

private func setupBuffer() {

glGenBuffers(1, &VBO1)
glBindBuffer(GLenum(GL_ARRAY_BUFFER), VBO1)
glBufferData(
GLenum(GL_ARRAY_BUFFER),
rectangleVertices.elementsSize,
rectangleVertices,
GLenum(GL_STATIC_DRAW)
)

glGenBuffers(1, &EBO1)
glBindBuffer(GLenum(GL_ELEMENT_ARRAY_BUFFER), EBO1)
glBufferData(
GLenum(GL_ELEMENT_ARRAY_BUFFER),
rectangleIndices.elementsSize,
rectangleIndices,
GLenum(GL_STATIC_DRAW)
)

glGenBuffers(1, &VBO2)
glBindBuffer(GLenum(GL_ARRAY_BUFFER), VBO2)
glBufferData(
GLenum(GL_ARRAY_BUFFER),
triganleVertices.elementsSize,
triganleVertices,
GLenum(GL_STATIC_DRAW)
)

glGenBuffers(1, &EBO2)
glBindBuffer(GLenum(GL_ELEMENT_ARRAY_BUFFER), EBO2)
glBufferData(
GLenum(GL_ELEMENT_ARRAY_BUFFER),
triganleIndices.elementsSize,
triganleIndices,
GLenum(GL_STATIC_DRAW)
)
}

### 渲染

override func glkView(_ view: GLKView, drawIn rect: CGRect) {

glClearColor(0, 0, 0, 1)
glClear(GLenum(GL_COLOR_BUFFER_BIT))

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

// 切换缓冲区
if count % 2 == 0 {
curIndices = rectangleIndices
glBindBuffer(GLenum(GL_ARRAY_BUFFER), VBO1)
glBindBuffer(GLenum(GL_ELEMENT_ARRAY_BUFFER), EBO1)
} else {
curIndices = triganleIndices
glBindBuffer(GLenum(GL_ARRAY_BUFFER), VBO2)
glBindBuffer(GLenum(GL_ELEMENT_ARRAY_BUFFER), EBO2)
}

count += 1

// 重传数据
setupVertexAttributes()

// 绘制
glDrawElements(
GLenum(GL_TRIANGLES),
GLsizei(curIndices.count),
GLenum(GL_UNSIGNED_BYTE),
nil
)
}

## 使用 VAO 的情况

### 将顶点数组和索引数组输入缓冲区

// vertex array object
private var VAO1: GLuint = 0

// vertex array object
private var VAO2: GLuint = 0

private func simpleSetupBuffer() {

glGenVertexArraysOES(1, &VAO1)
glBindVertexArrayOES(VAO1)

glGenBuffers(1, &VBO1)
...
setupVertexAttributes()

glBindVertexArrayOES(0)

glGenVertexArraysOES(1, &VAO2)
glBindVertexArrayOES(VAO2)

glGenBuffers(1, &VBO2)
...

setupVertexAttributes()

glBindVertexArrayOES(0)
}

1. glGenVertexArraysOES(GLsizei n, GLuint *arrays)

2. glBindVertexArrayOES(GLuint array)

glBindVertexArrayOES 传 0 代表解绑当前 VAO。

### 渲染

override func glkView(_ view: GLKView, drawIn rect: CGRect) {
...

// 切换缓冲区
if count % 2 == 0 {
curIndices = rectangleIndices
glBindVertexArrayOES(VAO1)
} else {
curIndices = triganleIndices
glBindVertexArrayOES(VAO2)
}

count += 1

// 绘制
glDrawElements(
GLenum(GL_TRIANGLES),
GLsizei(curIndices.count),
GLenum(GL_UNSIGNED_BYTE),
nil
)

glBindVertexArrayOES(0)
}

## 小结

• 了解到如何使用 VAO 来达到简化代码的目的。

## 延伸阅读

© 著作权归作者所有

🧀 专栏介绍 - 记录日常开发和学习中遇到的知识/问题 🚀 专栏方向 目前专注于 - OpenGL - ...
0条评论