How do I draw 1000+ particles (w/ unique rotation, scale, and alpha) in iPhone OpenGL ES particle system without slowing down the game?

主宰稳场 提交于 2019-12-18 12:44:39

问题


I am developing a game for iPhone using OpenGL ES 1.1. In this game, I have blood particles which emit from characters when they are shot, so there can be 1000+ blood particles on the screen at any one time. The problem is that when I have over 500 particles to render, the game's frame rate drops immensely.

Currently, each particle renders itself using glDrawArrays(..), and I know this is the cause for the slow down. All particles share the same texture atlas.

So what is the best option to reduce slow down from drawing many particles? Here are the options I found:

  1. group all the blood particles together and render them using a single glDrawArrays(..) call --if I use this method, is there a way for each particle to have its own rotation and alpha? Or do all of them HAVE to have the same rotation when this method is used? If I can't render particles with unique rotation, then I cannot use this option.
  2. Use point sprites in OpenGL ES 2.0. I am not using OpenGL ES 2.0 yet b/c I need to meet a deadline which I have set to release my game on the App Store. To use OpenGL ES would require preliminary research which unfortunately I do not have the time to perform. I will upgrade to OpenGL ES 2.0 upon a later release, but for the first, I only want to use 1.1.

Here is each particle rendering itself. This is my original particle-rendering methodolgy which caused the game to experience a significant drop in frame rate after 500+ particles were being rendered.

// 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();

Then I used method 1, but particles can't have unique rotation, scale, or alpha using this method (that I know of).

    // 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();

I'll reiterate my question:
How do I render 1000+ particles without frame rate drastically dropping and each particle can still have unique rotation, alpha, and scale?

Any constructive advice would really help and would be greatly appreciated!

Thanks!


回答1:


There is significant overhead with each OpenGL ES API call, so it's not a surprise that you're seeing a slowdown here with hundreds of passes through that drawing loop. It's not just glDrawArrays() that will get you here, but the individual glTranslatef(), glRotatef(), glScalef(), and glColorf() calls as well. glDrawArrays() may appear to be the hotspot, due to the way that deferred rendering works on these GPUs, but those other calls will also hurt you.

You should group these particle vertices together in one array (preferably a VBO so that you can take advantage of streaming updated data to the GPU more efficiently). You definitely can replicate the effects of individual rotation, scale, etc. in your combined vertex array, but you're going to need to perform the calculations as to where the vertices should be as they are rotated, scaled, etc. This will place some burden on the CPU for every frame, but that could be offset a bit by using the Accelerate framework to do some vector processing of this.

Color and alpha can be provided per-vertex in an array as well, so you can control that for each one of your particles.

However, I think you're right in that OpenGL ES 2.0 could provide an even better solution for this by letting you write a custom shader program. You could send static vertices in a VBO for all your points, then only have to update matrices to manipulate each particle and the alpha values for each particle vertex. I do something similar to generate procedural impostors as stand-ins for spheres. I describe this process here, and you can download the source code to the application here.




回答2:


Use about 1- 10 textures, each made of say 200 red blood dots on a transparent background, and then draw them each about 3 - 10 times. Then you have your thousands of dots. You draw all the images in a spherical pattern, etc - exploding in layers.

You can't always do a 1 to 1 correspondence with reality when gaming. Take a real close look at some games that run on old Xbox or iPad, etc - there are shortcuts you need to do - and they often look great when done.



来源:https://stackoverflow.com/questions/7435123/how-do-i-draw-1000-particles-w-unique-rotation-scale-and-alpha-in-iphone-o

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!