Эффективное объединение нескольких пиксельных шейдеров

Итак, я делаю что-то с XNA 3.1, и у меня есть много отдельных эффектов, которые применяются через пиксельные шейдеры. Они приходят из разных источников, таких как специальные атаки, окружение и т. Д. У меня проблема в том, что я заметил значительное снижение частоты кадров.

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

foreach(KeyValuePair<Ref<int>,Effect> p in renderEffects)
{
    Effect r = p.Value;
    g.SetRenderTarget(0, MainGame.MainRenderTarget);
    //Change RenderTarget to allow code to grab existing texture in the same draw area.
    levelDraw = MainGame.LevelRenderTarget.GetTexture();
    //Change back to draw back to this texture, allowing render effects to be layered.
    g.SetRenderTarget(0, MainGame.LevelRenderTarget);

    MainGame.StartDraw(MainGame.GameBatch);
    //Starts the sprite batch and sets some parameters
    r.Begin();
    r.CurrentTechnique.Passes[0].Begin();
    MainGame.GameBatch.Draw(levelDraw, new Rectangle(0, 0, levelDraw.Width, levelDraw.Height), Color.White);
    r.CurrentTechnique.Passes[0].End();
    r.End();
    MainGame.GameBatch.End();
}

Теперь это дает заметные потери кадров при наложении всего 3 эффектов, а при применении 10 - с 60FPS до 16FPS, что, конечно, недопустимо. Мне интересно, есть ли более эффективный способ сделать это. Учитывая, что у меня есть только одна текстура, я решил, что смогу объединить эффекты в один файл и выполнить несколько проходов, не возвращая текстуру обратно. Однако я не уверен, возможно ли это.

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

2 ответа

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

Возможно, вы захотите взглянуть на статью Шона Харгривса о фрагментах шейдеров в HLSL и код Тима Джонса, чтобы сделать это в XNA

Вы полностью закрашиваете все, что рисуете? Если ваши шейдеры требуют значительных вычислительных ресурсов, вы должны сначала выполнить "проход глубины", только ztesting/ запись в Z-буфер (записи в цветной буфер отключены). Также используйте тривиально простой шейдер, чтобы "заполнить глубину" экрана.

Другими словами, визуализируйте все непрозрачные объекты, обновляя только буфер глубины на первом проходе.

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

РЕДАКТИРОВАТЬ: теперь я понимаю, что OP делает полноэкранные эффекты, а не рендеринг сцены.

Другие вопросы по тегам