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

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

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

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

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

Решение

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

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

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

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

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

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

Другие вопросы по тегам