Комментарии 15
Во-вторых, не для каждого источника света подойдёт сферическая область. Есть же и другие типы источников света, кроме точечных. Или может быть достоверно известно, что сцена отсекает часть освещаемого объёма, и в этом случае можно освещённый объём принять за куб, например. Тогда придётся писать свой набор абстракций для предварительной проверки возможности источника света осветить конкретную координату.
В-третьих, объект, который освещаем, тоже может быть разной формы, и нужно учитывать и его форму и размеры в том числе. Если pivot персонажа (который может быть как центром тяжести, так и точкой под ногами) не освещён, это ещё не значит, что весь персонаж в тени.
Если «ловить освещение» со сцены (не важно, подхватывать из отрисованного кадра, или из отдельного Render to texture), то можно отхватить неожиданных багов. Например, берём пиксел со спины персонажа (камера находится за спиной персонажа), он тёмный — считаем, что персонаж в темноте. А на самом деле у персонажа там тёмный рюкзак. Или персонаж в светлом, но между ним и камерой чёрный столб. Или персонаж стоит лицом к источнику света и спина у него тёмная; но при этом всё равно неправильно считать, что персонаж спрятался в тени. Спереди его может быть отлично видно.
Опять же, в статье мало сказано о варианте с Render to texture. Если мы рисуем маленькую сферу в центре персонажа, чтобы оценить его освещенённость, то необходимо, чтобы сфера была на отдельном слое, который не будет отрисовываться на главной камере; а персонаж (или даже все персонажи) не должны отрисовываться при оценке освещённости. Иначе probe («маленькая сфера») будет всегда затенён персонажем. Так же будет хорошей идеей убрать из отрисовки на оценку освещённости незначимые объекты (не влияющие на результат):
- декали и частицы, которые лишь украшают поверхности, но не влияют на форму и свет;
- skybox и прочие далеко расположенные декорации;
- мелкие объекты, которые не могут влиять на результат (нельзя спрятаться за копьём или шваброй).
Объект можно аппроксимировать, например, сферой или цилиндром. Тогда луч надо начинать не от самого игрока, а чуть подальше.
По мне, так использовать дополнительную камеру — это какое-то чрезмерное извращение. Я думаю, что наверняка эта проблема решается в шейдерах. Но я не знаю, как их писать. Поэтому предлагаю использовать обычные скрипты как альтернативу.
Кошмарные костыли. Надо при помощи SRP или command buffer подхватить карту теней и найти в ней нужный фрагмент для оценки освещения, я ожидал прочитать об этом. В случае deferred режима рендеринга Light occlusion и lighting буферы можно оценить на этапе lighting pass.
Второй подход можно оптимизировать написав для сферы Шейдер(за основу можно взять пример diffuse lighting из документации юнити (https://docs.unity3d.com/Manual/SL-VertexFragmentShaderExamples.html)). В frag методе посчитать средний цвет всех пикселей и присвоить результат переменной, например, float _illumination. Значение этой переменной можно достать в monobehaviour скрипте имея ссылку на материал с этим шейдером и зная имя переменной, используя метод Material.GetFloat("_illumination"). Таким образом вычисление освещенности ложится на видеокарту, а с этим она справляется хорошо, отпадает необходимость использовать медленный Render Texture, и получение значения освещенности можно делать хоть каждый кадр, без падения производительности.
Unity3D: как узнать степень освещения точки сцены?