OpenGL ES - Как Batch Render 500+ частиц с различными альфа, вращениями и масштабами?
Я разрабатываю игру для iOS, в которой нужно будет визуализировать 500-800 частиц за раз. Я узнал, что это хорошая идея для пакетной визуализации многих спрайтов в OpenGL ES вместо вызова glDrawArrays(..)
на каждом спрайте в игре, чтобы иметь возможность рендерить больше спрайтов без резкого снижения частоты кадров.
Мой вопрос: как мне сделать пакетную рендеринг 500+ частиц, которые имеют разные альфы, вращения и масштабы, но имеют один и тот же атлас текстуры? Акцент этого вопроса на различных альфа, вращений и масштабов для каждой частицы.
Я понимаю, что этот вопрос очень похож на Как нарисовать более 1000 частиц (с уникальным вращением, масштабом и альфа) в системе частиц iPhone OpenGL ES без замедления игры? однако этот вопрос не касается пакетного рендеринга. Прежде чем воспользоваться преимуществами объектов буфера вершин, я хочу разобраться в пакетном рендеринге в OpenGL ES с уникальными альфами, поворотами и масштабами (но с одинаковой текстурой). Поэтому, хотя я планирую в конечном итоге использовать VBO, сначала я хочу воспользоваться этим подходом.
Примеры кода будут высоко оценены, и если вы используете массив индексов, как это делают некоторые примеры, пожалуйста, объясните структуру и назначение массива индексов.
РЕДАКТИРОВАТЬ Я использую OpenGL ES 1.1.
РЕДАКТИРОВАТЬ Ниже приведен пример кода того, как я рендерил каждую частицу в сцене. Предположим, что они используют одну и ту же текстуру, и эта текстура уже связана в OpenGL ES 1.1 до выполнения этого кода.
- (void) render {
glPushMatrix();
glTranslatef(translation.x, translation.y, translation.z);
glRotatef(rotation.x, 1, 0, 0);
glRotatef(rotation.y, 0, 1, 0);
glRotatef(rotation.z, 0, 0, 1);
glScalef(scale.x, scale.y, scale.z);
// change alpha
glColor4f(1.0, 1.0, 1.0, alpha);
// glBindTexture(GL_TEXTURE_2D, texture[0]);
glVertexPointer(2, GL_FLOAT, 0, texturedQuad.vertices);
glEnableClientState(GL_VERTEX_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, texturedQuad.textureCoords);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glPopMatrix();
}
Кодовая альтернатива этому методу будет принята с благодарностью!
1 ответ
Одной из возможностей будет включение этих значений в массив атрибутов вершин - я думаю, что это лучший вариант. Если вы используете OpenGL ES 1.1 вместо 2.0, вы выбиты из этого метода. Массивы атрибутов вершин позволяют хранить значения в каждой вершине, в этом случае вы можете хранить альфы и повороты каждый в своем собственном массиве атрибутов и передавать их в шейдер с помощью glVertexAttribArray
, Затем шейдер выполняет преобразование вращения и обработку цвета с помощью альфа-канала.
Другим вариантом было бы сделать преобразование вращения на процессоре, а затем пакетировать частицы с аналогичными значениями альфа в несколько вызовов отрисовки. Эта версия потребует немного больше работы, и это не будет один вызов отрисовки, но все равно поможет оптимизировать, если шейдер не является опцией.
ПРИМЕЧАНИЕ. Вопрос, на который вы ссылаетесь, также рекомендует решение для массива.
РЕДАКТИРОВАТЬ: учитывая ваш код здесь OpenGL ES 1.0, вот решение с использованием glColorPointer
:
// allocate buffers to store an array of all particle data
verticesBuffer = ...
texCoordBuffer = ...
colorBuffer = ...
for (particle in allParticles)
{
// Create matrix from rotation
rotMatrix = matrix(particle.rotation.x, particle.rotation.y, particle.rotation.z)
// Transform particle by matrix
verticesBuffer[i] = particle.vertices * rotMatrix
// copy other data
texCoordBuffer[i] = particle.texCoords;
colorBuffer[i] = color(1.0, 1.0, 1.0, particle.alpha);
}
glVertexPointer(verticesBuffer, ...)
glTexCoordPointer(texCoodBuffer, ...)
glColorPointer(colorBuffer, ...)
glDrawArrays(particleCount * 4, ...);
Хорошая оптимизация для этого решения - совместное использование буферов для каждого рендера, чтобы вам не приходилось перераспределять их каждый кадр.