воскресенье, 11 октября 2009 г.

Fresnel Reflection

Наверное многие замечали подобный эффект: плохо отражающая поверхность становится неплохим зеркалом при больших углах обзора (grazing angle). А происходит это из-за физических свойств света, когда луч отражается (и преломляется) на границе двух сред с различной плотностью. Описывается такое поведение уравнениями Френеля. Данные уравнения используются для того, чтобы рассчитать коэффициенты отражения и трансмиссии энергии (power) светового луча.

Кто занимается графикой, знает, что в эпоху Shader Model 2.0 были очень популярны различные аппроксимации уравнений Френеля, например, аппроксимация Шлика. Если поискать, можно легко их найти в "старых" шейдерах, реализующих там воду или стекло. Не знаю, как в Крайзисе считается, но в эпоху Shader Model 4.0/5.0 уже пора завязывать с этими аппроксимациями и считать подобные вещи честно. На самом деле вычислений здесь - кот наплакал. Если подразумевается использование преломлённого луча, то это значит что у нас уже есть косинусы углов падения и преломления. Придётся сделать всего семь умножений, два деления, плюс пять арифметических операций сложения/вычитания, чтобы получить коэффициент для неполяризованного света. Если преломления не считаются, а есть только угол падения, придётся использовать вариант с трансцендентными функциями. В этом случае формулу лучше запечь в текстуру и делать в шейдере выборку. Впрочем, первый вариант тоже является кандидатом на запекание в текстуру: cами по себе расчёты не сложны и не займут много инструкций (по нынешним меркам), но по моим предварительным оценкам, сложный шейдер, реализующий правдоподобный эффект преломления, выльется этак в 400-500 инструкций. В этих условиях целесообразнее сделать дополнительную выборку из текстуры, заодно и соотношение ALU/TEX будет выполняться получше.

Я написал тест, чтобы проверить, как распространяется эффект Френеля на энергию луча (и отладить математику, отлаживать её в прямо в шейдере - то ещё удовольствие). Вот скриншоты, показывающие преломление/отражение для воздуха и стекла:

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

Немного увеличим угол, эффект Френеля всё ещё не заметен:

При значительных углах видно, что отражённый луч получает все большую долю энергии падающего луча:

Почти предельный случай: почти вся энергия луча вкладывается в отражения (первое и второе).

А вот графики функций для стекла (по оси абсцисс - угол падения, по оси ординат - значение коэффициента). Для s-polarized (синий цвет) и p-polarized (красный):



А вот усреднённое значение для неполяризованного света:


Заметьте, что коэффициент в последнем случае никогда не равен нулю, т. е. во всех случаях часть энергии луча уходит в отражение, что подтверждает первый скриншот.

Думаю, с Френелем всё понятно (для CG-случая, физическая сторона вопроса очень глубока).

P. S. Реализовал трассировку луча для линзы, наполненной водой. Вот как это выглядит:

Хорошо видны две "мертвые зоны" по бокам обзора. Также хорошо видно, как странно ведёт себя луч рядом с этими зонами. Поэкспериментируйте - налейте в стеклянную бутыль воды и посмотрите, как искажается изображение на мониторе. А потом сравните с картинкой. Я сравнивал - всё правильно :)

Комментариев нет:

Отправить комментарий