2D Particle System - Производительность - PullRequest
2 голосов
/ 23 сентября 2011

Я реализовал 2D систему частиц, основанную на идеях и концепциях, изложенных в «Создание усовершенствованной системы частиц» (Джон ван дер Бург, журнал Game Developer, март 2000 г.) .

Теперь мне интересно, какую производительность мне следует ожидать от этой системы. В настоящее время я тестирую его в контексте моего простого (незаконченного) платформера SDL / OpenGL, где все частицы обновляются в каждом кадре. Рисунок сделан следующим образом

// Bind Texture
glBindTexture(GL_TEXTURE_2D, *texture);
// for all particles
    glBegin(GL_QUADS);
    glTexCoord2d(0,0);  glVertex2f(x,y);
    glTexCoord2d(1,0);  glVertex2f(x+w,y);
    glTexCoord2d(1,1);  glVertex2f(x+w,y+h);
    glTexCoord2d(0,1);  glVertex2f(x,y+h);
    glEnd();   

, где одна текстура используется для всех частиц.

Он работает до 3000 частиц. Честно говоря, я ожидал намного большего, особенно потому, что он предназначен для использования с несколькими системами на экране. Какое количество частиц мне следует ожидать, чтобы они отображались плавно?

PS: я относительно новичок в C ++ и OpenGL, так что вполне возможно, что я где-то напутал!?

РЕДАКТИРОВАТЬ Использование POINT_SPRITE

glEnable(GL_POINT_SPRITE);
glBindTexture(GL_TEXTURE_2D, *texture);
glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE); 

// for all particles
    glBegin(GL_POINTS);
    glPointSize(size);
    glVertex2f(x,y);
    glEnd();

glDisable( GL_POINT_SPRITE );

Не вижу никакой разницы в производительности при использовании GL_QUADS вообще!?

РЕДАКТИРОВАТЬ Использование VERTEX_ARRAY

// Setup
glEnable (GL_POINT_SPRITE);                                         
glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE);              
glPointSize(20);                                    

// A big array to hold all the points
const int NumPoints = 2000;
Vector2 ArrayOfPoints[NumPoints];
for (int i = 0; i < NumPoints; i++) {
    ArrayOfPoints[i].x = 350 + rand()%201;
    ArrayOfPoints[i].y = 350 + rand()%201;
}

// Rendering
glEnableClientState(GL_VERTEX_ARRAY);     // Enable vertex arrays
glVertexPointer(2, GL_FLOAT, 0, ArrayOfPoints);     // Specify data
glDrawArrays(GL_POINTS, 0, NumPoints);  // ddraw with points, starting from the 0'th point in my array and draw exactly NumPoints

Использование виртуальных машин изменило производительность по сравнению с вышеописанным. Затем я попробовал VBO, но не вижу там разницы в производительности?

Ответы [ 2 ]

4 голосов
/ 23 сентября 2011

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

Во-первых, используя glBegin () и glEnd (), вы используете немедленный режим, который, насколько я знаю, самый медленный способ выполнения задач. Более того, в текущем стандарте OpenGL его даже нет.

Для OpenGL 2.1

Точечные спрайты:

Возможно, вы захотите использовать точечные спрайты. Я реализовал систему частиц, используя их, и придумал хорошую производительность (по крайней мере, для моих знаний тогда). Используя точечные спрайты, вы делаете меньше вызовов OpenGL за кадр и отправляете меньше данных на графическую карту (или даже храните данные на графической карте, не будучи уверенными в этом). Короткий поиск в Google должен даже дать вам несколько реализаций этого взгляда.

Вершинные массивы:

Если использование точечных спрайтов не помогает, вам следует рассмотреть возможность использования массивов вершин в сочетании с точечными спрайтами (чтобы сэкономить немного памяти). По сути, вы должны хранить данные вершин частиц в массиве. Затем вы включаете поддержку массива вершин, вызывая glEnableClientState () с GL_VERTEX_ARRAY в качестве параметра. После этого вы вызываете glVertexPointer () (параметры описаны в документации OpenGL) и вызываете glDrawArrays () для рисования частиц. Это уменьшит количество вызовов OpenGL только до 3000 вместо одного вызова на кадр.

Для OpenGL 3.3 и выше

Instancing:

Если вы программируете под OpenGL 3.3 или выше, вы можете даже рассмотреть возможность использования инстансинга для рисования ваших частиц, что должно ускорить это еще больше. Опять же, короткий поиск в Google позволит вам взглянуть на некоторый код об этом.

В целом:

Использование SSE:

Кроме того, некоторое время может быть потеряно при обновлении ваших позиций вершин. Итак, если вы хотите ускорить это, вы можете взглянуть на использование SSE для их обновления. Если все сделано правильно, вы получите большую производительность (по крайней мере, при большом количестве частиц)

Структура данных:

Наконец, недавно я нашел ссылку ( divergentcoder.com / Программирование / AOS-SOA-Explorations-Part-1 , спасибо Бен) о структурах массивов (SoA) и массивов структур (AoS) , Они сравнивались по тому, как они влияют на производительность, на примере системы частиц.

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

Рассмотрите возможность использования массивов вершин вместо непосредственного режима (glBegin / End): http://www.songho.ca/opengl/gl_vertexarray.html

Если вы хотите попасть в шейдеры, вы также можете найти «вершинный шейдер» и рассмотреть возможность использования этого подхода в вашем проекте.

...