0

我正在尝试将多个精灵批处理到一个大缓冲区中,但我遇到了一些技术难题。我想我没有正确设置我的 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);

这是精灵对象。

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);

我还创建了一堆临时结构来为每个精灵进行计算,但如果可能的话,我想简化一下:

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

图片:在此处输入图像描述

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

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

4

1 回答 1

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));
}

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

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

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

拥有顶点数组(假设它是位置,但就 GL 而言,所有数组共享相同的索引,所以并不重要),您的第一个四边形的顶点 A1、B1、C1 和 D1 线性放置在数组中:

|A1B1C1D1|

所以顶点索引是 0、1、2 和 3。

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

|A1B1C1D1A2B2C2D2|

A2 的索引 - 第二个四边形的第一个顶点 - 不再是零,因为它在单独的数组中,而是 4。这是第二个四边形的“基本索引”(通常称为“基本顶点”) - 基本上从顶点数组的开头偏移,其中此对象的数据开始。第三个四边形将从索引 8 开始,依此类推。

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

于 2016-01-12T10:15:39.487 回答