如何提高配料性能


9

我正在为移动平台开发基于Sprite的2D游戏,并且正在使用OpenGL(实际上是Irrlicht)来渲染图形。首先,我以一种简单的方式实现了精灵渲染:将每个游戏对象渲染为具有自己的GPU绘制调用的四边形,这意味着如果我有200个游戏对象,则每帧进行200个绘制调用。当然,这是一个错误的选择,我的游戏完全受CPU限制,因为每个GPU绘制调用中都有少许CPU开销。GPU大多数时候都保持空闲状态。

现在,我认为我可以通过将对象分成大批并仅用几次绘制调用就可以渲染这些批处理来提高性能。我实施了批处理(以便共享相同纹理的每个游戏对象都以同一批进行渲染),并认为我的问题已经消失了……只是发现我的帧频比以前更低。

为什么?好吧,我有200个(或更多)游戏对象,并且每秒更新60次。我必须在每一帧中重新计算CPU中顶点的新位置(平移和旋转)(移动平台上的GPU不支持实例化,因此我无法在其中进行实例化),并每秒进行48000次计算(200 * 60 * 4,因为每个子图都有4个顶点)似乎太慢了。

我可以做些什么来提高性能?所有游戏对象都(几乎)每帧都在移动/旋转,所以我真的不得不重新计算顶点位置。我能想到的唯一优化是旋转的查找表,这样我就不必计算旋转。点精灵会有所帮助吗?有讨厌的骇客吗?还要别的吗?

谢谢。

Answers:


5

您是否将irrlicht端口用于android?对于Android和iPhone上的2D精灵,我使用与您相同的技巧:批处理。我在OpenGL ES 1.x和2.x中尝试了许多解决方案:

  • 按z(视差)和纹理排序,在CPU上进行转换并调用glDrawArrays或glDrawElements(最快的方法)。如果可以,请使用一种大纹理。
  • 使用VBO的技巧相同,但速度不快,因为对于每一帧,您都会刷新所有信息。它对于静态精灵很有用。
  • 使用OpenGL ES 2.x并使用顶点着色器计算位置(较慢)
  • 使用PointSprites(如果不是正方形且透明像素过多会导致填充率降低,则无法解决)
  • 使用gldrawtexoes扩展...
  • 对每个精灵使用一次drawcall(最慢的方法)

因此,就像您一样,所有转换都是由CPU为OGLES 1.x或OGLES 2.x完成的。如果您有霓虹灯指令,则可以使用它们来加快计算速度。

附言:在iPhone或Android设备上,我不受CPU限制,但填充率受限制。因此,限制透支非常重要。


太好了,这是我一直在寻找的东西。我不知道您的Irrlicht端口,但是我的Irrlicht版本已经在iOS上运行。您说您不受CPU限制-您要绘制多少个精灵?例如,对于iPhone上的100个精灵,您的帧速率是多少?如果我有200个对象,我每秒将进行48000次计算。您对填充率的观点很好。
user4241 2011年

静态图片(背景)在VBO中。我为每个视差使用一个VBO。否则,我在Moblox上有100到200个精灵。在包括3G在内的所有iPhone上,我都超过了30fps(我记得)。但是大的精灵非常昂贵(填充率问题)..
Ellis

我正在使用粒子引擎,可以在CPU上完成所有位置计算的情况下最多使用20000个粒子,并且在极限设置下(在3GS和iPhone4上)具有10fps。因此,在3GS或iPhone4上必须有1000个具有良好帧速率的子画面。
Ellis

谢谢,非常有帮助!您如何实现粒子引擎?我想您正在玩着色器?
user4241 2011年

我使用着色器是因为我需要gl_PointSize来设置每个粒子大小。我不再使用OGLES 1.x,因为旧手机不是我的目标。首先,我所有的代码都是OGLES 1.x,然后是OGLES 1.x和OGLES 2.x(没有性能改进),现在是OGLES 2.x(渲染性能)。
艾利斯(Ellis)

1

我建议您使用一个VBO,每个顶点包含每个渲染对象的位置/旋转,并像您所做的那样基于纹理进行批处理。我对ogl ES不太熟悉,因此我不确定它支持的glsl版本,但是您甚至可以基于一组纹理进行批处理,并存储要传递的4种左右纹理中的哪一种您将在顶点内部使用。点精灵肯定会提高您的性能,因为它会大大减少发送的数据量,如果正确执行批处理,则决不能降低性能。另外,您可以通过计算着色器上的旋转并仅将int / float值传递到参数中或顶点本身内部,从而稍微提高性能。(参数会更快,


谢谢您的回答。关于在着色器中进行旋转计算的建议是excellet,但不幸的是,我使用的是不支持着色器的OpenGL ES 1,因此我只能使用固定管线。我将尝试点精灵,但由于它们的大小有上限,因此无法在所有情况下使用它们。我对VBO还是有些悲观,如果我要重新计算每帧每个顶点的位置,VBO有什么帮助?
user4241

它允许您的顶点数据保留在GPU上,从而减少了每帧必须发送到GPU的数据量。您不需要着色器即可利用此方法,根本不需要更改顶点数据,如果每个精灵都有一个基本位置(例如原点),则可以通过以下方式更改世界矩阵:在调用draw之前先进行转换。但是,批处理时可能很难。使用固定功能,至少现在切换到VBO并取消批处理可能会更有益,这肯定会给您带来很大的帮助。
sringer 2011年

我明白你的意思了。因此,毕竟,您不是在谈论批处理,而只是使用一个draw调用来绘制一个游戏对象。我肯定会测试没有批处理的VBO如何影响我的游戏中的FPS,但是每帧200个抽签仍然听起来太大了……但是我想我那时必须忍受它。如果没有其他答案,我将接受您的回答。
2011年

1

您提到了没有实例化的移动平台。但是,您仍然有顶点着色器,不是吗?

在这种情况下,您仍然可以执行伪实例化,这也非常快。制作一个VBO(GL_STATIC_DRAW),其中带有角点(相对于精灵的中心点,例如-1 / -1、1 //-1、1 / 1,-1 / 1/1)以及您需要的任何纹理坐标。
然后,将每个绘制调用的通用顶点属性之一设置为精灵的中心点,并绘制两个带缓冲区边界的三角形。在顶点着色器中,读取通用顶点属性并添加顶点的坐标。

这样可以节省您为每个子画面进行数据传输的时间,并且速度要快得多。绘制调用的实际数目并不是那么重要,它们之间的阻塞/停滞是非常重要的。


对于OpenGL ES 2.0来说,这听起来不错。不幸的是,我使用的ES 1根本没有着色器。
user4241 2011年

0

问题在于每帧要发送给GPU的数据量。只需为每个批次创建一个VBO并填充一次,然后在绘制批次时应用相应的转换矩阵(通过glMultMatrix或着色器(如果使用的是ES 2.0))。


我不知道当我有200个具有独特转换的独立游戏对象时,这有什么帮助?使用glMultMatrix会将相同的转换应用于所有对象,这不是我想要的。同样,向GPU发送数据也不是瓶颈。如果我删除CPU端转换,性能非常好。
user4241 2011年

是的,但是如果正确应用,VBO仍可以提高性能。您目前如何渲染200个对象?您在使用glBegin / glEnd吗?
TheBuzzSaw 2011年

1
我将Irrlicht 3D引擎与自定义场景节点一起使用,因此我没有直接使用OpenGL(但在这种情况下,我想它使用的是简单的glBegin / glEnd)。VBO真的有帮助吗,因为我必须每帧修改整个缓冲区?另外,由于顶点变换计算,这不能解决关于CPU约束的根本问题。但是还是谢谢您的回答!
user4241 2011年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.