NeRV: Neural Reflectance and Visibility Fields for Relighting and View Synthesis
Перед прочтением статьи рекомендуем к просмотру наше видео с разбором NeRF и Instant NeRF.
Давайте вспомним для чего нужен и что делает классический NeRF. Это нейросеть, обученная с целью создания одной 3D сцены по нескольким её 2D фото с разных ракурсов. Для этого мы учим сеть предсказывать цвет и прозрачность точки в трёхмерном пространстве. На вход подаются координаты точки начала луча из камеры и углы, определяющие его поворот в трёхмерном пространстве (см. Рисунок 1).
Рендеринг — получение 2D картинки из 3D сцены. Для получения 2D изображения из NeRF мы пустим из каждого пикселя изображения луч (назовём его лучом камеры), получим для точек на лучах значения цвета
По архитектуре сеть представляет собой multilayer perceptron (MLP).
Зачем менять освещение?
Вы модный молодёжный 3D художник и хотите максимально упростить себе жизнь с помощью нейронок. Вы узнаёте про NeRF, очень радуетесь, бегом получаете через него рендеры для пары объектов из дома и… Не можете их особо нигде использовать. Потому что освещение в них фиксированное.
Представление NeRF не отделяет эффект падающего света от свойств материала поверхностей. Из-за этого при желании заменить источники света нам нужно будет сделать новые фото для каждого варианта освещения и заново обучить сеть. Это приводит к более дорогому сбору данных и обучению моделей. А если освещение динамическое, как при движении Солнца — непонятно, зачем нужен этот ваш нейронный рендеринг, дешевле же нарисовать…
Как обучить сеть, которая будет принимать источники освещения как часть входных данных и выдавать рендер для сцены с таким освещением?
Освещение
Для качественного предсказания освещения нужно научиться работать с двумя его типами — прямым (direct) и отражённым (indirect). Их различия показаны на Рисунке 3:
Можно предсказать direct illumination методом NeRF. Выпускаем из источника света несколько лучей (назовём их лучи освещения), проверяем прозрачность всех точек между точкой на луче из камеры и источником света. Можно на каждом луче освещения брать столько точек, сколько их на луче из камеры. Если возьмем меньше точек — потеряем часть информации о освещении. Следовательно, для качественного рендера нам понадобится вычислить плотность в \( O(n^2) \) точках.
Теперь рассмотрим indirect освещение для одной точки на луче из камеры. Сначала мы берём \( d \) лучей освещения (это выделено синим на Рисунке 4), каждый из которых требует вычисления в \( n \) точках. Для этого нам придётся посчитать плотность в этих \( n \) точках и на \( (n — 1) \) лучах освещения между этими точками и источником освещения.
Итого: в indirect освещении для одной точки мы имеем \( d \cdot n \cdot (n — 1) + 1 = O(n^2d) \) вычислений. Теперь мы вспоминаем, что считали только для одной точки на луче из камеры. Значит, для всех точек при единственном источнике освещения имеем \( O(n^3d) \), а при \( l \) источниках освещения будет уже \( O(n^3dl) \).
Как освещение просчитывают в графике?
BRDF — функция, связывающая угол падения между вектором \( \omega_i \) и нормалью к поверхности \( n \) и угол отражения между \( \omega_0 \) и \( n \) с яркостью луча до падения и после (см. Рисунок 5). Эту функцию можно получить на основе теоретической модели и за счёт других физических свойств материала. Для использования microfacet BRDF (как в Unreal Engine) нам, кроме нормали \( n \), нужно знать albedo (характеристика отражения света) и roughness (шероховатость поверхности).
Как улучшить сетками?
Для каждой точки MLP в NeRF предсказывает цвет \( (r, g, b) \) и плотность \( \sigma \). В NeRV мы разбиваем задачу между несколькими MLP.
Shape
Мы получим для каждого луча плотность \( \sigma \) (для понимания пройденного через точку количества света) и нормаль к поверхности в этой точке \( n \) (для углов падения и отражения). Пусть их вычисляет отдельная \( MLP_{shape} \).
Пусть \( t \) — параметр, отвечающий за положение точки на луче из камеры, \( x(t) \) — координаты точки для предсказания, тогда \( MLP_{shape}(x(t))= \sigma \). При этом мы считаем карту нормалей \( n = \nabla_x \sigma = \nabla_x MLP_{shape}(x(t)) \).
BRDF
Еще нам нужна \( MLP_{BRDF} \) для вычисления параметров albedo (\( a \)) и roughness (\( \gamma \)).
В нотации из формул выше имеем: \( MLP_{BRDF}(x(t)) = (a, \gamma) \). BRDF позволяет получать цвет пикселя с учётом падающего на него освещения.
Rendering
Для получения итогового результата мы используем уравнение рендеринга. Для решения задачи с прошлых этапов нам уже достаточно информации, но нужно будет еще учитывать положения всех предсказанных точек (см. Рисунок 4) и считать два интеграла по объему — это дорого. Эти два интеграла нам нужны для определения V — видимости освещения в точке (попадает ли вообще в неё луч света?) и D — расстояния, с которого в точку отразится луч из источника света. D помогает нам найти точку — на нее указывает синяя стрелка на Рисунке 6.
Дешевле получить приближенный результат отдельной сетью \(MLP_{V, D}\). Параметры вычисляются для конкретного луча \( \omega_i \) (см. Рисунок 5): \( MLP_{V, D}(x(t), \omega_i) = (V, D) \) .
Дальше в дело вступает магия физики и обычного рендеринга. Мы берём переменные в уравнении рендеринга и заполняем их сетками выше. Одно из заметных отличий этой статьи от NeRF — количество формул с интегралами 🙂
Итоги
Вот что у нас происходит в NeRV:
- для каждого луча сэмплируем набор точек, для каждой точки прогоняем MLP с целью получения \( \sigma \), карты нормалей и параметров BRDF;
- применяем direct освещение для каждой точки на луче: для вычислений используем V и BRDF;
- применяем indirect освещение для каждой точки на луче: с помощью D находим точку, из которой пойдёт отражение луча, вычисляем ее влияние с BRDF;
- объединяем полученные лучи и точки как в NeRF.
NeRV описывает решение проблемы со статичным освещением в NeRF, используя для этого достижения классического рендеринга. После обучения модели мы можем задать несколько точек в качестве источников освещения и получить отрендеренную сцену.