Докуметация Cтарт Статьи Форум Лента Вход
Не официальное русскоязычное сообщество
Главная
    Документация jMonkeyEngine
        jMonkeyEngine Уроки и Документация
            Документация для продвинутых пользователей
                Физически обоснованный рендеринг — Часть третья

Физически обоснованный рендеринг — Часть третья

Опубликованно: 08.06.2017, 14:45
Последняя редакция, Andry: 31.08.2017 14:46

irradianceMap

После некоторых обсуждений в команде я понял, что некоторые пункты не ясны в статье «PBR для художников». Я сделал обновление с дополнительной информацией о том, как обращаться с металличностью и зеркальным отражением. Я предлагаю вам прочитать его, если вы не читали(Первая часть).

Освещение на основе изображения(Image Based Lighting) в PBR

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

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

Сегодня я собираюсь сосредоточиться на технике под названием Image Based Lighting (IBL), которая позволит нам недорого вычислить непрямое освещение.

Как и прежде, вы можете найти в конце статьи раздел термины, с определениями различных необычных терминов, с которыми вы столкнетесь.

Непрямое освещение для PBR с освещением на основе изображений.

Прямое освещение обычно довольно понятно для всех, так как оно использует обычные источники света (точечный свет, направленный свет, …).

Однако непрямое освещение не так очевидно. Сначала вам нужно понять, что мы хотим имитировать с непрямым светом.

Его часто называют Глобальным освещением (или GI). Это означает, что свет отпрыгивает на окружающие объекты, тем самым освещая затененные поверхности. Существует несколько способов реализации глобального освещения, но наиболее распространенным является Освещение на основе изображений(Image Based Lighting) (IBL). Это очень часто связано
с PBR программным конвейером.

Таким образом, источником света в игре является цвет и, возможно, другие параметры, такие как направление, положение, радиус и.т.д. Изображение имеет цветовую информацию, и этот цвет можно рассматривать как источник света.

Для глобального освещения свет приходит со всех сторон. Поэтому хорошим способом моделирования GI с IBL является рассмотрение карты окружения(environment map) в качестве источника света.

Напоминание карты окружения(environment maps):

Чаще всего в играх карты окружения(environment maps) представляют собой кубические карты.

Как извлечь пиксель из карты окружения? Нам нужен вектор. Часто называют отражающим вектором (refVec), потому что этот вектор отражает направления взгляда на затененной поверхности.

Одна картинка стоит тысячи слов

Cube_mapped_reflection_example

Из Википедии: TopherTH на английском языке Wikipedia [GFDL (http://www.gnu.org/copyleft/fdl.html), или CC- BY-SA-3.0 (http://creativecommons.org/licenses/by-sa/3.0/)], через Wikimedia Commons Здесь отраженный луч — наш вектор отражения.

Здесь отраженный луч является нашим вектором отражения.

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

В этой теме есть сумасшедшая математика, и, честно говоря, я сам понимаю не все из этого. Поэтому вместо того, чтобы объяснять сложные математические уравнения, которые могут ввести в заблуждение, я собираюсь прямо сказать: как мы будем вычислять освещение с карты окружения?

IBL Диффузный

Сначала нам нужно вычислить коэффициент диффузии из карты окружения. Помните наш diffuse BRDF с последнего поста? Ламберт(Lambert).

Чтобы упростить, Lambert diffuse BRDF, поскольку он используется в игре, освещающий цвет, умножается на коэффициент видимости.

Этот коэффициент видимости является функцией нормали затененной геометрии и направления света.

Допустим, у вас есть напревленный источник света, который освещает переднюю часть геометрии. Задняя сторона этой геометрии находится в темноте. Значение коэффициента видимости передней стороны равно 1, а коэффициент видимости задней стороны — 0.

Для отраженного освещения мы можем вывести этот коэффициент видимости, потому что свет исходит отовсюду. Таким образом, все это упрощается в Diffuse factor = light color.

Но какой свет цвета для данной точки?

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

irradiance

На этом изображении оранжевая область представляет световые лучи, идущие от карты куба к затененному пикселю, которые мы должны учитывать, чтобы правильно вычислить свет цвета. Таким образом, идея для каждого затененного пикселя состояла бы в том, чтобы извлечь все эти тексели и объединить цвета.

Как вы можете понять, это непрактично для конвейера рендеринга в реальном времени. Даже с картой окружения 128 × 128, будет составлять около 50 тыс. Текстурных изображений на пиксель.

К счастью, мы можем использовать что-то, называемое Карта освещенности(Irradiance map). Карта освещенности — это, в основном, упомянутый расчет, за исключением того, что он предварительно вычисляется и испекается в текстуру. На практике это вот, на что похоже.

irradianceMap

Слева — исходная карта куба, справа, предварительно вычисленная карта освещенности.

Поэтому во время выполнения вам просто нужно сделать одну текстуру в этой карте с вектором отражения. Довольно круто хе?

Кроме того, чтобы предварительно вычислить эту карту, нам все равно придется пробовать карту куба буквально миллиарды раз, и даже если это будет во время разработки … это все равно очень долго.

Спасительные Сферические гармоники(Spherical Harmonics) (SH)

Что это опять? Я не буду подробно объяснять их (потому что я не могу на самом деле; -P), но просто знаю, что это еще одна математическая магия с большим именем. Вот статья, где это объясняется простыми словами, с точки зрения того, для чего вы можете их использовать.

Проще говоря, SH может помочь нам быстрее вычислить карту освещенности. В этой статье объясняется, что все это сводится к вычислению только 9 коэффициентов сферических гармоник для эффективной апроксимации коэффициента освещенности.

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

Но все же … оно медленнее, чем один выбор текстуры, поэтому я решил вычислить карту освещенности и использовать ее в шейдере.

С помощью этой методики я могу вычислить карту освещенности куба 128X128 на CPU в Java примерно за 200 мс. Слишком медленно делать на каждом кадре, но во время разработки это мгновение ока.

DiffuseIBL

Вот диффузный эффект отраженного освещения с использованием освещенности карты куба.

IBL Зеркальный

Отраженный диффузный — это круто, но мы хотим «блестящего»!! Блестящее подразумевает зеркальное освещение.

Важно понимать, что мы хотим, как зеркальное отражение. Мы хотим, чтобы он был очень аккуратным, когда шероховатость низка, и очень размыта, когда высока.

Roughness

По мере увеличения шероховатости отражение становится более размытым.

Для этого нам нужно решить интеграл, называемый radiance integral.

Существует способ сделать это довольно быстро, что называется importance sampling. Однако для получения правильных результатов требуется много образцов, и поэтому он довольно медленный.

Например, для предыдущего снимка я использовал этот метод с 1024 образцами. Это было едва интерактивно, потому что он работал на скорости 16 кадров в секунду на GTX 670.

Спасибо Epic games!

Epic games пришли с решением этой проблемы для Unreal Engine 4. На самом деле и другие делали, но Epic games обнародовали эту статью от Брайана Кариса. Я не могу поблагодарить их за это.

В этой статье они объясняют, как они это делают в UE4. Они используют метод, который они назвали Split Sum Approximation. Это не ускоряет вычисление, но преобразует его так, что его можно испечь в двух предварительно отфильтрованных текстурах.

  • Нефильтрованная карта окружения

Мы собираемся предварительно обработать карту окружения на CPU.

Как объяснялось ранее, нам нужно, чтобы отражение было более размытым по мере увеличения шероховатости. Основная идея здесь заключается в сохранении разных уровней шероховатости карты окружения в карте mip. Первый уровень карты mip будет соответствовать шероховатости = 0, а последний будет соответствовать шероховатости = 1.

От уровней mip до уровней mip мы будем convolve (размывать) изображения в зависимости от шероховатости. Чем больше шероховатость увеличивается значение на образце, которые мы собираемся использовать, тем больше оно будет распространено.

Но это еще не все, мы также хотим «испечь» зеркальный BRDF на карте, поэтому для каждого пикселя мы собираемся вычислить микрограни «Cook-Torrentz» BRDF (помните последний пост).

Но, поскольку мы выполняем предварительную обработку карты, у нас нет никакой информации о нормалях и направлении вида затененной поверхности. Поэтому мы предполагаем, что они все одинаковы и равны envVector, которые мы будем использовать для получения пикселей с карты. Также предположим, что точка затенения находится точно в центре карты куба.

prefilteredEnvMapSampling

Это снова аппроксимация, и оно имеет стоимость по качеству, но мы все для аппроксимации, пока она работает быстрее, и все еще хорошо выглядит, не так ли?

Вот как выглядит результат:

PrefilteredEnvMap

Нефильтрованная карта окружения с различными уровнями mip. Обратите внимание, как размытие увеличивается через них.

Итак, теперь мы можем вычислить первую сумму аппроксимации сплит-суммы с помощью одной выбранной текстуры. Мы собираемся вычислить уровень Lod (уровень mip, где нужно получить texel) в соответствии с шероховатостью.

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

  • Интеграции карты в BRDF

Теперь нам понадобится вторая сумма аппроксимации сплит-суммы.

Это интеграция, которая имеет два входа, шероховатость, которая в диапазоне от 0 до 1, и скалярное произведение между нормалью и направлением света (N.L, читается N dot L), который также в диапазоне от 0 до 1.

Выходы представляют собой масштаб(scale) и смещение(bias), также варьирующееся от 0 до 1.

Таким образом, в основном мы можем выпекать все комбинации в 2D-карту. Шероховатость и N.L будет координатой текстуры. Красным каналом карты будет масштаб, а зеленый канал будет смещением. (Синий канал не используется)

Вот как это выглядит:

integrateBrdf

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

Теперь нам нужно объединить значения, полученные с этих карт, чтобы получить зеркальное освещение.

Вот как выглядит зеркальное отражение, с шероховатостью 0,1.

IndirectSpeculra

Итак, в конце:

Псевдокод косвенного освещения выглядит следующим образом:

//диффузный
indirectDiffuse = textureCube(IrradianceMap, refVec)  * diffuseColor

//зеркальный
lod = getMipLevelFromRoughness(roughness)
prefilteredColor =  textureCube(PrefilteredEnvMap, refVec, lod)
envBRDF = texture2D(BRDFIntegrationMap,vec2(roughness, ndotv)).xy
indirectSpecular = prefilteredColor * (specularColor * envBRDF.x + envBRDF.y)

indirectLighting = indirectDiffuse + indirectSpecular

На этом заканчивается статья. Достаточно много информации для обработки. Теперь вы должны иметь представление обо всем этом. В следующий раз мы пойдем под капот и YOU GONNA HAZ CODE!!

Термины:

Global Illumination (GI): концепция, которая представляет все освещение сцены, которое не исходит от направленного источника света.

Image Based Lighting (IBL): метод, который использует изображение в качестве источника света

Irradiance map: Предварительно рассчитанная карта окружения, которая содержит данные о диффузном освещении окружения.

Spherical Harmonics (SH): прочитайте это

Importance Sampling: математическая техника для аппроксимации результата интеграла.

Split Sum Approximation: способ, используемый в Unreal Engine 4, преобразовать интеграл зеркального блеска в 2 суммы, которые можно легко испечь в предварительно отфильтрованные текстуры.


Переведено для jmonkeyengine.ru, оригинал
Автор перевода: Andry

Добавить комментарий

jMonkeyEngine.ru © 2017. Все права сохранены.