当我调用glDrawElements时,我会有一些奇怪的行为



我正在编写一个基本的纹理批处理渲染器,但不知何故,它只渲染一个纹理,而不是四个。下面的代码有什么问题吗?我找不到任何错误。我正在使用GLEW和GLFW进行开窗。

VertexBuffer、VertexArray、IndexBuffer、Shader和Texture类已经过测试,并且工作正常。

void BatchRenderObjects(vector<ObjectInstance> texq, GLuint tex_id, Shader shader)
{
int current_index = 0;
int array_index = 0;
const size_t vb_size = 20 * (texq.size());
const size_t ib_size = 6 * texq.size();
const size_t texslot_size = 32;
VertexBuffer VBO(GL_ARRAY_BUFFER);
IndexBuffer IBO;
VertexArray VAO;
GLfloat *vertex_buffer = new GLfloat[vb_size];
GLuint *index_buffer = new GLuint[ib_size];
{
unsigned int offset = 0;
for (int i = 0; i < ib_size; i += 6)
{
index_buffer[i + 0] = 0 + offset;
index_buffer[i + 1] = 1 + offset;
index_buffer[i + 2] = 2 + offset;
index_buffer[i + 3] = 2 + offset;
index_buffer[i + 4] = 3 + offset;
index_buffer[i + 5] = 0 + offset;
offset += 4;
}
}
{
for (int i = 0; i < texq.size(); i++)
{
vertex_buffer[current_index + 0] = texq[i].coords[0];
vertex_buffer[current_index + 1] = texq[i].coords[1];
vertex_buffer[current_index + 2] = texq[i].coords[2];
vertex_buffer[current_index + 3] = texq[i].tex_coords[0];
vertex_buffer[current_index + 4] = texq[i].tex_coords[1];
vertex_buffer[current_index + 5] = texq[i].coords[3];
vertex_buffer[current_index + 6] = texq[i].coords[4];
vertex_buffer[current_index + 7] = texq[i].coords[5];
vertex_buffer[current_index + 8] = texq[i].tex_coords[2];
vertex_buffer[current_index + 9] = texq[i].tex_coords[3];
vertex_buffer[current_index + 10] = texq[i].coords[6];
vertex_buffer[current_index + 11] = texq[i].coords[7];
vertex_buffer[current_index + 12] = texq[i].coords[8];
vertex_buffer[current_index + 13] = texq[i].tex_coords[4];
vertex_buffer[current_index + 14] = texq[i].tex_coords[5];
vertex_buffer[current_index + 15] = texq[i].coords[9];
vertex_buffer[current_index + 16] = texq[i].coords[10];
vertex_buffer[current_index + 17] = texq[i].coords[11];
vertex_buffer[current_index + 18] = texq[i].tex_coords[6];
vertex_buffer[current_index + 19] = texq[i].tex_coords[7];
current_index = current_index + 20;
}
}
// Setup vertex buffer, index buffer and vertex array
{
VAO.Bind();
VBO.BufferData(vb_size, vertex_buffer, GL_STATIC_DRAW);
VBO.VertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0);
VBO.VertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
IBO.BufferData(ib_size, index_buffer, GL_STATIC_DRAW);
VAO.Unbind();
}
shader.Use();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex_id);
glUniform1i(glGetUniformLocation(shader.GetProgramID(), "u_Texture"), 0);
VAO.Bind();
glDrawElements(GL_TRIANGLES, 6 * texq.size(), GL_UNSIGNED_INT, 0);
//glDrawArrays(GL_TRIANGLES, 0, 24); 
VAO.Unbind();
return; 
}

它实际上是非常基本的。它从结构中生成"顶点缓冲区"one_answers"索引缓冲区",并在屏幕上绘制纹理。这是ObjectInstance结构。

struct  ObjectInstance
{
float coords[12]; 
float tex_coords[8];
};

最后是我的主要函数的片段。

ObjectInstance t1 = { {-1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f},
{1.0f, 1.0f,  1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}};
ObjectInstance t2 = { {-1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 1.0f, 0.0f},
{1.0f, 1.0f,  1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}};
ObjectInstance t3 = { {0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f},
{1.0f, 1.0f,  1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}};
ObjectInstance t4 = { {0.0f, -1.0f, 0.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
{1.0f, 1.0f,  1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}};
std::vector<ObjectInstance> test_vector;
test_vector.push_back(t1);
test_vector.push_back(t2);
test_vector.push_back(t3);
test_vector.push_back(t4);

我在游戏循环中用适当的参数调用函数。

最后是我的顶点和片段着色器。VERTEX SHADER:

#version 330 core
layout(location = 0) in vec3 position;
layout(location = 1) in vec2 texCoord;
out vec2 TexCoord;
void main()
{
gl_Position = vec4(position, 1.0f);
TexCoord = texCoord; 
}

碎片阴影

#version 330 core
in vec2 TexCoord;
out vec4 color; // the color outputted
uniform sampler2D u_Texture;
void main()
{
color = texture(u_Texture, TexCoord); 
}

不,我有一个纹理,我想画4次。这只是我想在屏幕的不同坐标中绘制的一个纹理。但是,显然我只得到了其中一个打印在左下角。你知道我为什么会犯这个错误吗?

让我们从以下代码开始:

const size_t vb_size = 20 * (texq.size());of GLfloats
const size_t ib_size = 6 * texq.size();

不知道您的特定缓冲区对象抽象类,但GL中的glBufferData预计大小(以字节为单位(,因此

VBO.BufferData(vb_size, ...);
IBO.BufferData(ib_size, ...);

将只上传您实际数据的1/4(意外地与您四个对象中的第一个完全匹配(。

所有对象都具有相同的纹理坐标。由于您正在编写批渲染器,因此所有对象都使用一个draw调用进行渲染,这意味着一个纹理(至少,从您的代码来看,这似乎是您的方法,因为您只绑定了一个纹理,并且着色器中没有代码使用当前绑定的单个纹理以外的任何其他纹理(。

所以我假设你有一个由四个不同图像组成的纹理?如果是这样的话,你应该得到你的4个对象,但每个对象都显示了一个纹理中的所有四个图像。要修复它,你必须调整你的纹理坐标,如下所示:

ObjectInstance t1 = { {-1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f},
{0.5f, 0.5f,  0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f}};
ObjectInstance t2 = { {-1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 1.0f, 0.0f},
{0.5, 1.0f,  0.5f, 0.5f, 0.0f, 0.5f, 0.0f, 1.0f}};

等等。我还没有检查过,但这应该是你问题的原因。

另一种选择是绑定多个纹理,并为每个对象提供某种id,您可以在片段着色器中访问该id,以确定要使用的纹理单位。在这种情况下,在设置代码和片段着色器中还有一些工作要做。

嘿,问题来了。

const size_t vb_size = 20 * (texq.size());
const size_t ib_size = 6 * texq.size();

应该是

const size_t vb_size = (20 * (texq.size())) * sizeof(GLfloat); 
const size_t ib_size = (6 * texq.size()) * sizeof(GLfloat);

这是因为OpenGL的大小以原始字节为单位。

我遇到了问题。这是因为opengl采用了字节大小。正如塞缪尔所指出的。。

嘿,问题来了。

const size_t vb_size = 20 * (texq.size());
const size_t ib_size = 6 * texq.size();

应该是

const size_t vb_size = (20 * (texq.size())) * sizeof(GLfloat); 
const size_t ib_size = (6 * texq.size()) * sizeof(GLfloat);

最新更新