Как нарисовать более 1000 частиц (с уникальным вращением, масштабом и альфа) в системе частиц iPhone OpenGL ES без замедления игры? - PullRequest
2 голосов
/ 15 сентября 2011

Я занимаюсь разработкой игры для iPhone с использованием OpenGL ES 1.1.В этой игре у меня есть частицы крови, которые испускаются персонажами во время стрельбы, поэтому на экране одновременно может быть более 1000 частиц крови.Проблема в том, что когда у меня более 500 частиц для рендеринга, частота кадров игры очень сильно падает.

В настоящее время каждая частица рендерится, используя glDrawArrays (..) , и я знаю, что этопричина для замедления.Все частицы имеют один и тот же текстурный атлас.

Так что же является лучшим вариантом для уменьшения замедления от вытягивания множества частиц?Вот варианты, которые я нашел:

  1. сгруппируйте все частицы крови вместе и визуализируйте их, используя один glDrawArrays (..) call - если яиспользовать этот метод, есть ли способ для каждой частицы иметь свое вращение и альфа?Или все они должны иметь одинаковое вращение при использовании этого метода?Если я не могу рендерить частицы с уникальным вращением, то я не могу использовать эту опцию.
  2. Использовать точечные спрайты в OpenGL ES 2.0. Я пока не использую OpenGL ES 2.0 b / c Iнужно уложиться в срок, который я установил для выпуска своей игры в 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+ частиц без рамкискорость резко падает, и каждая частица все еще может иметь уникальное вращение, альфа и масштаб?

Любой конструктивный совет действительно помог бы и был бы очень признателен!

Спасибо!

Ответы [ 2 ]

3 голосов
/ 15 сентября 2011

Используйте около 1-10 текстур, каждая из которых сделана, скажем, из 200 красных кровяных точек на прозрачном фоне, а затем нарисуйте их примерно 3 - 10 раз. Тогда у вас есть тысячи точек. Вы рисуете все изображения в виде шаров и т. Д. - взрываясь в слоях.

Вы не всегда можете делать 1: 1 переписку с реальностью во время игры. Внимательно посмотрите на некоторые игры, которые работают на старых Xbox или iPad, и т. Д. - есть ярлыки, которые вы должны сделать - и они часто выглядят великолепно, когда закончите.

1 голос
/ 16 сентября 2011

С каждым вызовом OpenGL ES API возникают значительные издержки, поэтому неудивительно, что вы видите здесь замедление с сотнями проходов в этом цикле рисования.Здесь вы найдете не только glDrawArrays (), но и отдельные вызовы glTranslatef (), glRotatef (), glScalef () и glColorf ().glDrawArrays () может показаться горячей точкой из-за способа, которым отложенный рендеринг работает на этих графических процессорах, но эти другие вызовы также повредят вам.

Вы должны сгруппировать эти вершины частиц в один массив (предпочтительноVBO, чтобы вы могли более эффективно использовать потоковую передачу обновленных данных в графический процессор).Вы определенно можете повторить эффекты отдельного вращения, масштаба и т. Д. В вашем комбинированном массиве вершин, но вам нужно будет выполнить вычисления относительно того, где должны быть вершины, когда они повернуты, масштабированы и т. Д.некоторая нагрузка на процессор для каждого кадра, но это может быть немного скомпенсировано с помощью инфраструктуры Accelerate для выполнения некоторой векторной обработки этого.

Цвет и альфа-канал также могут быть предоставлены для каждой вершины в массиве,так что вы можете контролировать это для каждой из ваших частиц.

Однако я думаю, что вы правы в том, что OpenGL ES 2.0 может предоставить еще лучшее решение для этого, позволив вам написать специальную шейдерную программу.Вы можете отправлять статические вершины в VBO для всех ваших точек, тогда вам нужно будет только обновить матрицы, чтобы манипулировать каждой частицей и значениями альфа для каждой вершины частицы.Я делаю нечто подобное, чтобы генерировать процедурные самозванцы в качестве заменителей для сфер.Я описываю этот процесс здесь , и вы можете скачать исходный код приложения здесь .

...