Термин «частица мертва» - это термин, который описывает только семантическую мертвую часть частицы. С точки зрения графического процессора, все частицы постоянно находятся в реальном времени, и все частицы будут вычисляться в каждом кадре. (Или хотя бы частицы от 0 до N будут обрабатываться, но даже мертвые).
Как только ЦП «обнаруживает», что частица мертва (например, ее возраст составляет 5 секунд или около того), необходимо запомнить индекс для этой частицы, чтобы новые частицы могли повторно использовать этот индекс. Это можно сделать разными способами, два очевидных способа - стопки или кучи.
Специальная структура данных для хранения индексов мертвых частиц необходима только в том случае, если максимальные возрасты частиц различаются. Если они не отличаются, вы можете просто реализовать кольцевой буфер. Но в большинстве случаев вы будете использовать этот движок частиц для всех видов частиц, и у них может быть переменное время существования значений. Тогда вам понадобятся эти структуры данных.
Алгоритм использует фрагментный шейдер для вычисления скорости. Он считывает данные из одной текстуры (которая содержит координаты x / y / z вместо информации о цвете r / g / b) и записывает данные в другую текстуру (которая также содержит координаты x / y / z вместо информации о цвете r / g / b. ), использует сопоставление 1: 1 между исходной и целевой текстурой и отображает всю исходную текстуру в целевую текстуру. Это не имеет ничего общего с реальными частицами, которые будут визуализированы позже на шаге 6. Render Particles
.
Или другими словами: «четырехугольник размером с экран» здесь на самом деле неправильный термин, он должен читаться как «четырехугольник с размером текстуры», потому что в этот момент на экране ничего не отображается. Целевая текстура (т.е. текстура, которая будет содержать новую информацию о положении) ЯВЛЯЕТСЯ экраном.
/ отредактировать еще раз:
Хорошо, можно перефразировать документ:
У вас есть struct
:
struct color {
float r, g, b;
};
и несколько #define
s:
#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];
В настоящее время:
- Процесс Рождения и Смерти
#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;
}
- Обновить скорости
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);
- Обновить позиции
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);
- Сортировка по альфа-смешиванию
sort a bit...
- Передача данных текстуры в данные вершины
copy the pos texture into a vbo
- Визуализировать частицы
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