如何在iPhone OpenGL ES粒子系统中绘制1000多个粒子(具有独特的旋转,缩放和alpha)而不会减慢游戏速度?
我正在开发一个使用OpenGL ES 1.1的iPhone游戏。 在这个游戏中,我会有一些血液粒子在被射击时从angular色中散发出来,所以在任何时候屏幕上都会有1000多个血液粒子。 问题是,当我有超过500个粒子渲染,游戏的帧速率下降非常大。
目前,每个粒子使用glDrawArrays(..)渲染自己,我知道这是造成速度减慢的原因。 所有的粒子共享相同的纹理地图集。
那么减less绘制多个粒子的速度最好的select是什么? 以下是我find的选项:
- 将所有的血液粒子组合在一起,并使用一个单一的glDrawArrays(..)调用渲染 – 如果我使用这种方法,有没有办法让每个粒子有自己的旋转和alpha? 或者当这个方法被使用时,他们都必须有相同的旋转? 如果我无法渲染具有独特旋转的粒子,那么我不能使用这个选项。
- 在OpenGL ES 2.0中使用点精灵。 我没有使用OpenGL ES 2.0,但我需要满足一个截止date,我已经在App Store上发布了我的游戏。 要使用OpenGL ES需要进行初步的研究,不幸的是我没有时间去执行。 在稍后的版本中,我将升级到OpenGL ES 2.0,但首先我只想使用1.1。
这里是每个粒子渲染本身。 这是我最初的粒子渲染方法,它使得游戏在渲染了500多个粒子之后经历了帧速率的显着下降。
// original method: each particle renders itself. // slow when many particles must be rendered [[AtlasLibrary sharedAtlasLibrary] ensureContainingTextureAtlasIsBoundInOpenGLES:self.containingAtlasKey]; glPushMatrix(); // translate glTranslatef(translation.x, translation.y, translation.z); // rotate glRotatef(rotation.x, 1, 0, 0); glRotatef(rotation.y, 0, 1, 0); glRotatef(rotation.z, 0, 0, 1); // scale glScalef(scale.x, scale.y, scale.z); // alpha glColor4f(1.0, 1.0, 1.0, alpha); // load vertices glVertexPointer(2, GL_FLOAT, 0, texturedQuad.vertices); glEnableClientState(GL_VERTEX_ARRAY); // load uv coordinates for texture glTexCoordPointer(2, GL_FLOAT, 0, texturedQuad.textureCoords); glEnableClientState(GL_TEXTURE_COORD_ARRAY); // render glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glPopMatrix();
然后我使用方法1,但粒子不能有独特的旋转,缩放,或使用这种方法(我知道)的阿尔法。
// this is method 1: group all particles and call glDrawArrays(..) once // declare vertex and uv-coordinate arrays int numParticles = 2000; CGFloat *vertices = (CGFloat *) malloc(2 * 6 * numParticles * sizeof(CGFloat)); CGFloat *uvCoordinates = (CGFloat *) malloc (2 * 6 * numParticles * sizeof(CGFloat)); ...build vertex arrays based on particle vertices and uv-coordinates. ...this part works fine. // get ready to render the particles glPushMatrix(); glLoadIdentity(); // if the particles' texture atlas is not already bound in OpenGL ES, then bind it [[AtlasLibrary sharedAtlasLibrary] ensureContainingTextureAtlasIsBoundInOpenGLES:((Particle *)[particles objectAtIndex:0]).containingAtlasKey]; glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); glVertexPointer(2, GL_FLOAT, 0, vertices); glTexCoordPointer(2, GL_FLOAT, 0, uvCoordinates); // render glDrawArrays(GL_TRIANGLES, 0, vertexIndex); glPopMatrix();
我会重申我的问题:
我如何渲染超过1000帧的帧速率,并且每个粒子仍然有独特的旋转,alpha和scale?
任何build设性的意见将真正帮助,将不胜感激!
谢谢!
每个OpenGL ES API调用都会带来很大的开销,所以在这里通过绘制循环进行数百次遍历时,看到一个放缓并不奇怪。 这不仅仅是glDrawArrays()会让你在这里,而是单独的glTranslatef(),glRotatef(),glScalef()和glColorf()调用。 由于延迟渲染在这些GPU上工作的方式,glDrawArrays()可能会成为热点,但其他调用也会伤害到你。
您应该将这些粒子顶点组合在一个数组中(最好是VBO,以便更有效地利用stream更新数据到GPU)。 你绝对可以在你的组合顶点数组中复制单个旋转,缩放等等的效果,但是你将需要执行关于顶点在旋转,缩放等时的位置的计算。对于每一帧,CPU都有一些负担,但是通过使用Accelerate框架对此进行一些vector处理可能会抵消一些负担。
颜色和alpha也可以在数组的每个顶点提供,所以你可以控制你的每个粒子。
不过,我认为你是对的,因为OpenGL ES 2.0可以通过编写自定义着色器程序来提供更好的解决scheme。 您可以发送所有点的VBO中的静态顶点,然后只需更新matrix来操作每个粒子和每个粒子顶点的alpha值。 我做了类似的事情,为程序冒名顶替者。 我在这里描述这个过程,你可以在这里下载源代码到应用程序。
使用大约1-10个纹理,每个纹理由透明背景上的200个红血球组成,然后每个纹理大约3-10次。 那么你有你的数千个点。 您以球形图案等forms绘制所有图像 – 分层爆炸。
在游戏中,你不能总是和现实做一对一的对应。 仔细观察一下在旧的Xbox或iPad等上运行的游戏 – 有一些捷径需要做 – 而且它们通常看起来很棒。
- Delphi FireMonkey iOS应用程序:部署到iPhone模拟器8.1时出错
- iOS – UIAppearance appearanceWhenContainedIn的问题
- 在将Xcode更新到IOS 9之后,启animation面上的应用程序和初始viewcontroller不加载
- SpriteKit:使用SKTextureAtlas会导致不正确的Physics Body
- iOS自动完成function
- UIView的Frame属性未在iOS中的动画内部分配
- 将NSUInteger添加到NSMutableArray
- 使用iOS SDK和完整的Cocoa Touch / Objective-C代码确定用户的设备
- 将string的NSMutableArray添加到UILabel时,程序崩溃