乐趣区

关于android:Opengl-ES之EBO

后面咱们介绍了 VBO 与 VAO 等缓冲对象,明天咱们来介绍一下 EBO。

对于 VBO 或 VAO 能够查看之前的文章:Opengl ES 之 VBO 和 VAO

EBO 是个啥

EBO(Element Buffer Object,也叫 IBO:Index Buffer Object)索引缓冲区对象,这个缓冲区次要用来存储顶点的索引信息,索引的意义在于缩小反复数据,次要是在函数 glDrawElements
中应用。

在之前的文章中,咱们绘制三角形、四边形等,因为顶点数据或者专用的顶点坐标不多,都是调用函数 glDrawArrays 进行绘制的,试想一下,如果须要绘制一个顶点数量比拟多,而且多个顶点之间须要通过
不同的组合进行顶点复用的,那么函数 glDrawArrays 及很难满足绘制需要了,此时就须要应用 EBO 搭配函数 glDrawElements 进行绘制了,例如应用 8 个顶点绘制一个正方体的例子。

在 OpenGL 通过索引缓冲对象 (EBO) 来对顶点进行复用,做到反复的顶点只须要调配一次内存,再绘图的时候后通过 EBO 通知 GPU 顶点的索引。

如果应用了 EBO,那么绘图函数 glDrawElements 通过索引到相应的顶点缓冲区去拿数据,如果绑定了 VAO 就到 VAO 里拿数据。

EBO 的应用

EBO 的应用和后面介绍的 VBO 的应用差不多:

  • 函数 glGenBuffers 创建对象 ID

    unsigned int EBO;
    glGenBuffers(1, &EBO);
  • 函数 glBindBuffer 绑定 EBO

与 VBO 相似,只不过 EBO 的类型变成了 GL_ELEMENT_ARRAY_BUFFER

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
  • 函数 glBufferData 绑定数据
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

对于 GL_STATIC_DRAW 等几个参数的类型在 VBO 的文章中曾经做了介绍,这里就不多说了,童鞋们能够看之前的文章。

当以上步骤配置结束就能够应用 EBO 了,在绘制函数 glDrawElements 调用前调用函数 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); 进行绑定即可应用。

  • 在析构函数中调用函数 glDeleteBuffers 销毁 EBO

     glDeleteBuffers(1,&EBO);

留神:笔者在联合应用 VAO、VBO 和 EBO 的时候发现,解除绑定时须要先解除 VAO 的绑定,再解除其余 VBO 及 EBO 的绑定,否则可能会导致绘制不失效。

实例 Demo

咱们沿用之前 VBO/VAO 绘制四边形的例子,在下面拓展一下应用四个顶点坐标联合 EBO 绘制一个四边形。

次要代码 EBOOpengl.cpp:


#include "EBOOpengl.h"

#include "../utils/Log.h"


// 顶点着色器
static const char *ver = "#version 300 es\n"
                         "in vec4 aColor;\n"
                         "in vec4 aPosition;\n"
                         "out vec4 vColor;\n"
                         "void main() {\n"
                         "vColor = aColor;\n"
                         "gl_Position = aPosition;\n"
                         "}";

// 片元着色器
static const char *fragment = "#version 300 es\n"
                              "precision mediump float;\n"
                              "in vec4 vColor;\n"
                              "out vec4 fragColor;\n"
                              "void main() {\n"
                              "fragColor = vColor;\n"
                              "}";

const static GLfloat VERTICES_AND_COLOR[] = {
        0.5f, -0.5f, // 右下
        // 色彩
        0.0f, 0.0f, 1.0f, 1.0f,
        0.5f, 0.5f, // 右上
        // 色彩
        0.0f, 0.0f, 1.0f, 1.0f,
        -0.5f, -0.5f, // 左下
        // 色彩
        0.0f, 0.0f, 1.0f, 1.0f,
        -0.5f, 0.5f, // 左上
        // 色彩
        0.0f, 0.0f, 1.0f, 1.0f,
};

//const static unsigned int indices[] = {
//        // 留神索引从 0 开始!
//        // 此例的索引 (0,1,2,3) 就是顶点数组 vertices 的下标,//        // 这样能够由下标代表顶点组合成矩形
//        0, 1, 2, // 第一个三角形
//        1, 2, 3  // 第二个三角形
//};

//// 应用 shor 类型
//const static unsigned short indices[] = {
//        // 留神索引从 0 开始!
//        // 此例的索引 (0,1,2,3) 就是顶点数组 vertices 的下标,//        // 这样能够由下标代表顶点组合成矩形
//        0, 1, 2, // 第一个三角形
//        1, 2, 3  // 第二个三角形
//};

// 应用 byte 类型
const static uint8_t indices[] = {
        // 留神索引从 0 开始!
        // 此例的索引 (0,1,2,3) 就是顶点数组 vertices 的下标,// 这样能够由下标代表顶点组合成矩形
        0, 1, 2, // 第一个三角形
        1, 2, 3  // 第二个三角形
};

EBOOpengl::EBOOpengl() {initGlProgram(ver, fragment);
    positionHandle = glGetAttribLocation(program, "aPosition");
    colorHandle = glGetAttribLocation(program, "aColor");

    // VAO
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    // vbo
    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(VERTICES_AND_COLOR), VERTICES_AND_COLOR, GL_STATIC_DRAW);

    // stride 步长 每个顶点坐标之间相隔 6 个数据点,数据类型是 float
    glVertexAttribPointer(positionHandle, 2, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void *) 0);
    // 启用顶点数据
    glEnableVertexAttribArray(positionHandle);
    // stride 步长 每个色彩坐标之间相隔 6 个数据点,数据类型是 float,色彩坐标索引从 2 开始
    glVertexAttribPointer(colorHandle, 4, GL_FLOAT, GL_FALSE, 6 * sizeof(float),
                          (void *) (2 * sizeof(float)));
    // 启用色彩顶点数据
    glEnableVertexAttribArray(colorHandle);

    // EBO
    glGenBuffers(1,&ebo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,ebo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(indices),indices,GL_STATIC_DRAW);

    // 这个程序不能乱啊,先解除 vao,再解除其余的,不然在绘制的时候可能会不起作用,须要从新 glBindBuffer 才失效
    // vao 解除
    glBindVertexArray(0);
    // 解除绑定
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    // 解除绑定
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);

    LOGD("program:%d", program);
    LOGD("positionHandle:%d", positionHandle);
    LOGD("colorHandle:%d", colorHandle);
}

void EBOOpengl::onDraw() {
    // 清屏
    glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    glUseProgram(program);

    // VBO 与 VAO 配合绘制
    // 应用 vao
    glBindVertexArray(vao);
    // 应用 EBO
//    glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_INT,(void *)0);
// 应用 short 类型节俭内存
//    glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_SHORT,(void *)0);
// 应用 byte 类型节俭内存
    glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_BYTE,(void *)0);
    glUseProgram(0);
    // vao 解除绑定
    glBindVertexArray(0);

    // 禁用顶点
    glDisableVertexAttribArray(positionHandle);
    if (nullptr != eglHelper) {eglHelper->swapBuffers();
    }
}

EBOOpengl::~EBOOpengl() noexcept {glDeleteBuffers(1,&ebo);
    glDeleteBuffers(1,&vbo);
    glDeleteVertexArrays(1,&vao);
}

技巧:在确保数据不会产生溢出的状况下尽量应用占有内存小的数据类型以节约内存,例如应用 short 比 int 要节俭,应用 byte 比 short 要节俭。

往期笔记

Opengl ES 之 EGL 环境搭建
Opengl ES 之着色器
Opengl ES 之三角形绘制
Opengl ES 之四边形绘制
Opengl ES 之纹理贴图
Opengl ES 之 VBO 和 VAO

关注我,一起提高,人生不止 coding!!!

退出移动版