我正在尝试将多个精灵批处理到一个大缓冲区中,但是我遇到了一些技术问题。我想我没有正确设置我的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
我是否错误地设置了我的opengl缓冲区?为什么它只渲染一个四边形?特别是当输出显示v_buff数据结构中两个四边形的顶点信息和颜色信息时?
我不明白为什么我只渲染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.