粒子系统设计?

时间:2009-09-23 12:37:30

标签: opengl oop particles

我正在设计自己的粒子系统引擎,这是出于学习目的,我真的不想使用现有的引擎。

现在我生成了漂亮的粒子,但是我想布置引擎以便更容易使用它们。

我一直在思考类“粒子系统”,

该类将包含以下引用:

particlesList :组成系统的粒子列表。

systemEmitter :粒子的系统发射器,Emitter类应该能够执行几种粒子发射技术,例如,从多边形中随机发射的线,点发射。此类也应该进行排放控制,例如朝向一个点,远离一个点,沿着发射的方向和时间发射。

particleController :管理例如围绕点旋转,可变粒径,可变粒子颜色,粒子以不同方式作出反应的系统周围区域,碰撞检测(与其他对象或在粒子如果变得必要的话。)

粒子渲染器:负责绘制此系统,变量混合类型,粒子纹理,粒子类型,如三角形,圆形,自定义......

这四个项目将构成粒子系统类。有些FX可能需要多个粒子系统,例如Fire FX,可以使用一个系统进行火灾,一个系统用于烟雾,一个系统用于火花。

这就是我的想法,但我真的很想知道这种设计方法是否合适,或者你是否看到我缺少某些东西或者能够/应该做些不同的事情。我没有想过一些简单的方法来“保存”FX,例如什么是告诉我的引擎的最佳方式,“画火”,“画爆炸”,“画喷泉”等,也许存储外汇信息在xml文件中是个好主意等等。

非常欢迎意见,正如我之前所说,出于学习原因,我真的想要构建它,而不是使用其他引擎。

4 个答案:

答案 0 :(得分:5)

这个设置应该没问题。我希望你在想的是数据将构成粒子类中的粒子。您只希望拥有基本要素,因此在运行系统时只需要尽可能少地读/写内存。

就数据驱动而言应该非常直接。我建议使用xml和二进制格式选项进行加载。这样你就可以在开发过程中轻松调整内容(而且没有工具)。一旦你有了工具或完成了调整,我会将xml转换为二进制文件以便快速加载。

您可能还需要一个处理这些粒子系统的创建和更新的管理器类。这也可以让您处理与您的所有系统有关的其他功能。这方面的一些例子是限制由于性能原因或具有所有系统应考虑的碰撞平面而可以管理的粒子系统或粒子的数量。

你提到这是出于教育目的,在这方面,这些事情非常挑剔(但如果你要在一个粒子沉重的游戏中使用它,这很重要)。

我假设这是使用像DirectX或OpenGL这样的API来渲染。在这方面,我会让粒子效果共享你的顶点信息的相同内存池。这有助于提高渲染速度。我还会跟踪受粒子系统影响的区域的边界,以用于截锥体剔除(AABB或圆圈)。

更新粒子系统的一个重要部分是属性从一个值到另一个值的方式。动态越多,可以使值的插值效果越好。简单地线性插值可能已经足够好了,但是有一个用于插值的动态图可能更好。例如,在一秒钟内不是从0到255蓝色,在0.2秒内变为0到128然后在0.8秒内变为128-255可能很酷。添加它将大大增加效果外观的选项。

除此之外,我认为你对自己想做的事情有很好的了解。你提到渲染不同类型的粒子告诉我你正在以正确的方式思考这个问题。我见过人们让粒子引擎专注于渲染一个广告牌四边形。有选择发射三维几何形状真的让事情看起来很棒。您可能还想考虑(如果您还没有)您的系统能够获取模型信息并将其动态拆分为要发出的单独粒子。实际上爆炸模型看起来要好得多,然后显示一些爆炸粒子并淡出对象或将其切换到受损状态。

答案 1 :(得分:1)

优化简单的2D精灵粒子的一些想法。

一个好主意是将所有粒子发送到顶点数组/ VBO中,并使用顶点着色器随时间更新它们的位置。如果你有一个简单的动作,可以使用x(t)y(t)(即它们仅依赖于时间)的数学公式轻松描述,这是很好的。

另一个好主意是使用点精灵而不是三角形和四边形。这应该将管道上所需的带宽减少到四分之一。


在我的太空模拟中,我实施了最简单的方法:使用glBegin() / glEnd()将粒子作为纹理四边形发送。它们作为单独的对象被倾倒到当前的“扇区”中,并且完全独立于倾倒之后的时间。这是最原始,最愚蠢和最愚蠢的事情,并且负责大幅降低性能,特别是因为我所做的是通过STL向量迭代器迭代对象并按顺序发送它们中的每一个。

您需要考虑您想要多少粒子,以及您希望它们做什么。 *你想让他们对周围环境做出反应并发生碰撞吗?然后,您需要更新处理CPU和一次又一次发送的数据。 *他们只是以最愚蠢的方式飞来飞去吗?然后,您可以将所有粒子作为VBO和TBO发送,并在着色器中更新它们。

玩得开心!


更新以与提问者的评论#1相关: - )

我要做的是使用KISS principle。这意味着:一个名为ParticleEmitter的类,包含一个顶点数组,一个速度数组,以及一个STL vector,它包含简单碰撞器的实例,如平面,球体,三角形。此外,还有一个带有碰撞器的“全局”* STL vector。然后根据碰撞器更新速度。

可以使用影响因子(重力,风等)来完成类似的工作:ParticleEmitter中带有影响因子的另一个STL向量和带有影响因子的另一个“全局”STL vector

影响者和碰撞者将是实施affectParticle(particle_t*)的类。其中struct particle_t { float x,y,z; float vx,vy,vz; }。我会保留它的POD结构,并在ParticleEmitter::update()中运行更新。

但是如果你在iPhone上运行它,它可能会过度复杂吗?也许你可以逃脱已经实施的东西?我不知道我的设计会如何影响基准测试结果,但如果你保持粒子,碰撞器和影响器倒计时,这对我来说听起来很合理,因为听起来它可能会大约n*c+n*a

这些只是我的临时想法,以及我个人如何实施它。您的设计或其他人的设计可能会更好: - )

*“全局”在引号下,因为使用您正在使用的任何空间分区可能是有意义的。

答案 2 :(得分:1)

我在C ++中为自己的引擎实现了相同的优秀设计。我没有使用引用和模板策略(策略 - 阅读Alexandresku的“Modern C ++ Desing”)。静态多态性提供了更好的性能。

答案 3 :(得分:0)

我想根据自己的经验做一些评论。

  1. 传统上,大多数粒子使用AOS(Array of Struct)来存储粒子属性。但这可能不是最好的决定。使用SOA(Array of Array)表示将为您添加每个粒子系统的属性提供很大的灵活性。而且,使用SOA的SIMD可以更轻松地提高性能。例如,使用SSE指令一起做4个粒子。
  2. 粒子发射的位置仅是一个粒子属性的初始化。当您发射粒子时,您可能需要初始化其他属性,例如生命周期,速度等。您可以将所有这些功能抽象为初始化器。对于position,您可能有磁盘初始化程序,框初始化程序等。
  3. 一些现代粒子系统采用事件的概念。粒子系统可能会产生事件(例如雨与地形碰撞),而其他粒子系统可以监听并执行某些动作(例如发射飞溅)。
  4. 顺便说一句,我认为最好的方法是研究现有应用程序/中间件的设计,以及实验。