Задача - сделать объёмный свет, т.е. подсветку пространства вокруг источника света.
Пример (HL Alyx):


Само собой, рисовать здоровенные спрайты размером с половину экрана не вариант, филлрейта не хватит, еще и со смешиванием. Поскольку крупных источников света в кадре обычно немного, напрашивается решение во время отрисовки сцены вести луч к камере и измерять расстояние до каждого источника. Такое решение описано здесь: https://ijdykeman.github.io/graphics/simple_fog_shader
Работает прекрасно, мобильный процессор справляется с тремя-четырьмя источниками (обычно в кадре больше и нет, при повороте камеры можно аккуратно тушить ушедшие из поля зрения источники и зажигать новые). Но хочется иметь возможность придать освещенной части фигуру, отличную от круга, чтобы делать вот такие штуки:


Пробовал алгоритмически описать конус в шейдере - некрасиво и дорого, даже для одного источника.
Пока придумал следующее: в отдельном фреймбуфере, разрешением в несколько раз меньше основного, рисуем любую геометрию с размытыми краями. Затем при отрисовке сцены накладываем готовую текстуру с объёмным светом. Попробовал, работает, причём мобильный процессор справился даже с несколькими десятками спрайтов размером с половину экрана (в реальности во много раз меньше экрана, фреймбуфер-то маленький). Ступенек пикселей не видно, поскольку все края размытые.
Но в этом случае никак нельзя учесть глубину. Можно попробовать вписать её в один из каналов и проверять при смешивании, но если несколько объектов будут друг за другом, при этом дальний будет перекрыт геометрией, а ближний не будет - дальний просветит сквозь ближний.
Пока идея такая:
- 2-3 круглых источника делать первым способом;
- "фигурный свет" рисовать вторым способом, не допуская перекрытия (не более 1 источника в кадре), в один из каналов вписывать глубину для проверки на этапе смешивания;
- для источников, находящихся сильно далеко, просто рисовать маленький спрайт прямо на сцене.
Что думаете? Может, есть еще какая-нибудь известная техника? Или какой-ниибудь определенный термин, по которому погуглить решения?
Отмечу, что ищу дешёвые в плане производительности решения, всякие там реймарчинги не предлагать. Спасибо.
Скорее всего свет в пост процессинге делают.
Ещё пример с множеством перекрывающихся объёмов:

ronniko
Вопрос не в том, как это реализовано конкретно здесь, а в том, как это подешевле сделать и без постпроцессинга.
> https://otosection.com/volumetric-light-scattering-as-a-post-processing-effect/
Статью нейросеть что ли сгенерирована? Бессвязный набор слов.
romanshuvalov
> Но в этом случае никак нельзя учесть глубину
Может быть, надо рисовать всю геометрию, а не только свет.
iw4nna.rock
> Может быть, надо рисовать всю геометрию, а не только свет.
Нельзя: рендер идёт в фреймбуфер низкого разрешения, при отсечении по depth test я получу гребёнку из пикселей.
romanshuvalov
> при отсечении по depth test я получу гребёнку из пикселей
не понятно, что вы имели в виду.
Гребёнку наверно можно убрать размытием. Один фиг на ваших скринах всё в жутком блуме...
iw4nna.rock
> Гребёнку наверно можно убрать размытием.
Размытие нельзя, прямой рендер на экран, постпроцессинга нет.
Под гребёнкой я имею в виду, что граница отсечения будет низкого разрешения. На втором скриншоте левый источник скрыт геометрией. Вместо очертания камня при таком способе будет лесенка из пикселей низкого разрешения.
romanshuvalov
> Вместо очертания камня при таком способе будет лесенка из пикселей низкого
> разрешения
А, понятно.
Ну мне такое делать не приходилось, но если пришлось бы, то мне захотелось бы наверно нарисовать "объёмную" картинку с точками света, которые знают о своей глубине, можно маленькую, сильно размыть её, вычислить глубины в межточечном пространстве, можно даже на ЦПУ, а потом сверху добавить геометрию из камней, столбов, стен итп.
iw4nna.rock
> а потом сверху добавить геометрию из камней, столбов, стен итп.
Так часть геометрии позади, часть впереди. А источников несколько, и геометрия может быть между ними.
Интересная тематика. Как такой вариант? Восстанавливаем depth из depth буфера, знаем параметры источника, считаем длину освещенной части (суммарную плотность частиц по лучу от камеры до мирового положения пикселя в волюме), умножаем на свойства частицы.
Суммарную плотность считаем либо какой-то формулой, либо шагами по лучу в интервале от ближней части волюма источника до мирового положения пикселя.
romanshuvalov
Что думаете? Может, есть еще какая-нибудь известная техника? Или какой-ниибудь определенный термин, по которому погуглить решения?
Блюм на объектах с эмиссией на мобильных картах не работает? Или вас не устраивает произодительность?
По-моему на примерах одни и те же подходы, ну плюс волюметрикс ещё. Вы альтернативу ищите?
romanshuvalov
> Само собой, рисовать здоровенные спрайты размером с половину экрана не вариант
Это почему вдруг? Есть тесты?
Ну и вообше, зачем на телефоне всё это.
Там должго быть всё плоское, контрастное и с контурами.
Не знаю, насколько применимо в контексте современного графония, но в старых играх была кое-где такая реализация — интеграл по волюметрикам считался отдельным проходом для вертексов, а у фрагментов это значение уже только интерполировалось. Хм, сейчас думаю, а ведь на хай-поли, наоборот, должно работать только лучше. Так что предлагаю реально попробовать сделать так:
—> считай "некрасивые дорогие конусы" как есть, но не во фрагментном шейдере, а в повершинном (заграждения от геометрии на этой стадии можно игнорировать, я думаю),
—> во фрагментном, просто делай добавление/интерполяцию (как там этот фог у тебя работает) от последнего шага формулы для фога.
Что-то типа:
void vertex_shader() { your_normal_vertex_shader_shit( ...); [var_fog_power, var_fog_coverage] = integrate_fog( uni_camera_pos, attr_vertex_pos); } void fragment_shader( ) { float3 surface_color = calc_surface_color_like_usual( ...); final_color = surface_color * ( 1 - var_fog_coverage) + var_fog_power; }
betauser
Это просто более сложная вариация на первый вариант, визуально слабо отличающаяся, но имеющая те же проблемы.
MSA2
> Блюм на объектах с эмиссией на мобильных картах не работает?
Посмотрите на четвертый скриншот, о каком блюме речь?
Der FlugSimulator
> Это почему вдруг? Есть тесты?
Да. Если на Oculus Quest 2 отрисовать сцену, а затем еще раз поверх всего фреймбуфера нарисовать полупрозрачный квад - проиводительность упадёт ниже приемлимого уровня. На ПК-видеокартах такой проблемы нет, но мобильные чипы имеют низкий филлрейт. Поэтому я всё рисую в один проход.
> зачем на телефоне всё это.
Не на телефоне, на VR-устройстве с Qualcomm Snapdragon XR2 и разрешением 1440х1560 в каждый глаз.
Имбирная Ведьмочка
Допустим, мы имеем плоскую стену (один квад) и перед ней висящий фонарь, как на третьем скриншоте. Каким образом расчёт четырёх точек квада поможет нарисовать конус?
Тема в архиве.