OpenGL ES学习之四---你好三角形(顶点缓冲区对象)

加载顶点属性的方式二:顶点缓冲区对象(VBO) 使用缓冲区对象,减少客户内存和图像内存之间数据的复制,提高性能(CPU到GPU数据复制) 预定义宏

#define VERTEX\_POS\_SIZE       3 // x, y and z
#define VERTEX\_COLOR\_SIZE     4 // r, g, b, and a

#define VERTEX\_POS\_INDX       0
#define VERTEX\_COLOR\_INDX     1

用户数据结构

typedef struct
    {
    // Handle to a program object
    GLuint programObject;

    // VertexBufferObject Ids
    GLuint vboIds\[2\];

    // x-offset uniform location
    GLuint offsetLoc;

} UserData;

初始化

bool VertexBufferObjects::init()
{
    bool ret = false;
    do
    {
        CC\_BREAK\_IF(false == TestCase::init());

        const char vShaderStr\[\] =
            "#version 300 es                            \\n"
            "layout(location = 0) in vec4 a_position;   \\n"
            "layout(location = 1) in vec4 a_color;      \\n"
            "uniform float u_offset;                    \\n"
            "out vec4 v_color;                          \\n"
            "void main()                                \\n"
            "{                                          \\n"
            "    v\_color = a\_color;                     \\n"
            "    gl\_Position = a\_position;              \\n"
            "    gl\_Position.x += u\_offset;             \\n"
            "}";


        const char fShaderStr\[\] =
            "#version 300 es            \\n"
            "precision mediump float;   \\n"
            "in vec4 v_color;           \\n"
            "out vec4 o_fragColor;      \\n"
            "void main()                \\n"
            "{                          \\n"
            "    o\_fragColor = v\_color; \\n"
            "}";

        // Create the program object
        userData.programObject = GLShader::LoadProgram(vShaderStr, fShaderStr);

        userData.offsetLoc = glGetUniformLocation(userData.programObject, "u_offset");

        if (userData.programObject == 0)
        {
            return GL_FALSE;
        }

        // Store the program object
        userData.vboIds\[0\] = 0;
        userData.vboIds\[1\] = 0;

        glClearColor(1.0f, 1.0f, 1.0f, 0.0f);

        ret = true;
    } while (0);

    return ret;
}

绘制函数

void VertexBufferObjects::onDraw(const Mat4& transform, uint32_t flags)
{
    auto winSize = Director::getInstance()->getWinSize();
    // 3 vertices, with (x,y,z) ,(r, g, b, a) per-vertex
    GLfloat vertices\[3 * (VERTEX\_POS\_SIZE + VERTEX\_COLOR\_SIZE)\] =
    {
        -0.5f,  0.5f, 0.0f,        // v0
        1.0f,  0.0f, 0.0f, 1.0f,  // c0
        -1.0f, -0.5f, 0.0f,        // v1
        0.0f,  1.0f, 0.0f, 1.0f,  // c1
        0.0f, -0.5f, 0.0f,        // v2
        0.0f,  0.0f, 1.0f, 1.0f,  // c2
    };
    // Index buffer data
    GLushort indices\[3\] = { 0, 1, 2 };

    glViewport(0, 0, winSize.width, winSize.height);
    glClear(GL\_COLOR\_BUFFER_BIT);

    glUseProgram(userData.programObject);

    glUniform1f(userData.offsetLoc, 0.0f);

    //不使用顶点缓冲区对象绘制图元
    DrawPrimitiveWithoutVBOs(vertices,
        sizeof(GLfloat) * (VERTEX\_POS\_SIZE + VERTEX\_COLOR\_SIZE),
        3, indices);

    // Offset the vertex positions so both can be seen
    glUniform1f(userData.offsetLoc, 1.0f);

    //使用顶点缓冲区对象绘制图元
    DrawPrimitiveWithVBOs(&userData, 3, vertices,
        sizeof(GLfloat) * (VERTEX\_POS\_SIZE + VERTEX\_COLOR\_SIZE),
        3, indices);
}

不使用缓冲区绘制

//
// vertices   - pointer to a buffer that contains vertex
//              attribute data
// vtxStride  - stride of attribute data / vertex in bytes 步进(跨距)
// numIndices - number of indices that make up primitive
//              drawn as triangles (顶点数目)
// indices    - pointer to element index buffer.
//
void VertexBufferObjects::DrawPrimitiveWithoutVBOs(GLfloat *vertices,
    GLint vtxStride,
    GLint numIndices,
    GLushort *indices)
{
    GLfloat   *vtxBuf = vertices;

    glBindBuffer(GL\_ARRAY\_BUFFER, 0);
    glBindBuffer(GL\_ELEMENT\_ARRAY_BUFFER, 0);

    //启用属性
    glEnableVertexAttribArray(VERTEX\_POS\_INDX);
    glEnableVertexAttribArray(VERTEX\_COLOR\_INDX);

    //加载顶点数据
    glVertexAttribPointer(VERTEX\_POS\_INDX, VERTEX\_POS\_SIZE,
        GL\_FLOAT, GL\_FALSE, vtxStride,
        vtxBuf);
    vtxBuf += VERTEX\_POS\_SIZE;

    glVertexAttribPointer(VERTEX\_COLOR\_INDX,
        VERTEX\_COLOR\_SIZE, GL_FLOAT,
        GL_FALSE, vtxStride, vtxBuf);

    glDrawElements(GL\_TRIANGLES, numIndices, GL\_UNSIGNED_SHORT,
        indices);

    //禁用顶点属性
    glDisableVertexAttribArray(VERTEX\_POS\_INDX);
    glDisableVertexAttribArray(VERTEX\_COLOR\_INDX);
}

使用缓冲区绘制

void VertexBufferObjects::DrawPrimitiveWithVBOs(UserData *userData,
    GLint numVertices, GLfloat *vtxBuf,
    GLint vtxStride, GLint numIndices,
    GLushort *indices)
{
    GLuint   offset = 0;

    // vboIds\[0\] - used to store vertex attribute data
    // vboIds\[l\] - used to store element indices
    if (userData->vboIds\[0\] == 0 && userData->vboIds\[1\] == 0)
    {
        // Only allocate on the first draw
        //创建缓冲区对象
        //void glGenBuffers(GLsizei n, GLuint *buffers)
        //n:number of buffer object names to return
        //buffers:pointer to an array of  n entries, where allocated buffer objects are returned
        glGenBuffers(2, userData->vboIds);

        //激活缓冲区对象(is used to make a buffer object current.)
        //void glBindBuffer(GLenum target, GLuint buffer);
        //指定当前活动缓冲区的对象
        //target can be set to any of the following targets :
        //GL\_ARRAY\_BUFFER
        //    GL\_ELEMENT\_ARRAY_BUFFER
        //    GL\_COPY\_READ_BUFFER
        //    GL\_COPY\_WRITE_BUFFER
        //    GL\_PIXEL\_PACK_BUFFER
        //    GL\_PIXEL\_UNPACK_BUFFER
        //    GL\_TRANSFORM\_FEEDBACK_BUFFER
        //    GL\_UNIFORM\_BUFFER
        //    buffer buffer object to be assigned as the current object to target
        glBindBuffer(GL\_ARRAY\_BUFFER, userData->vboIds\[0\]);
        //用数据分配和初始化缓冲区对象
        //void glBufferData(GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage);
        //target:可以是GL\_ARRAY\_BUFFER()(顶点数组数据)或GL\_ELEMENT\_ARRAY_BUFFER(元素数组数据)
        //size:存储相关数据所需的内存容量
        //data:用于初始化缓冲区对象,可以是一个指向客户区内存的指针,也可以是NULL
        //usage:数据在分配之后如何进行读写,如GL\_STREAM\_READ,GL\_STREAM\_DRAW,GL\_STREAM\_COPY
        glBufferData(GL\_ARRAY\_BUFFER, vtxStride * numVertices,
            vtxBuf, GL\_STATIC\_DRAW);
        glBindBuffer(GL\_ELEMENT\_ARRAY_BUFFER, userData->vboIds\[1\]);
        glBufferData(GL\_ELEMENT\_ARRAY_BUFFER,
            sizeof(GLushort) * numIndices,
            indices, GL\_STATIC\_DRAW);
    }

    glBindBuffer(GL\_ARRAY\_BUFFER, userData->vboIds\[0\]);
    glBindBuffer(GL\_ELEMENT\_ARRAY_BUFFER, userData->vboIds\[1\]);

    //启用顶点属性
    glEnableVertexAttribArray(VERTEX\_POS\_INDX);
    glEnableVertexAttribArray(VERTEX\_COLOR\_INDX);

    //加载顶点数据
    glVertexAttribPointer(VERTEX\_POS\_INDX, VERTEX\_POS\_SIZE,
        GL\_FLOAT, GL\_FALSE, vtxStride,
        (const void *)offset);

    offset += VERTEX\_POS\_SIZE * sizeof(GLfloat);
    //加载顶点数据
    glVertexAttribPointer(VERTEX\_COLOR\_INDX,
        VERTEX\_COLOR\_SIZE,
        GL\_FLOAT, GL\_FALSE, vtxStride,
        (const void *)offset);

    glDrawElements(GL\_TRIANGLES, numIndices, GL\_UNSIGNED_SHORT,
        0);

    //禁用顶点属性
    glDisableVertexAttribArray(VERTEX\_POS\_INDX);
    glDisableVertexAttribArray(VERTEX\_COLOR\_INDX);

    glBindBuffer(GL\_ARRAY\_BUFFER, 0);
    glBindBuffer(GL\_ELEMENT\_ARRAY_BUFFER, 0);
}

效果图: 20 工程源码:CocosShader


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 xue_huashan@163.com

文章标题:OpenGL ES学习之四---你好三角形(顶点缓冲区对象)

文章字数:1.1k

本文作者:max-xue

发布时间:2017-06-19, 20:28:08

最后更新:2019-11-09, 10:44:34

原始链接:http://blog.le-more.com/2017/06/19/cocos/a1-b6-e7-82-b9-e7-bc-93/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录
×

喜欢就点赞,疼爱就打赏