PBR. Секреты фотореалистичной графики

Когда сегодня говорят о 3D-графике, под этим почти всегда подразумевается фотореализм – стремление к тому, чтобы конечное изображение виртуальной сцены было неотличимо от фотографии. За эталон, как правило, берется именно фотография, так как повторить то, как мы видим мир нашими глазами, воспроизвести чересчур сложно, да и не нужно, ведь картинка на плоском экране – это совершенно не то же самое, что «картинка» в нервной системе человека.

Если вы профессиональный графический разработчик или GPU-инженер, то, наверное, нижеследующий текст ничего нового вам не откроет. Но если вы только начинаете работать с 3D, то, вероятно, сталкивались с недоумением – почему ваши рендеры выглядят скучно и как бы «плоско», несмотря на качественный контент? Фотореализм связан не только с детализированными 3D-объектами и текстурами. Это еще и целый комплекс техник, набор идей и подходов – именно они, в первую очередь, и отвечают за «магию» реалистичности. В этой статье я расскажу о большинстве из этих секретов – поверьте, профессионалы отлично ими владеют и постоянно их используют для создания вау-эффекта.

PBR

Энергетическая яркость и отражательная способность

3D-графика – это наполовину про геометрию, а наполовину про свет. Для того, чтобы реалистично рендерить, нужно хотя бы в общих чертах понимать принципы вычислительной оптики. Пиксели отрендеренной сцены – это не точки на поверхности 3D-объектов изображенного мира. Это скорее точки на поверхности виртуальной «матрицы фотоаппарата» – свет, который отразился от объекта и попал в оптическую систему. Значение пикселя – это энергетическая яркость (radiance) в направлении этого пикселя: величина потока (radiant flux), излучаемого единицей площади в единицу телесного (т.е. объемного) угла в данном направлении. Обычно допускается, что пиксель имеет бесконечно малую площадь, так что энергетическая яркость в нашем случае – это поток, посылаемый в пиксель одним-единственным световым лучом.

Важно: в реальности, конечно, никаких световых лучей при рендеринге нет – просто мы используем математическую модель, в рамках которой удобно оперировать понятием луча.

Вторая важнейшая концепция, с которой имеет дело любой реалистичный рендер, – это отражательная способность (reflectance). Как ясно из названия, это способность поверхности отражать падающий на нее поток электромагнитного излучения. Чтобы найти энергетическую яркость пикселя, в простейшем случае (если допустить, что свет распространяется в вакууме, ничем по пути не поглощается и не преломляется) нужно вычислить энергию, отраженную участком поверхности в направлении, в котором луч света попадает на пиксель – это направление обычно называется видовым вектором (eye vector). В компьютерной графике для этого используются аналитические двулучевые функции отражательной способности (bidirectional reflectance distribution function, BRDF) или просто модели освещения (shading model). Двулучевыми они называются по той причине, что параметрами в них выступают два луча – входящего и выходящего света. В нашем случае входящий свет – это луч от точки поверхности к источнику света (вектор освещения), выходящий – от точки поверхности к пикселю на экране (видовой вектор).

BRDF vectors

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

PBR

Важно понимать, что BRDF – это радиометрическая модель, то есть, абстрактное математическое описание оптического явления. BRDF не сводятся к какой-либо физической теории, являясь, по сути, эвристиками – эвристический метод не является точным и всеохватывающим, но он достаточен и оптимален для решения поставленной задачи. Задача в нашем случае может быть сформулирована следующим образом: «Как сделать так, чтобы виртуальные трехмерные объекты были похожи на настоящие?». Для решения этой задачи нам не нужно углубляться в физику, полноценно воссоздавать электромагнитное поле, решать уравнения Максвелла и т.д. – достаточно просто смоделировать то, что мы наблюдаем своими глазами.

Есть распространенное мнение, что в реалистичной 3D-графике используются какие-то особые научные методы, восходящие к физике, и поэтому результат выглядит так круто. Наверное, термин physically based rendering (PBR) уходит корнями именно в это заблуждение. Часто его переводят как «физически корректный рендеринг» – даже статья в Википедии озаглавлена именно так, но PBR к физике имеет весьма опосредованное отношение. Правильнее было бы говорить о «физически обоснованном рендеринге» – то есть, рендеринге, учитывающем законы физики. Самый очевидный пример такого закона – сохранение энергии. Чтобы BRDF могла считаться «физичной», энергия отражения в ней не должна превышать энергию освещения – уже одно это весьма полезно для достижения правдоподобного результата.

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

В целом, PBR – это не какая-то конкретная техника, а обозначение совокупности техник и подходов, которые учитывают некоторые законы физики и моделируют явления оптики с использованием условно-физичных параметров: альбедо, шероховатость, металличность, френелевское отражение, коэффициент преломления и др.

Вот несколько примеров «физичных» аналитических BRDF, которые широко применяются в компьютерной графике – в том числе, в последние годы, и в реальном времени:

  • Модель Кука-Торренса (Cook-Torrance) – модель, учитывающая микрограни, долгое время была де-факто стандартом в рендер-движках;
  • Модель Орена-Найара (Oren-Nayar) – часто используется для моделирования шероховатых материалов, таких как ткани;
  • Распределение GGX – одна из самых реалистичных современных моделей, результаты которой близки к радиометрическим данным в базе MERL;
  • Disney principled BRDF – модель на основе анизотропного GGX, поддерживает множество разных явлений, в том числе подповерхностное рассеивание (subsurface scattering) и бесцветное покрытие (clearcoat). Используется, например, в Renderman и Blender.

Рабочие процессы PBR

Вам, наверное, уже знакомы эти три параметра, которые используются многими PBR-системами:

Альбедо (albedo) или базовый цвет (base color) – характеристика отражательной способности поверхности в зависимости от длины волны. Человеческий глаз воспринимает это свойство как цвет. При абсолютно черном альбедо свет полностью поглощается, при абсолютно белом – полностью отражается. Строго говоря, понятие альбедо относится только к диффузному отражению, так что рекомендуется использовать термин «базовый цвет», если один и тот же параметр отвечает и за диффузный, и за зеркальный цвет.

Шероховатость (roughness) – присутствует, если BRDF поддерживает микрограни, то есть, если моделируется поверхность, состоящая из микроскопических зеркальных выпуклостей. При roughness = 1 поверхность считается строго ламбертовой. В этом случае свет полностью рассеивается. При roughness = 0 поверхность отражает зеркально: угол отражения равен углу падения. В промежуточных значениях между 0 и 1 часть излучения отражается зеркально, а часть – диффузно. Такое происходит в слоистых материалах, например, покрашенных или лакированных – когда свет частично отражается от гладкой поверхности, а частично проникает вглубь и там рассеивается. Чем больше шероховатость, тем сильнее размыты зеркальные блики от источников света. Чаще всего шероховатость однородна (т.е. вероятность рассеивания светового луча в случайном направлении одинакова на всей площади поверхности), однако существуют и анизотропные BRDF с возможностью задавать неоднородность шероховатости – например, если поверхность должна иметь направленные бороздки, как у полированного металлического диска.

Металличность (metallic) – концентрация металлов в веществе. Металлы почти не пропускают видимое излучение, отличаясь весьма высокой отражательной способностью: в компьютерной графике обычно допускается, что при metallic = 1 поверхность отражает 100% излучения. При metallic < 1 часть излучения рассеивается (и часть поглощается в зависимости от альбедо). Некоторые металлы (золото, медь) имеют цветной оттенок из-за того, что они поглощают часть излучения на определенных частотах – этот эффект имеет квантовомеханическую природу, так что нам в компьютерной графике досконально его моделировать не нужно, достаточно предусмотреть поддержку цветных отражений для металлов: то есть, чем металличнее поверхность, тем сильнее цвет зеркального отражения зависит от параметра base color. У неметаллов (которые также называют диэлектриками) цвет зеркального отражения не зависит от альбедо – блики всегда имеют цвет источника света.

Rougness metallic

Подход с использованием параметра metallic называют металл-диэлектрическим рабочим процессом (metallic workflow). В некоторых движках и рендерах можно встретить процесс specular/gloss. Эти два процесса суть одно и то же, просто они выносят в параметры разные переменные BRDF. Металл-диэлектрический процесс придуман для того, чтобы соблюдался закон сохранения энергии (diffuse + specular <= 1), то есть, грубо говоря,

specular = albedo * metallic
diffuse = albedo * (1 - metallic)
gloss = 1 - roughness

Если хранить сразу specular и diffuse, то есть вероятность, что их сумма получится «нефизичной» – совокупная отраженная энергия может быть больше падающей, а это уже не PBR. Для сохранения энергии нужно делать дополнительные телодвижения: параметры должны быть взаимосвязанными – чем больше gloss, тем ярче specular (и, соответственно, тусклее diffuse). У металл-диэлектрического подхода такой связи между параметрами нет, что довольно удобно.

Также есть разница в экономии по весу текстур:

Specular/gloss - 24-bit (diffuse) + 24-bit (specular) + 8-bit (gloss)
Metallic/roughness - 24-bit (base color) + 8-bit (metallic) + 8-bit (roughness)

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

Эффект Френеля

Fresnel

Зависимость отраженного света от падающего сложнее, чем кажется: любая «физичная» модель освещения обязана учитывать отражение Френеля (Fresnel reflection). Этот эффект можно описать в простых словах следующим образом: любая поверхность приближается к идеальному зеркалу по мере уменьшения угла между поверхностью и направлением взгляда. Вы можете легко это проверить, если возьмете какой-нибудь предмет и повернете его к источнику света параллельно вашему взгляду. Почему так происходит? Чтобы понять этот феномен, нужно усвоить простой факт: любая неламбертова поверхность часть излучения отражает зеркально. Но мы не всегда видим это отражение из-за большого количества рассеянного света от микроскопических неровностей. Когда вы смотрите вдоль поверхности, все неровности на ней компенсируют друг друга, поверхность визуально сглаживаются – вы будете видеть меньше случайных лучей, до ваших глаз будет доходить в основном зеркально отраженный свет.

Гамма-коррекция в шейдерах

Гамма-коррекция – это одна из тем, которые почему-то старательно обходятся стороной в большинстве книг и статей по компьютерной графике. Итог – целые поколения специалистов о ней ничего не знают, буковку «s» в аббревиатуре sRGB не замечают и все вычисления, связанные с цветом, делают неправильно.

Человеческий глаз различает детали в очень широком диапазоне яркости, который значительно превышает возможности мониторов. Картинка, которую вы видите на экране, вроятнее всего, имеет 8 бит на канал – яркость, которую можно на нем передать, варьируется в целочисленном диапазоне [0, 255]. Это само по себе не проблема, так как любой диапазон яркости можно перенормировать в эту шкалу – разумеется, с потерей информации, но тут уж ничего не поделаешь (потери можно минимизировать, если использовать сведение экспозиций, но это уже другая история). Проблема возникает, если попытаться сделать это линейно. В нормальных условиях глаз лучше различает перепады освещенности в тенях, чем в светлых участках. Следовательно, изображение с линейно дискретизированной яркостью будет содержать слишком мало информации в тенях – а в светах, наоборот, избыточное количество. Чтобы это компенсировать, используется нелинейная (обычно степенная) функция, которая «сжимает» и «растягивает» точность информации в нужных участках диапазона. Это и есть гамма-коррекция. Выглядит она так: f(x) = x1/γ. Ее выполняет, например, цифровая фотокамера перед тем, как сохранить изображение в формат JPEG.

Итак, представим, что у нас есть картинка (например, текстура для 3D-модели) – отображается она хорошо, с «правильными» перепадами яркости. Теперь хотим ее использовать в шейдерных вычислениях. Помним, что пиксели хранятся в гамма-скорректированном виде – обычно в этом случае говорят, что цвет в гамма-пространстве. Это нужно для вывода картинки на экран, но совершенно не подходит для обработки. Суммирование и умножение значений яркости (а, следовательно, и 3-канальных пикселей) в гамма-пространстве не имеют ни математического, ни физического смысла. Конечно, вы можете их суммировать и умножать, и у вас что-то получится, но это «что-то» не будет соответствовать информации, полученной из реального мира. Такие данные нельзя использовать в физических формулах. Перед тем, как обработать пиксель, его нужно перевести обратно в линейное пространство при помощи функции f(x) = xγ. При этом в качестве значения γ часто используется 2.2. На GLSL эти преобразования будут выглядеть так:

linearColor = pow(inputColor, vec3(2.2));
outputColor = pow(linearColor, vec3(1.0/2.2));

inputColor – это то, что вы получаете из входных данных. Например, значение пикселя из текстуры или константа цвета из палитры графического редактора. linearColor – это то, что можно использовать для алгебраических преобразований – суммирования, смешивания, интерполяции и т.д. – а также как входные значения для физических формул, например, BRDF. outputColor – это значение, которое можно выводить на экран (если у вас выводной буфер sRGB – а чаще всего это именно так).

Абсолютно любые вычисления для PBR следует делать в линейном пространстве и никак иначе!

sRGB (standard RGB) – это стандартное цветовое пространство, охватывающее спектр, который может быть передан всеми существующими мониторами и телевизорами. Важно понимать, что, применительно к sRGB, γ=2.2 – это аппроксимация. На самом деле, функция гамма-коррекции состоит из линейной части около черного цвета, где γ=1, и нелинейной части, где γ<=2.4. Такие сложности понадобились для совместимости с CRT-мониторами и телевизорами, которые имеют нетривиальную зависимость количества испускаемых фотонов от напряжения на катоде.

Важно: ответ на вопрос, конвертировать ли результат шейдера в гамма-пространство или нет, зависит от того, как работает ваш графический API. Например, в OpenGL можно задать glEnable(GL_FRAMEBUFFER_SRGB), и в этом случае при записи в буфер кадра все значения будут автоматически конвертироваться в sRGB, и в шейдере делать это не нужно.


Copyright © 2008-2023 Тимур Гафаров и соавторы. Доступно по СС BY-NC-SA 3.0.