在 OpenGL 中,在保持良好帧速率的同时,VBO 中有多少个顶点的好目标是什么



我正在从头开始制作2D游戏引擎,主要是为了好玩。最近我一直非常担心整个发动机的性能。我一直在阅读关于目标多边形数量的文章,试图达到,我已经看到了数百万的谈话,同时我只设法获得了 40,000 个,而帧速率没有可怕的下降。

我尝试使用显卡中的映射缓冲区而不是我自己的缓冲区,但这实际上给了我更差的性能。我已经读过像三重缓冲区渲染这样的技术,我可以看到它在理论上如何加速它,我无法想象它会加速我的代码到我读过的数百万。

我使用的格式是 28 字节顶点(三个浮点用于位置,2 个浮点用于纹理坐标,1 个浮点用于颜色,1 个用于从哪个纹理缓冲区读取)。我曾考虑过将其修剪下来,但似乎又一次不值得。

浏览我的代码 几乎 98% 的时间都花在分配、填充和将 VAO 提供给显卡上。所以这是我目前唯一的瓶颈。

所有的精灵都只是 4 面多边形,我只是用GL_QUADS来渲染整个对象。 40,000 精灵感觉真的很低。我只有一次抽奖电话,所以我从我读到的内容中期待至少 10 倍。我领导过一些模型仅在 40D 中就有近 30k 个多边形!

以下是我如何呈现这一切的一些相关代码:

//This is the main render loop, currently it's only called once per frame
for (int i = 0; i < l_Layers.size(); i++) {
glUseProgram(l_Layers[i]->getShader().getShaderProgram());
GLint loc = glGetUniformLocation(l_Layers[i]->getShader().getShaderProgram(), "MVT");
glUniformMatrix4fv(loc,1, GL_FALSE, mat.data);
l_Layers[i]->getVertexBuffer().Bind();
glDrawArrays(GL_QUADS, 0, l_Layers[i]->getVertexBuffer().getSize());
l_Layers[i]->getVertexBuffer().Unbind();
}
//These lines of code take up by far the most compute time
void OP::VertexBuffer::startBuffer(int size)
{
flush();
Vertices = new Vertex[size * 4];
}
void OP::VertexBuffer::submit(Vertex vertex)
{
Vertices[Index] = vertex;
Index++;
}
void Layer::Render() {
l_VertexBuffer.startBuffer(l_Sprites.size());
for (size_t i = 0; i < l_Sprites.size(); i++) {
Vertex* vert = l_Sprites[i]->getVertexArray();
l_VertexBuffer.submit(vert[0]);
l_VertexBuffer.submit(vert[1]);
l_VertexBuffer.submit(vert[2]);
l_VertexBuffer.submit(vert[3]);
}
}

我不知道我做错了什么,但我只是不明白人们如何在屏幕上获得更多数量级的多边形。特别是当他们有比我GL_QUADS更复杂的模型时。

98% 的时间都花在分配、填充和将 VAO 提供给显卡上。所以这是我目前唯一的瓶颈。

创建 VAO 并填充它实际上应该只发生一次,因此不会影响帧速率,您只需需要在调用 render 之前绑定 VAO。

显然,我看不到您的所有代码,所以我可能有错误的想法,但看起来您每次调用 Render 时都会创建一个新的顶点数组。

你把所有的时间都花在这里,我并不感到惊讶:

//These lines of code take up by far the most compute time
void OP::VertexBuffer::startBuffer(int size)
{
flush();
Vertices = new Vertex[size * 4];
}

在每次渲染调用大型数组时调用new会极大地影响您的性能,您还会花时间将每一帧分配给该数组。

最重要的是,您似乎正在泄漏内存。

每次致电时:

Vertices = new Vertex[size * 4];

您未能释放在上次调用 Render 时分配的数组。您正在执行的操作类似于以下示例:

foo = new Foo();
foo = new Foo();

内存在第一次调用中分配给 foo,创建的第一个 foo 从未被解构或解除分配,现在没有办法这样做,因为 foo 已被重新分配,因此第一个 foo 已经泄漏。

所以我认为你在这里遇到了一系列问题。

相关内容

  • 没有找到相关文章