【问题标题】:2D Particle System - Performance2D 粒子系统 - 性能
【发布时间】:2011-09-22 23:06:00
【问题描述】:

我已经根据"Bulding an Advanced Particle System" (John van der Burg, Game Developer Magazine, March 2000) 中概述的想法和概念实现了一个 2D 粒子系统。

现在我想知道我应该从这个系统中获得什么性能。我目前正在我的简单(未完成)SDL/OpenGL 平台游戏的上下文中对其进行测试,其中所有粒子每帧都会更新。绘制如下

// Bind Texture
glBindTexture(GL_TEXTURE_2D, *texture);
// for all particles
    glBegin(GL_QUADS);
    glTexCoord2d(0,0);  glVertex2f(x,y);
    glTexCoord2d(1,0);  glVertex2f(x+w,y);
    glTexCoord2d(1,1);  glVertex2f(x+w,y+h);
    glTexCoord2d(0,1);  glVertex2f(x,y+h);
    glEnd();   

其中一个纹理用于​​所有粒子。

它可以平稳运行多达约 3000 个粒子。老实说,我期待更多,特别是因为这意味着要在屏幕上与多个系统一起使用。我应该期望多少个粒子才能平滑显示?

PS:我对 C++ 和 OpenGL 也比较陌生,所以很可能是我在某个地方搞砸了!?

编辑使用POINT_SPRITE

glEnable(GL_POINT_SPRITE);
glBindTexture(GL_TEXTURE_2D, *texture);
glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE); 

// for all particles
    glBegin(GL_POINTS);
    glPointSize(size);
    glVertex2f(x,y);
    glEnd();

glDisable( GL_POINT_SPRITE );

根本看不出使用GL_QUADS 的性能差异!?

编辑使用VERTEX_ARRAY

// Setup
glEnable (GL_POINT_SPRITE);                                         
glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE);              
glPointSize(20);                                    

// A big array to hold all the points
const int NumPoints = 2000;
Vector2 ArrayOfPoints[NumPoints];
for (int i = 0; i < NumPoints; i++) {
    ArrayOfPoints[i].x = 350 + rand()%201;
    ArrayOfPoints[i].y = 350 + rand()%201;
}

// Rendering
glEnableClientState(GL_VERTEX_ARRAY);     // Enable vertex arrays
glVertexPointer(2, GL_FLOAT, 0, ArrayOfPoints);     // Specify data
glDrawArrays(GL_POINTS, 0, NumPoints);  // ddraw with points, starting from the 0'th point in my array and draw exactly NumPoints

使用 VA 对上述性能产生了影响。然后我尝试了 VBO,但并没有真正看到那里的性能差异?

【问题讨论】:

    标签: c++ performance particle-system


    【解决方案1】:

    我不能说您对该解决方案有多少期望,但有一些方法可以改进它。

    首先,通过使用 glBegin() 和 glEnd(),您使用的是立即模式,据我所知,这是最慢的做事方式。此外,它甚至不再出现在当前的 OpenGL 标准中。

    对于 OpenGL 2.1

    点精灵:

    您可能想要使用点精灵。我使用它们实现了一个粒子系统,并提出了一个很好的性能(至少就我当时的知识而言)。使用点精灵,您每帧执行的 OpenGL 调用更少,并且您向显卡发送的数据更少(或者甚至将数据存储在显卡上,对此不确定)。一个简短的谷歌搜索甚至应该给你一些实现来看看。

    顶点数组:

    如果使用点精灵没有帮助,您应该考虑将顶点数组与点精灵结合使用(以节省一点内存)。基本上,您必须将粒子的顶点数据存储在一个数组中。然后,您可以通过调用 glEnableClientState() 以 GL_VERTEX_ARRAY 作为参数来启用顶点数组支持。之后,调用 glVertexPointer()(参数在 OpenGL 文档中解释)并调用 glDrawArrays() 来绘制粒子。这会将您的 OpenGL 调用减少到只有少数,而不是每帧 3000 个调用。

    适用于 OpenGL 3.3 及以上版本

    实例化:

    如果您针对 OpenGL 3.3 或更高版本进行编程,您甚至可以考虑使用实例化来绘制粒子,这样可以进一步加快速度。同样,简短的 google 搜索将让您查看一些关于此的代码。

    一般:

    使用 SSE:

    此外,更新顶点位置可能会浪费一些时间。所以,如果你想加快速度,你可以看看使用 SSE 来更新它们。如果做得正确,您将获得很多性能(至少在大量粒子时)

    数据布局:

    最后,我最近找到了一个关于数组结构 (SoA) 和结构数组 (AoS) 的链接(divergentcoder.com/programming/aos-soa-explorations-part-1,谢谢 Ben)。以粒子系统为例,对它们对性能的影响进行了比较。

    【讨论】:

    • 我已使用glGetString(GL_VERSION) 确定我当前使用的是版本 2.1.2。你能给我指一个beginner 教程来解释如何使用Point Sprites 吗?我已经阅读了一些关于它的内容,听起来不错,但是我还没有找到合适的代码吗?关于 SoA vs Aos,你指的是divergentcoder.com/programming/aos-soa-explorations-part-1吗? (有人在我之前提出的另一个问题的答案中发布了它:)
    • 哈,是的,这正是我的意思:D 好的,我又找到了这个网站:codesampler.com/oglsrc/oglsrc_6.htm,我上次基本上使用了那个代码。它不需要你做太多的改变,因为它仍然使用立即模式。因此,在那之后,如果您愿意,您仍然可以研究如何将其与 VBO 等高级 OpenGL 技术相结合
    • 我已经为 Point Sprites 尝试了一些代码(请参阅我原始问题中的编辑),但我的屏幕上没有看到任何内容?
    • 使用即时模式渲染是一个巨大的速度杀手,但一开始并不总是可见的。如果您的应用程序特别受 GPU 限制,那么在您开始受 CPU 限制之前它不会受到影响;在您的情况下,这可能是 3000 粒子标记。摆脱这种情况可能很困难,因为您每帧都在重新创建缓冲区(除非您可以使用单个四边形粒子并使用变换),但是进行一次绘制调用将为您节省 ton您的应用驱动程序中的 CPU 时间。
    • @Ben glGetError() 是否返回任何错误状态? glPointSize() 和 glPointParameterf() 设置正确了吗?
    【解决方案2】:

    考虑使用顶点数组而不是立即模式(glBegin/End):http://www.songho.ca/opengl/gl_vertexarray.html

    如果您愿意进入着色器,您也可以搜索“顶点着色器”并考虑在您的项目中使用该方法。

    【讨论】:

      猜你喜欢
      • 2015-10-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-09
      • 1970-01-01
      相关资源
      最近更新 更多