обновлять скорости и положение системы частиц путем рендеринга четырехугольника

Реализация системы частиц на основе графического процессора с использованием алгоритма, описанного в этой статье: http://www.gamasutra.com/view/feature/130535/building_a_millionparticle_system.php?print=1

Я не могу понять двух вещей:

  1. Зачем использовать стек или кучу для хранения доступного индекса частицы? Если частица умерла в момент времени t, то она начнет свою жизнь с нуля в момент времени t + 1. Есть параметр N для управления количеством частиц на экране. Если я могу повторно использовать все частицы, зачем мне нужен индекс доступных частиц и даже использовать кучу для их хранения?
  2. Чтобы обновить скорости и положение, он сказал: «Фактическое моделирование реализовано во фрагментном шейдере. Шейдер выполняется для каждого пикселя цели рендеринга путем рендеринга квадрата размером с экран ...» Если я хочу, чтобы частицы были нарисованные в виде точек, мне нужно изменить четырехугольник на точки? Почему четырехугольник? Как его можно рисовать за очки?

.


person NUO    schedule 27.11.2016    source источник
comment
BTW: Только что дочитали: »Частицы можно визуализировать как точечные спрайты, треугольники или четырехугольники [...]. Если должно быть создано несколько вершин для каждой частицы, концепция [...] требует ручного копирования положения частицы перед рендерингом. На следующем этапе рендеринга позиции необходимо три или четыре раза рендерить в пиксели, расположенные рядом друг с другом в текстуре. [...] «и» По причинам, указанным в предыдущем разделе, и для уменьшения нагрузки на вершинный блок, частицы в настоящее время визуализируются как точечные спрайты. «   -  person Bodo Thiesen    schedule 28.11.2016


Ответы (1)


  1. Термин «частица мертва» - это термин, который описывает только семантическую мертвую часть частицы. С точки зрения графического процессора, все частицы постоянно находятся в реальном времени, и все частицы будут вычисляться в каждом кадре. (Или хотя бы частицы от 0 до N будут обрабатываться, но даже мертвые).

    Как только ЦП «обнаруживает», что частица мертва (например, ее возраст составляет 5 секунд или около того), необходимо запомнить индекс для этой частицы, чтобы новые частицы могли повторно использовать этот индекс. Это можно сделать разными способами, два очевидных способа - стопки или кучи.

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

  2. Алгоритм использует фрагментный шейдер для вычисления скорости. Он считывает данные из одной текстуры (которая содержит координаты x / y / z вместо информации о цвете r / g / b) и записывает данные в другую текстуру (которая также содержит координаты x / y / z вместо информации о цвете r / g / b. ), использует сопоставление 1: 1 между исходной и целевой текстурой и отображает всю исходную текстуру в целевую текстуру. Это не имеет ничего общего с реальными частицами, которые будут визуализированы позже на шаге 6. Render Particles.

    Или другими словами: «четырехугольник размером с экран» здесь на самом деле неправильный термин, он должен читаться как «четырехугольник с размером текстуры», потому что в этот момент на экране ничего не отображается. Целевая текстура (т.е. текстура, которая будет содержать новую информацию о положении) ЯВЛЯЕТСЯ экраном.

/ отредактировать еще раз:

Хорошо, можно перефразировать документ:

У вас есть struct:

struct color {
    float r, g, b;
};

и несколько #defines:

#define vector color
#define x r
#define y g
#define z b

И у вас есть несколько массивов для ваших частиц:

#define NP 1024 * 1024
struct vector particle_pos[2][NP];
struct vector particle_vel[2][NP];
uint32_t particle_birth_tick[NP];

// Double buffering - gonne have to remember, where
// we read from and where we write to:
struct vector * particle_pos_r = particle_pos[0];
struct vector * particle_pos_w = particle_pos[1];
struct vector * particle_vel_r = particle_vel[0];
struct vector * particle_vel_w = particle_vel[1];

В настоящее время:

  1. Процесс Рождения и Смерти
#define TTL 5 * 25 // 5 seconds * 25 simulation steps per second.
for (size_t i = 0; i < NP; ++i) {
    if (particle_birth_tick[i] + TTL == current_tick) {
        particle_pos_r[i].x = somewhere behind viewer;
        particle_pos_r[i].y = somewhere behind viewer;
        particle_pos_r[i].z = somewhere behind viewer;
        particle_vel_r[i].x = 0;
        particle_vel_r[i].y = 0;
        particle_vel_r[i].z = 0;
        free_list.add(i);
    }
}
void add_particle(struct vector p, struct vector v) {
    size_t i = free_list.pop_any();
    particle_pos_r[i] = p;
    particle_vel_r[i] = v;
}
  1. Обновить скорости
for (size_t i = 0; i < 1024 * 1024; ++i) {
    particle_vel_w[i].x = do_calculations(particle_vel_r[i].x)
    particle_vel_w[i].y = do_calculations(particle_vel_r[i].y)
    particle_vel_w[i].z = do_calculations(particle_vel_r[i].z)
}
swap(particle_vel_r, particle_vel_w);
  1. Обновить позиции
for (size_t i = 0; i < 1024 * 1024; ++i) {
    particle_pos_w[i].x = particle_pos_r[i].x + particle_vel_r[i].x;
    particle_pos_w[i].y = particle_pos_r[i].y + particle_vel_r[i].y;
    particle_pos_w[i].z = particle_pos_r[i].z + particle_vel_r[i].z;
}
swap(particle_pos_r, particle_pos_w);
  1. Сортировка по альфа-смешиванию
sort a bit...
  1. Передача данных текстуры в данные вершины
copy the pos texture into a vbo
  1. Визуализировать частицы
actually draw particles

Интересный момент здесь заключается в том, что шаги 2–5 выполняются исключительно на графическом процессоре (шаг 1 выполняется как на графическом процессоре, так и на процессоре). Отсюда и термин «рендеринг». Потому что эти циклы в 2 и 3 просто «визуализируют» «текстуру» particle_vel_r и / или particle_pos_r в «буфер кадра» particle_vel_w или particle_pos_w, полностью заполняя буфер кадра «квадратик размером с экран» исходной текстурой.

person Bodo Thiesen    schedule 27.11.2016
comment
Что касается вопроса 1, означает ли это, что мы сначала создаем самую большую текстуру (например, 1024 * 1024), если мы хотим, чтобы на экране отображалось только 100 частиц в кадре, мы просто манипулируем кучей размером 100, вставляем их индексы и обновляем только те 100 атрибутов частиц в текстуре 1024 * 1024. - person NUO; 28.11.2016
comment
Что касается вопроса 2, я могу понять, что текстура позиции используется в качестве входных данных для фрагментного шейдера, потому что текстура позиции содержит всю информацию о положении частицы. Я не мог понять, почему рендеринг четырехугольника размером с экран может производить вычисления! Все ли частицы появляются на экране после рендеринга четырехугольников? Как фрагментный шейдер узнает, что я хочу рисовать частицы как точки или как рекламные щиты? - person NUO; 28.11.2016
comment
Q2: См. Отредактированный ответ. Q1: Я не совсем понимаю, что вы имеете в виду. Но я думаю, ты прямо сейчас. Либо вы можете заставить графический процессор обрабатывать всю текстуру размером 1k * 1k с самого начала, либо вы можете обрабатывать только ее части - например, первые 5 строк, потому что все живые частицы помещаются в них. - person Bodo Thiesen; 28.11.2016
comment
Q2: Render означает рисование на экране, верно? Буфер фрагмента принимает положение частиц (x, y, z) в качестве входных данных, а затем рисует четырехугольник. Зачем вы рисуете позиции на экране? Я имею в виду, что обычно мы рисуем точки с помощью glBegin (GL_POINTS), а затем указываем их положения. Как графический процессор при рендеринге четырехугольника узнает, что вы рендерируете точки? Что, если я хочу визуализировать каждую частицу как рекламный щит? - person NUO; 28.11.2016
comment
Опять же: они неправильно используют графический процессор для математических вычислений. Графический процессор может считывать данные из текстур (обычно данные цвета) и записывать данные в текстуры (опять же, обычно данные цвета). Но здесь, как я уже сказал, они неправильно используют GPU для вычислений. Таким образом, вместо чтения данных о цвете они считывают координаты xyz, вычисляют их и записывают в новую текстуру. Этот процесс также называется рендерингом, потому что это те же операции, что и перемещение цветовых данных. Имейте в виду: до шага 6 в этом документе ничего не происходит с буфером кадра, который фактически содержит изображение, видимое пользователю. - person Bodo Thiesen; 28.11.2016