改进OpenGL粒子系统

5

我正在寻找一种提高粒子系统性能的方法,因为它在FPS方面非常昂贵。 这是因为我调用了:

glDrawElements(GL_TRIANGLE_STRIP, mNumberOfIndices,
          GL_UNSIGNED_SHORT, 0);

我在我的应用程序中为每个粒子调用此方法(可能在1000到5000个粒子之间)。请注意,当粒子数量增加到1000以上时,我的应用程序开始下降FPS。我正在使用VBO:s,但是调用此方法的性能太昂贵了。
有什么想法可以使粒子系统更有效?
编辑:这是我的粒子系统绘制事物的方式:
glBindTexture(GL_TEXTURE_2D, textureObject);
glBindBuffer(GL_ARRAY_BUFFER, vboVertexBuffer[0]);
glVertexPointer(3, GL_FLOAT, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, vboTextureBuffer[0]);
glTexCoordPointer(2, GL_FLOAT, 0, 0); 
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboIndexBuffer[0]);

Vector3f partPos;

for (int i = 0; i < m_numParticles; i++) {
    partPos = m_particleList[i].m_pos;          
    glTranslatef(partPos.x, partPos.y, partPos.z);
    glDrawElements(GL_TRIANGLE_STRIP, mNumberOfIndices, 
        GL_UNSIGNED_SHORT, 0);
    gl.glTranslatef(-partPos.x, -partPos.y, -partPos.z);
}

2
你在使用什么数据类型来表示坐标等内容?如果你没有使用 GL_FLOAT 以外的其他类型,那么你可能会遇到(巨大的)性能下降。 - Rookie
@新手:我有浮点数值。 - Curtain
我知道这篇文章有点旧了,但是对于任何想知道的人,这里是我发现的一个很棒的教程。(我不是这个教程的作者)。http://www.opengl-tutorial.org/intermediate-tutorials/billboards-particles/particles-instancing/ - Thibault Reuille
2个回答

7

从您的描述来看,似乎您为每个粒子都有一个独立的VBO。这不是正确的做法。应该将所有粒子放入一个单一的VBO中,并使用单个glDrawElementsglDrawArrays调用一次性绘制它们全部。如果可用,最好使用实例化。


谢谢回答,但我为每个粒子重用相同的VBO。然后,我只是使用 glDrawElements() 循环遍历每个粒子。问题在于这太多次调用 glDrawElements(),我不清楚应该如何解决它。 - Curtain
答案很明显:使用单个绘制调用绘制整个粒子系统。 - kvark
@kvark:这对我来说不是一个很大的惊醒。问题是,由于每个粒子都需要自己的位置,所以哪种方法是最好的?在绘制时修改VBO吗? - Curtain
将它们全部一次性放入单个VBO中。将其作为未连接面的单个(大)网格。粒子1和索引0,1,2,3,粒子2在索引4,5,6,7等处。 - datenwolf
@datenwolf:谢谢,我回家后会试一下。 :) - Curtain
3
朱利安·阿桑奇。关键是:粒子位置数据仍然会从系统内存传输到VRAM以进行绘制。在您当前的实现中,它以内部uniforms的形式传递,通过glTranslate设置。如果您将粒子位置作为VBO的一部分,并每帧更改它,那么仍将有相同数量的数据传输总线。但绘图操作将更快。 - kvark

2
稍微解释一下datenwolf所说的,只需将所有粒子索引打包到一个索引缓冲区中,并使用单个glDrawElements调用绘制所有粒子。这意味着您不能再使用三角形条带,而是要使用三角形集,但这不应该是太大的问题。
否则,如果您的硬件支持实例渲染(或更好的实例数组),则可以通过从每个粒子的相应数组中获取位置和texCoord数据,并将单个粒子渲染n次来完成。然后,您仍然需要在顶点着色器中计算四个角的位置和texCoord数据(假设您为每个粒子绘制一个四边形),因为使用实例数组时,您仅获得每个实例(粒子)的一个属性。
您还可以使用几何着色器创建粒子的四边形,并仅渲染单个点集,但我认为这可能比实例化慢,考虑到SM4 / GL3硬件很可能也支持实例化。

谢谢回答。好的,那么我需要将所有粒子放入一个单独的VBO中,其中包含正确的x、y和z坐标(我可以跳过它们的转换),因为它们需要在不同的位置渲染。然而,在绘制时上传新的VBO到OpenGL是否高效,因为位置总是会改变? - Curtain
1
@Julian 只需将位置缓冲区设置为 GL_DYNAMIC_DRAW(甚至是 GL_STREM_DRAW?),并在每帧更新它(使用 glMapBufferglBuffer(Sub)Data),这应该比您当前的解决方案快。 - Christian Rau
谢谢,等我到电脑前尝试一下。 :) - Curtain

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接