有过一点OpenGL开发经验的人就知道每次绘图之前都会绑定顶点数组,每次将一个顶点传到GPU进行绘制。但是从CPU传数据到GPU的效率并不高,所以我们就需要使用VBO顶点缓存对象来一次性传递多个顶点到GPU,而VAO是3.0以后的版本才有的功能,它允许我们保存对于顶点的配置信息,我们配置好之后就只需要绑定对应的VAO,然后直接绘制即可。索引缓冲对象EBO和VBO类似也就是保存下标的缓冲。
- 顶点数组对象:Vertex Array Object,VAO
- 顶点缓冲对象:Vertex Buffer Object,VBO
- 索引缓冲对象:Element Buffer Object
下面就简单实用这三个东西来绘制一个三角形和一个矩形。
EGL环境初始化
这里我就不多说了,可以看我之前的文章关于Android端EGL环境。
这里注意的一点是需要注意API的版本,但是我在手机上测试实用2也能用,这就很尴尬了。
EGLint eglContextAttribute[] = {
EGL_CONTEXT_CLIENT_VERSION, 3,
EGL_NONE
};
if (!(context = eglCreateContext(display, config,
NULL == sharedContext ? EGL_NO_CONTEXT : sharedContext,
eglContextAttribute))) {
LOGE("eglCreateContext() returned error %d", eglGetError());
release();
return false;
}
着色器
绘制三角形和矩形的着色器都十分简单,直接贴上。3.0的GLSL使用in代替了attribute,out代替varying。片元着色器的out就是制定颜色输出了。
1、vertex_shader.glsl
#version 300 es
layout (location = 0) in vec3 aPos;
void main(){
gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
}
2、fragment_shader.glsl
#version 300 es
out vec4 FragColor;
void main(){
FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);
}
绘制流程
1、绘制三角形
(1) VAO,VBO的配置
float vertices[] = {
-0.5f, -0.0f, 0.0f, // left
0.5f, -0.0f, 0.0f, // right
0.0f, 1.0f, 0.0f // top
};
VAO = new GLuint[2];
VBO = new GLuint[2];
//生成两个VAO和两个VBO
glGenVertexArrays(2, VAO);
glGenBuffers(2, VBO);
//绑定第一个VAO
glBindVertexArray(VAO[0]);
//绑定第一个VBO
glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);
//GL_STATIC_DRAW表示顶点不会变化,绑定数组
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
//指定解析顶点规则
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr);
glEnableVertexAttribArray(0);
//解绑
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
这里我们初始化了两个VAO和两个VBO,因为后面需要一个矩形,然后绑定之后将顶点数据绑定到VBO,同时指定解析顶点规则,这样就可以将这些规则保存到响应的VAO中,最后我们解绑。
(2)三角形的绘制
一切配置完成后三角形绘制就很简单了,除了初始化,我们只需要绑定VAO然后绘制一个三角形就可以了。
glViewport(_backingLeft, _backingTop, _backingWidth, _backingHeight);
//设置一个颜色状态
glClearColor(0.0f, 0.0f, 1.0f, 0.0f);
//使能颜色状态的值来清屏
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glUseProgram(program);
glBindVertexArray(VAO[0]);
glDrawArrays(GL_TRIANGLES, 0, 3);
2、绘制矩形
(1)VAO,VBO,EBO的配置
和之前很类似,这次需要额外绑定一个EBO,然后这些信息同样会保存在对应VAO中。
unsigned int indices[] = { // 注意索引从0开始!
0, 1, 3, // 第一个三角形
1, 2, 3 // 第二个三角形
};
glGenBuffers(1, &EBO);
glBindVertexArray(VAO[1]);
glBindBuffer(GL_ARRAY_BUFFER, VBO[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices1), vertices1, GL_STATIC_DRAW);
//绑定索引EBO
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
//绑定索引数组
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
//指定解析顶点规则
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *) 0);
glEnableVertexAttribArray(0);
glBindVertexArray(0);
(2)绘制矩形
最后的绘制同样只需要绑定VAO来绘制就可以了
glBindVertexArray(VAO[1]);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
源码地址
参考资料:https://learnopengl-cn.github.io/01%20Getting%20started/04%20Hello%20Triangle/