Подтвердить что ты не робот

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

Итак, я делаю вещи с 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, что, конечно, неприемлемо. Мне интересно, есть ли более эффективный способ сделать это. Учитывая, что у меня есть только одна текстура, я считал, что могу объединить эффекты в один файл и выполнить несколько проходов без захвата текстуры назад. Я не уверен, что это возможно.

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

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

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

EDIT: теперь я понимаю, что OP выполняет полноэкранные эффекты, а не рендер сцены.