C # XNA 2D оптимизация эффекта следа - PullRequest
3 голосов
/ 29 марта 2012

В настоящее время в качестве эффекта следа в моей игре на каждые 5 кадров добавляется полупрозрачная копия текстуры спрайта в список <> следов.

Альфа-значения этих трасс уменьшаются в каждом кадре, а функция draw выполняет итерацию по списку и рисует каждую текстуру. Как только они достигают 0 альфа, они удаляются из списка <>.

Результатом является небольшой эффект следа за движущимися объектами. Проблема примерно для 100+ объектов, частота кадров начинает резко падать.

Все текстуры следа взяты из одного листа спрайта, поэтому я не думаю, что это проблема пакетной обработки. Я профилировал код, и интенсивность ЦП во время всплесков падения FPS ниже, чем при нормальном FPS, поэтому я предполагаю, что это означает ограничение GPU?

Есть ли способ добиться этого эффекта более эффективно?

Вот общий код, который я использую:

// fade alpha
m_alpha -= (int)(gameTime.ElapsedGameTime.TotalMilliseconds / 10.0f);

// draw
if (m_alpha > 0) {
    // p is used to alter RGB of the trails color (m_tint) depending on alpha value
    float p = (float)m_alpha/255.0f;
    Color blend = new Color((int)(m_tint.R*p), (int)(m_tint.G*p), (int)(m_tint.B*p), m_alpha);               
    // draw texture to sprite batch
    Globals.spriteBatch.Draw(m_texture, getOrigin(), m_rectangle, blend, getAngle(), new Vector2(m_rectangle.Width/2, m_rectangle.Height/2), m_scale, SpriteEffects.None, 0.0f);                
} else {
        // flag to remove from List<>
        m_isDone = true;               
}

Полагаю, я должен заметить, что m_texture, данный классу trail, является ссылкой на глобальную текстуру, разделяемую всеми трейлами. Я отмечаю, что создаю печатную копию для каждого следа.

РЕДАКТИРОВАТЬ: Если я просто закомментирую вызов SpriteBatch.Draw, даже когда я выделяю новый трейл каждый кадр для сотен объектов, нет пропуска кадров ... должен быть лучший способ сделать это .

1 Ответ

3 голосов
/ 29 марта 2012

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

Этот метод ОЧЕНЬ эффективен и используется в знаменитой заставке Flurry (www.youtube.com/watch?v=pKPEivA8x4g).

Чтобы увеличить длину трасс, простоувеличьте прозрачность прямоугольника, который вы используете для очистки экрана.В противном случае вы сделаете его более непрозрачным, чтобы сделать след короче.Однако обратите внимание, что если вы сделаете следы слишком длинными, сделав прямоугольник слишком прозрачным, вы рискуете оставить некоторые легкие следы следа, которые из-за альфа-смешивания могут не полностью стереться даже после долгого времени.Заставка Flurry страдает от такого рода артефактов, но есть способы компенсировать это.

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

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

С другой стороны, я думаю, что узким местом в вашем коде является следующая строка:

Globals.spriteBatch.Draw(m_texture, getOrigin(), m_rectangle, blend, getAngle(), new Vector2(m_rectangle.Width/2, m_rectangle.Height/2), m_scale, SpriteEffects.None, 0.0f);   

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

...