如何将多个四边形批处理到一个巨型缓冲区中

时间:2016-01-12 09:03:05

标签: opengl vertex-buffer batching

我正在尝试将多个精灵批处理到一个大缓冲区中,但是我遇到了一些技术问题。我想我没有正确设置我的vbo尺寸,但让我们看看。

目前这只渲染了1个彩色四边形,虽然我想渲染两个。

int SPRITE_COUNT = 2;
cg_sprite** sprites;

float* v_buff;
float* c_buff;
float* t_buff;

vec4 *i0, *i1, *i2, *i3; //tmp vec4 used to hold pre transform vertex
vec4 *o0, *o1, *o2, *o3; //tmp vec4 used to hold pos transformed vertex

float v_buffer[16];   //tmp buffers to hold vertex data
float c_buffer[16];   //color

这就是我设置我的vbo的方式。

//setting up the buffers to hold concat vertex and color data
v_buff = (float*)calloc(
    1, (sizeof(float) * sizeof(sprites[0]->quad->vertices) * SPRITE_COUNT));
c_buff = (float*)calloc(
    1, (sizeof(float) * sizeof(sprites[0]->quad->colors) * SPRITE_COUNT));
t_buff = (float*)calloc(
    1,
    (sizeof(float) * sizeof(sprites[0]->quad->tex_coords) * SPRITE_COUNT));
i_buff = (short*)calloc(
    1, (sizeof(short) * sizeof(sprites[0]->quad->indices) * SPRITE_COUNT));

glGenBuffers(1, &vao);
glBindVertexArray(vao);

glEnableVertexAttribArray(0);
glGenBuffers(1, &vert_buff);
glBindBuffer(GL_ARRAY_BUFFER, vert_buff);
glBufferData(GL_ARRAY_BUFFER,
             SPRITE_COUNT * sizeof(sprites[0]->quad->vertices), v_buff,
             GL_STREAM_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat),
                      (GLvoid*)0);

glEnableVertexAttribArray(1);
glGenBuffers(1, &col_buff);
glBindBuffer(GL_ARRAY_BUFFER, col_buff);
glBufferData(GL_ARRAY_BUFFER,
             SPRITE_COUNT * sizeof(sprites[0]->quad->colors), c_buff,
             GL_STREAM_DRAW);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat),
                      (GLvoid*)0);

glGenBuffers(1, &ind_buff);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ind_buff);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
             SPRITE_COUNT * sizeof(sprites[0]->quad->indices), i_buff,
             GL_STREAM_DRAW);

glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);

这里是一个sprite对象。

typedef struct {
    vec3 angles;
    GLshort vertex_count;
    GLfloat vertices[12];
    GLfloat colors[16];
    GLshort indices[6];
    GLfloat tex_coords[8];
} cg_quad;

typedef struct sprite {
    cg_quad* quad;
    vec3 scale;
    vec3 pos;
    vec3 angl;
    mat4 m_mat;
    GLuint texture_id;
}cg_sprite;

因为我试图绘制精灵,所以我手动创建它们: 精灵函数原型:

cg_sprite* cg_sprite_new(const float x_pos, const float y_pos, const float z, const float w, const float h);

sprites = calloc(1, sizeof(cg_sprite*) * SPRITE_COUNT);
sprites[0] = cg_sprite_new(-100, 50, 0, 100, 100);
sprites[1] = cg_sprite_new(100, -50, 0, 100, 100);

我还创建了一堆临时结构来用于为每个sprite进行计算,尽管如果可能的话我想简化它:

for(int i = 0; i < SPRITE_COUNT; i++) {
    i0 = calloc(1, sizeof(vec4) * SPRITE_COUNT);
    i1 = calloc(1, sizeof(vec4) * SPRITE_COUNT);
    i2 = calloc(1, sizeof(vec4) * SPRITE_COUNT);
    i3 = calloc(1, sizeof(vec4) * SPRITE_COUNT);

    o0 = calloc(1, sizeof(vec4) * SPRITE_COUNT);
    o1 = calloc(1, sizeof(vec4) * SPRITE_COUNT);
    o2 = calloc(1, sizeof(vec4) * SPRITE_COUNT);
    o3 = calloc(1, sizeof(vec4) * SPRITE_COUNT);
}

这是渲染循环:

void variable_render(double alpha) {
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glUseProgram(ce_get_default_shader()->shader_program);
    glBindVertexArray(vao);

    //--------------- update vertex data ---------------------
    for (int i = 0; i < SPRITE_COUNT; i++) {
        vmathT3MakeIdentity(&rot);
        vmathT3MakeIdentity(&scal);
        vmathT3MakeIdentity(&trns);
        vmathT3MakeIdentity(&tmp);

        vmathT3MakeScale(&scal, &sprites[i]->scale);
        vmathT3MakeRotationZYX(&rot, &sprites[i]->angl);
        vmathT3MakeTranslation(&trns, &sprites[i]->pos);
        vmathT3Mul(&tmp, &trns, &scal);  // scale then trnslate
        vmathT3Mul(&tmp, &tmp, &rot);    // scale then translate then rotate

        vmathM4MakeFromT3(&sprites[i]->m_mat, &tmp);

        cg_quad_getquadverts(&i0[i], &i1[i], &i2[i], &i3[i], sprites[i]->quad);
        vmathM4MulV4(&o0[i], &sprites[i]->m_mat, &i0[i]);
        vmathM4MulV4(&o1[i], &sprites[i]->m_mat, &i1[i]);
        vmathM4MulV4(&o2[i], &sprites[i]->m_mat, &i2[i]);
        vmathM4MulV4(&o3[i], &sprites[i]->m_mat, &i3[i]);

        v_buff[(i * 12) + 0] = o0[i].x; //copy over vertex data
        v_buff[(i * 12) + 1] = o0[i].y;
        v_buff[(i * 12) + 2] = o0[i].z;

        v_buff[(i * 12) + 3] = o1[i].x;
        v_buff[(i * 12) + 4] = o1[i].y;
        v_buff[(i * 12) + 5] = o1[i].z;

        v_buff[(i * 12) + 6] = o2[i].x;
        v_buff[(i * 12) + 7] = o2[i].y;
        v_buff[(i * 12) + 8] = o2[i].z;

        v_buff[(i * 12) + 9] = o3[i].x;
        v_buff[(i * 12) + 10] = o3[i].y;
        v_buff[(i * 12) + 11] = o3[i].z;

        c_buff[(i * 16) + 0] = sprites[i]->quad->colors[0]; //color
        c_buff[(i * 16) + 1] = sprites[i]->quad->colors[1];
        c_buff[(i * 16) + 2] = sprites[i]->quad->colors[2];
        c_buff[(i * 16) + 3] = sprites[i]->quad->colors[3];
        c_buff[(i * 16) + 4] = sprites[i]->quad->colors[4];
        c_buff[(i * 16) + 5] = sprites[i]->quad->colors[5];
        c_buff[(i * 16) + 6] = sprites[i]->quad->colors[6];
        c_buff[(i * 16) + 7] = sprites[i]->quad->colors[7];
        c_buff[(i * 16) + 8] = sprites[i]->quad->colors[8];
        c_buff[(i * 16) + 9] = sprites[i]->quad->colors[9];
        c_buff[(i * 16) + 10] = sprites[i]->quad->colors[10];
        c_buff[(i * 16) + 11] = sprites[i]->quad->colors[11];
        c_buff[(i * 16) + 12] = sprites[i]->quad->colors[12];
        c_buff[(i * 16) + 13] = sprites[i]->quad->colors[13];
        c_buff[(i * 16) + 14] = sprites[i]->quad->colors[14];
        c_buff[(i * 16) + 15] = sprites[i]->quad->colors[15];

        i_buff[(i * 6) + 0] = sprites[i]->quad->indices[0]; //indices
        i_buff[(i * 6) + 1] = sprites[i]->quad->indices[1];
        i_buff[(i * 6) + 2] = sprites[i]->quad->indices[2];

        i_buff[(i * 6) + 3] = sprites[i]->quad->indices[3];
        i_buff[(i * 6) + 4] = sprites[i]->quad->indices[4];
        i_buff[(i * 6) + 5] = sprites[i]->quad->indices[5];

        print_vbuff(v_buff, SPRITE_COUNT, "v_buffer");
        print_cbuff(c_buff, SPRITE_COUNT, "c_buffer");
        print_ibuff(i_buff, SPRITE_COUNT, "i_buffer");
    }

    vmathM4Mul(&mvp_mat, &p_mat, &v_mat);

    glUniformMatrix4fv(view_mat_loc, 1, GL_FALSE, vmathM4GetData(&v_mat));
    glUniformMatrix4fv(proj_mat_loc, 1, GL_FALSE, vmathM4GetData(&p_mat));
    glUniformMatrix4fv(mvp_matrix_loc, 1, GL_FALSE, vmathM4GetData(&mvp_mat));

    glBindBuffer(GL_ARRAY_BUFFER, vert_buff);
    glBufferData(GL_ARRAY_BUFFER,
                 SPRITE_COUNT * sizeof(sprites[0]->quad->vertices), v_buff,
                 GL_STREAM_DRAW);

    glBindBuffer(GL_ARRAY_BUFFER, col_buff);
    glBufferData(GL_ARRAY_BUFFER,
                 SPRITE_COUNT * sizeof(sprites[0]->quad->colors), c_buff,
                 GL_STREAM_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ind_buff);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER,
                 SPRITE_COUNT * sizeof(sprites[0]->quad->indices), i_buff,
                 GL_STREAM_DRAW);

    glDrawElements(GL_TRIANGLES, SPRITE_COUNT * sprites[0]->quad->vertex_count,
                   GL_UNSIGNED_SHORT, 0);

    glBindVertexArray(0);
}

目前这只画了1个四边形,它的颜色正确,我的日志记录输出看起来还不错,所以我不知道我哪里出错了。

这是上面代码的示例输出。

void print_vbuff(float* i, int count, char* tag) {
    printf("%s\n", tag);
    for (int k = 0; k < count; k++) {
        printf(
            "      v0 v1 v2 v3                    \n"
            "-------------------------------------\n "
            "x%d   %3.0f %3.0f %3.0f %3.0f \n "
            "y%d   %3.0f %3.0f %3.0f %3.0f \n "
            "z%d   %3.0f %3.0f %3.0f %3.0f \n\n ",
            k, i[(12 * k) + 0], i[(12 * k) + 3], i[(12 * k) + 6],
            i[(12 * k) + 9], k, i[(12 * k) + 1], i[(12 * k) + 4],
            i[(12 * k) + 7], i[(12 * k) + 10], k, i[(12 * k) + 2],
            i[(12 * k) + 5], i[(12 * k) + 8], i[(12 * k) + 11]);
    }
    printf("\n\n\n");
}

void print_cbuff(float* i, int count, char* tag) {
    printf("%s\n", tag);
    for (int k = 0; k < count; k++) {
        printf(
            "      v0 v1 v2 v3                    \n"
            "-------------------------------------\n "
            "x%d   %3.0f %3.0f %3.0f %3.0f \n "
            "y%d   %3.0f %3.0f %3.0f %3.0f \n "
            "z%d   %3.0f %3.0f %3.0f %3.0f \n "
            "z%d   %3.0f %3.0f %3.0f %3.0f \n\n ",
            k, i[(16 * k) + 0], i[(16 * k) + 4], i[(16 * k) + 8],
            i[(16 * k) + 12], k, i[(16 * k) + 1], i[(16 * k) + 5],
            i[(16 * k) + 9], i[(16 * k) + 13], k, i[(16 * k) + 2],
            i[(16 * k) + 6], i[(16 * k) + 10], i[(16 * k) + 14], k,
            i[(16 * k) + 3], i[(16 * k) + 7], i[(16 * k) + 11],
            i[(16 * k) + 15]);
    }
    printf("\n\n\n");
}

void print_ibuff(short* i, int count, char* tag) {
    printf("%s\n", tag);
    for (int k = 0; k < count; k++) {
        printf(
            "      v0 v1                          \n"
            "-------------------------------------\n "
            "x%d  %3d %3d \n "
            "y%d  %3d %3d \n "
            "z%d  %3d %3d \n\n ",
            k, i[(6 * k) + 0], i[(6 * k) + 3], k, i[(6 * k) + 1],
            i[(6 * k) + 4], k, i[(6 * k) + 2], i[(6 * k) + 5]);
    }
    printf("\n\n\n");
}

这是运行此代码的一些示例输出:

v_buffer
      v0 v1 v2 v3
-------------------------------------
 x0   -50 -50  50  50
 y0   -50  50  50 -50
 z0     0   0   0   0

       v0 v1 v2 v3
-------------------------------------
 x1   -50 -50  50  50
 y1   -50  50  50 -50
 z1     0   0   0   0




c_buffer
      v0 v1 v2 v3
-------------------------------------
 x0     1   0   0   1
 y0     0   1   0   1
 z0     0   0   1   0
 z0     1   1   1   1

       v0 v1 v2 v3
-------------------------------------
 x1     1   0   0   1
 y1     0   1   0   1
 z1     0   0   1   0
 z1     1   1   1   1




i_buffer
      v0 v1
-------------------------------------
 x0    0   0
 y0    1   2
 z0    2   3

       v0 v1
-------------------------------------
 x1    0   0
 y1    1   2
 z1    2   3

图像:enter image description here

我是否错误地设置了我的opengl缓冲区?为什么它只渲染一个四边形?特别是当输出显示v_buff数据结构中两个四边形的顶点信息和颜色信息时?

我不明白为什么我只渲染1个四边形。

1 个答案:

答案 0 :(得分:0)

每次使用glBufferData时,都会传递SPRITE_COUNT * 48(或64)而不会将其乘以sizeof(float)。它还没有适应你。

您的GL_ELEMENT_ARRAY_BUFFER设置为sprites[0]->quad->indices且从未更新过。 spires[1]永远不会对指数做出贡献。您需要将每个精灵附加到索引缓冲区,并应用索引移位(或使用指定的基本顶点参数绘制)。

void quad_copy(void* dest, size_t dest_index, cg_quad* q) {
    memcpy(&dest[dest_index], &q->vertices, 12 * sizeof(float));
}

可能只是copypaste错误,typeof(dest)void*,你不能用数组索引直接取消引用它,它应该导致编译错误。

使用软件转换,你的性能会很差,但这是另一回事。

根据要求解释索引偏移量:

有顶点数组(假设它是位置,但就GL而言都是数组 分享相同的指数,所以并不重要),你的第一个四边形的顶点 A1,B1,C1和D1呈线性排列:

|A1B1C1D1|

所以顶点索引是0,1,2和3.

现在将第二个四边形添加到数组尾部:

|A1B1C1D1A2B2C2D2|

A2的索引 - 第二个四边形的第一个顶点 - 不再是零,就像它一样 单独的数组,但4。 这是第二个四分之一'base index'(通常称为“基本顶点”) - 基本上是偏移的 从此对象的数据开始的顶点数组的开头。第三个四分之一 从索引8开始,依此类推。

在一般情况下,您需要在数组中保存当前顶点数,并将其用作 附加另一个对象时的基本索引,但因为你的情况很简单 你只能有四边形(而不是任意大小的对象),你可以轻松转换 objectc指向基本索引。由于每个四边形只有4个唯一的顶点,每个顶点 quad占4个索引,因此quad N的基本索引是N * 4.