XNA-создание большого количества частиц одновременно

время для другого вопроса XNA. На этот раз это чисто с точки зрения технического дизайна.

моя ситуация такая: Я создал движок частиц на основе GPU-вычислений, далеко не полный, но он работает. Мой GPU легко обрабатывает частицы 10k, не потея, и я не удивлюсь, если смогу добавить еще кучу.

моя проблема: всякий раз, когда у меня есть много частиц, созданных в то же время, моя частота кадров ненавидит мне. Почему? Много использования процессора, хотя я минимизировал его, чтобы содержать почти только операции с памятью.

создание частиц по-прежнему выполняется CPU-вызовами, такими как:

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

когда у меня есть около 4 излучателей, создающих одну частицу на кадр, мой FPS понижается (конечно, только 4 кадра в секунду, но 15 излучателей снижает мой FPS до 25).

создание частиц:

        //### As you can see, not a lot of action here. ###
        ParticleVertex []tmpVertices = ParticleQuad.Vertices(Position,Velocity,this.TimeAlive);
        particleVertices[i] = tmpVertices[0];
        particleVertices[i + 1] = tmpVertices[1];
        particleVertices[i + 2] = tmpVertices[2];
        particleVertices[i + 3] = tmpVertices[3];
        particleVertices[i + 4] = tmpVertices[4];
        particleVertices[i + 5] = tmpVertices[5];

        particleVertexBuffer.SetData(particleVertices);

Я думаю, что, возможно, я не должен создавать частицы так часто, возможно, есть способ позволить GPU создавать все, или, может быть, я просто не знаю, как вы это делаете. ;)

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

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

1 ответов


нет никакого способа, чтобы GPU создавал все (кроме использования Геометрические Шейдеры что требует SM4.0).

если бы я создавал систему частиц для максимальной эффективности процессора, я бы создать (просто чтобы выбрать число для примера) 100 частиц в буфере вершин и индексов, как это:

  • сделайте буфер вершин, содержащий квадроциклы (четыре вершины на частицу, а не шесть, как у вас)
  • использовать пользовательские формат вершин, который может хранить значение "смещение по времени", а также Значение" начальная скорость " (аналогично образец частицы 3D XNA)
  • установите значение времени таким образом, чтобы каждая частица имела смещение по времени на 1/100 меньше, чем последняя (поэтому смещения варьируются от 1,0 до 0,01 через буфер).
  • установить начальную скорость случайным образом.
  • используйте буфер индекса, который дает вам два треугольника, которые вам нужны, используя четыре вершины для каждого крупица.

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

тогда у меня будет вершинный шейдер, который будет принимать следующие входные данные:

  • Per-Vertex:
    • смещение по времени
    • начальный скорость
  • Шейдер Параметры:
    • настоящее время
    • время жизни частиц (которое также является значением времени обертывания частиц и долей частиц в используемом буфере)
    • положение/вращение/масштаб системы частиц (мировая матрица)
    • любые другие интересные входы, которые вам нравятся, такие как: размер частиц, гравитация, ветер и т. д.
    • шкала времени (чтобы получить реальное время, поэтому скорость и другие физические расчеты имеют смысл)

что вершинный шейдер (опять же, как образец частицы 3D XNA) может затем определить положение вершины частицы на основе ее начальной скорости и времени, которое эта частица была в моделировании.

времени для каждой частицы будет (псевдо код):

time = (currentTime + timeOffset) % particleLifetime;

другими словами, с течением времени частицы будут высвобождаться при постоянной ставка (за счет смещения). И всякий раз, когда частица умирает в time = particleLifetime (или это в 1.0? модуль с плавающей запятой сбивает с толку), петли времени назад к time = 0.0 Так что частица снова входит в анимацию.

затем, когда пришло время рисовать мои частицы, я бы установил свои буферы, шейдер и параметры шейдера и позвонил DrawIndexedPrimitives. Теперь вот умный бит: я бы установил startIndex и primitiveCount такой, что ни одна частица не начинается в середине анимации. Когда сначала я нарисую 1 частицу (2 примитива), и к тому времени, когда эта частица умрет, я нарисую все 100 частиц, 100-я из которых только начнется.

затем, мгновение спустя, таймер 1-й частицы сделает петлю вокруг и сделает ее 101-й частицей.

(если бы я хотел только 50 частиц в моей системе, я бы просто установил время жизни частиц на 0,5 и только когда-либо рисовал первые 50 из 100 частиц в вершине / индексе буфер.)

и когда пришло время отключить систему частиц-просто сделайте то же самое в обратном направлении - установите startIndex и primitiveCount такие, что частицы перестают быть нарисованными после того, как они умирают.

основной принцип для понимания заключается в том, что вы рассматриваете свой буфер вершин/индексов как круговой буфер взвешенные частицы.

один недостаток кругового буфера заключается в том, что, когда вы перестаете испускать частицы, если вы не остановитесь, когда текущее время кратно времени жизни частицы, вы получите активный набор частиц, охватывающих концы буфера с зазором посередине, что требует двух вызовов рисования (немного медленнее). Чтобы избежать этого, вы можете подождать, пока не наступит время перед остановкой - для большинства систем это должно быть нормально, но может выглядеть странно для некоторых (например: a "медленная" система частиц, которая должна немедленно остановиться).

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

все, что было сказано: Если возможно, возможно, стоит использовать существующую библиотеку частиц.