Отложенная заливка и цвет фона
Я реализовал упрощенное отложенное затенение (я не вычисляю границы для точечных источников света), где после заполнения g-буфера я просто использую полноэкранный квад для вычисления освещения. Я использую смешивание ( glBlendFunc(GL_ONE, GL_ONE)) во время второго этапа для обработки нескольких источников света. Тогда значения rgb в glClearColor должны быть установлены в 0 для правильных результатов. При заполнении g-буфера glClearColor может быть любого цвета (некоторые цвета могут изменять только цвет фона в конечном изображении). Теперь мне интересно, как мне установить цвет фона на конечном изображении. Один из способов сделать это - использовать glClearColor(0,0,0) во время заполнения g-буфера, а затем использовать следующий оператор if в фрагментном шейдере:
if((normal.x == 0.0) && (normal.y == 0.0) && (normal.z == 0.0))
{
fragColor = vec4(1, 0, 0, 1); // here we can set a background color
}
else
{
fragColor = computeLighting(worldPos, normal, diffM, specM, specMS);
}
Работает нормально, но оператор if может привести к некоторому снижению производительности. Это единственный способ установить цвет фона?
1 ответ
Не уверен, что понимаю, в чем проблема, но вот некоторые мысли с большим количеством предположений.
Вы думаете о том, чтобы сделать что-то подобное?:
- Очистите диффузное вложение в вашем gbuffer с цветом фона, который вы хотите (как бы то ни было... вы не хотите очищать другие текстуры с этим значением, например, от нормалей!)
- После заполнения вашего буфера все, что не покрыто вашей геометрией, все равно должно иметь цвет фона (в вашем диффузном вложении)
- Если нормаль не определена для фрагмента, вы вручную пишете жестко закодированный цвет на последнем этапе.
Я предполагаю, что ваш рендерер делает следующее:
- Заполните gbuffer (рассеянный, нормальный, глубина и т. Д. В FBO с несколькими вложениями)
- Для каждого источника света вы визуализируете четырехэкранное смешивание добавок с отдельным FBO (буфером накопления света).
- Затем, наконец, вы объединяете диффузное вложение в вашем буфере с буфером накопления света, чтобы отобразить конечный результат на вашем экране.
Нет никаких причин, по которым ваш шейдер должен отвечать за написание такого цвета фона. Я также на самом деле визуализирую то, что находится в фоновом режиме, и всегда очищаю gbuffer с 0 значениями. Я думаю, что вещи могут пойти не так, когда вы комбинируете рассеянное и светлое на последнем этапе, так что может быть проще перейти на трафаретный подход, описанный ниже. Лично я сохраняю индекс материала в альфа-канале диффузного цвета, затем загружаю все свойства материала в текстуру.
В моих материалах у меня есть два скаляра (и больше...):
- AmbientWeight
- облегченный
При объединении диффузного буфера и светового буфера (значительно упрощено):
FinalColor = Diffuse * AmbientWeight + Diffuse * Light * LightWeight
Если в качестве фона используется материал 0 с AmbientWeight = 1 и LightWeight = 0, FinalColor всегда будет исходным значением в диффузном буфере.
Многие простые отложенные рендеры просто вычисляют конечный результат следующим образом:
FinalColor = Diffuse * Light
(Фрагмент из диффузного буфера * фрагмент из светового буфера)
В вашем случае это, конечно, приведет к исчезновению цвета фона, так как эти фрагменты никогда не будут подсвечены. (Diffuse * 0
всегда результат) Вы можете использовать альфа-канал в диффузном буфере в качестве AmbientWeight для некоторых быстрых результатов.
FinalColor = Diffuse * Diffuse.a + Diffuse * Light
Когда дело доходит до производительности:
Это действительно сложно предсказать. Пропуск окончательных легких вычислений в шейдере может дать вам кое-что, но вы уже сделали все чтения и распаковку gbuffer до того, как дойдете до этой стадии. Независимо от того, что возвращает шейдер, вы в конечном итоге воздействуете на весь световой буфер с помощью операции смешивания, и вы читаете весь gbuffer за свет. Проверка того, что все компоненты в обычном буфере равны 0, сработает только для областей без геометрии. При использовании полноэкранного четырехугольника на свет у вас будет довольно много узких мест.
Начните с чтения буфера положения (или восстановления положения из буфера глубины), затем определите, не может ли ваш точечный источник света добраться до фрагмента, и отбросьте его, прежде чем что-либо сделать, может немного помочь. Для небольших источников света вы не будете читать все, начиная с gbuffer за фрагмент. Это действительно зависит от того, насколько толстый ваш gbuffer, что вы визуализируете, насколько велики ваши источники света и сколько источников света вы визуализируете.
Динамическое ветвление также может снизить производительность, но иногда может быть "меньшим злом". Я избегаю этого в максимально возможной степени.
Дополнительно:
Когда дело доходит до "цвета фона", я лично использую буфер трафарета, чтобы заполнить фон скайбоксом или чем-то подобным. Создайте маску трафарета при записи диффузного буфера, когда визуализируете фон с обратной маской, чтобы затрагивать только фрагменты фона (без проверки глубины или глубины записи). Если бы вся моя сцена была покрыта геометрией, не было бы написанных фрагментов. Это предполагает, что вы записываете конечный результат в 3-й FBO, который использует то же самое вложение глубины, что и ваш gbuffer. (Буфер Depth24 + Stencil8)
Вместо того, чтобы рисовать каждый источник света с помощью полноэкранного четырехугольника (со смешиванием), вы также можете отправлять массивы, используя UBO с информацией о свете. Затем нарисуйте весь точечный свет одним полноэкранным квадом. В итоге вы выполняете одинаковое количество легких вычислений, но количество операций чтения всегда остается постоянным. (UBO все еще имеют ограничение по размеру, хотя)
Возможно, вы также найдете интересную мозаичную задержку затенения в качестве потенциального следующего шага: http://www.cse.chalmers.se/~olaolss/main_frame.php?contents=publication&id=tiled_shading(вы читаете из gbuffer только один раз и пишете только один фрагмент для светового прохода)
Документ: http://www.cse.chalmers.se/~uffe/tiled_shading_preprint.pdf