首页 > 其他分享 >Opengl ES之EBO

Opengl ES之EBO

时间:2022-09-27 10:37:19浏览次数:61  
标签:VAO Opengl BUFFER EBO VBO 顶点 GL ES


前面我们介绍了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!!!
微信扫码关注

标签:VAO,Opengl,BUFFER,EBO,VBO,顶点,GL,ES
From: https://www.cnblogs.com/goFlyer/p/16733618.html

相关文章

  • Get started with NuGet packages in Azure Artifacts
    GetstartedwithNuGetpackagesinAzureArtifactsDownloadNuGetpackages1.Getthefeed'ssourceURLFromwithinyourproject,selectArtifacts,andthen......
  • Opengl ES之VBO和VAO
    前言本文主要介绍了什么是VBO/VAO,为什么需要使用VBO/VAO以及如何使用VBO和VAO。VBO什么是VBOVBO(vertexBufferObject):顶点缓冲对象。是在显卡存储空间中开辟的一块区......
  • cesium基础组件的显示与隐藏
    方法一/*通过css控制组件显隐及位置*/.cesium-viewer-toolbar,/*右上角按钮*/.cesium-viewer-animationContainer,/*左下角动画控件*/.......
  • 【luogu CF1109E】Sasha and a Very Easy Test(线段树)
    SashaandaVeryEasyTest题目链接:luoguCF1109E题目大意维护一个长度为n的序列,有区间乘,单点除(保证能整除),区间求和答案对p取模。p不一定是质数。思路麻了考场......
  • .net的.dll.refresh文件和pdb文件
    .net的.dll.refresh文件和pdb文件 dll.refresh文件打开refresh文件,可以看到里面仅仅是个路径。众所周知,.net的程序生成后会在bin目录下生成.dll文件,而.dll.refresh这......
  • 帧结构和物理资源(CRB,Resourcegrid,Resource-element和PointA)
    Resourcegrid  N.B.commonRB我们会在本文后半部分介绍,这里先简单介绍一下:commonresourceblock指的是在不同的numerology中,即对于某一种子载波间距配置,commonre......
  • 帧结构和物理资源(Numerologies,系统帧和子帧,时隙)
    之所以名字写这么长,是因为我发现后面的每个知识点的内容都很多,但是也不排除内容很少的知识点,所以为了查阅方便,我尽量一篇文章只写一个知识点,而如果知识点内容少,那我就把它......
  • [云原生] Kubernetes 应用接入最佳实践
    应用接入最佳实践目标:稳定性,可用性,性能,安全从多维度思考高可用的问题迁移对应用造成的影响JavaConcurrentGCThreadHeapSize线程数不可控Node.js多线程模式......
  • TypeScript extends
    ......
  • [Typescript] 38. Medium - Diff
    Getan Object thatisthedifferencebetween O & O1/*_____________YourCodeHere_____________*/typeDiff<T,S>={[KinExclude<(keyofT|keyof......