ПрограммированиеСтатьиГрафика

Быстрая реализация модели освещения Кука-Торренса с использованием GLSL

Автор:

С развитием технологий и увеличением вычислительно мощности видеокарт все легче становиться использовать в трехмерной графике сложные вычислительные алгоритмы. Иногда, конечно, приходится немного пожертвовать производительностью ради красивого вида. Но что поделаешь — красота требует жертв, а сама красота в трехмерной графике достигается использованием «честных», то есть физически обоснованных алгоритмов. Одним из таких алгоритмов и является модель освещения Кука-Торренса. Она очень хорошо подходит для создания различных стеклянных и металлических поверхностей.

Итак, мы начнем!

1. Модель освещения Кука-Торренса
2. Реализация модели Кука-Торренса на GLSL
Ссылки

1. Модель освещения Кука-Торренса

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

Формула Ламберта | Быстрая реализация модели освещения Кука-Торренса с использованием GLSL

Теперь рассмотрим модель Кука-Торренса. Количество отраженного света зависит от трех факторов:
1. Коэффициент Френеля (F)
2. Геометрическая составляющая, учитывающая самозатенение (G)
3. Компонент, учитывающий шероховатость поверхности (D)

Общая формула для вычисления отраженного света такова:

Формула вычисления отраженного света. | Быстрая реализация модели освещения Кука-Торренса с использованием GLSL

Рассмотрим вычисление геометрической составляющей:

image005.png | Быстрая реализация модели освещения Кука-Торренса с использованием GLSL

где N – нормаль в точке, V – вектор взгляда, L – положение источника света, H – нормализованная сумма векторов L и V. Все векторы должны быть нормированы.

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

Распределение Бемкана | Быстрая реализация модели освещения Кука-Торренса с использованием GLSL

где параметр m (от 0 до 1) определяет шероховатость поверхности. Чем он больше, тем поверхность шероховатее, следовательно, отражает свет даже под широкими углами.

Коэффициент Френеля.
Для вычисления коэффициента Френеля существует много формул, но в данном случае целесообразнее применять аппроксимацию Шлика:

Коэффициент Френеля | Быстрая реализация модели освещения Кука-Торренса с использованием GLSL

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

image011.png | Быстрая реализация модели освещения Кука-Торренса с использованием GLSL

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

2. Реализация модели Кука-Торренса на GLSL

Удобно будет написать функцию, которая будет нам вычислять отраженный свет по алгоритму Кука-Торренса. Наша функция должна иметь следующий вид:

float CookTorrance(vec3 _normal, vec3 _light, vec3 _view, float roughness_val)

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

float CookTorrance(vec3 _normal, vec3 _light, vec3 _view, float roughness_val)
{
 if (roughness_val <= 0.0) return 0.0;
}

Если же шероховатость больше нуля, то будем вычислять все:

// вычислим средний вектор между положением источника света и вектором взгляда
   vec3  half_vec = normalize( _view + _light );
// найдем разнообразные скалярные произведения :)
   float NdotL    = max( dot( _normal, _light ), 0.0 );
   float NdotV    = max( dot( _normal, _view ), 0.0 );
   float NdotH    = max( dot( _normal, half_vec ), 1.0e-7 );
   float VdotH    = max( dot( _view,   half_vec ), 0.0 );
// NdotH не может быть равным нулю, так как в последствии на него надо будет делить

// вычислим геометрическую составляющую
   float geometric = 2.0 * NdotH / VdotH;
         geometric = min( 1.0, geometric * min(NdotV, NdotL) );

// вычислим компонент шероховатости поверхности
   float r_sq          = roughness_val * roughness_val;
   float NdotH_sq      = NdotH * NdotH;
   float NdotH_sq_r    = 1.0 / (NdotH_sq * r_sq);
   float roughness_exp = (NdotH_sq - 1.0) * ( NdotH_sq_r );
   float roughness     = exp(roughness_exp) * NdotH_sq_r / (4.0 * NdotH_sq );
// может быть, эти вычисления в точности не соответствуют приведенным выше формулам
// но поверьте – это они и есть :)

// вычислим коэффициент Френеля, не вводя дополнительный параметр
   float fresnel       = 1.0 / (1.0 + NdotV);

// вычисляем результат, добавляя к знаменателю малую величину
// чтобы не было деления на ноль
   Rs = min(1.0, (fresnel * geometric * roughness) / (NdotV * NdotL + 1.0e-7));

Конечная формула вычисления освещения будет выглядеть примерно так:

   vResult = vAmbient + LdotN  * (vDiffuse + vSpecular * Rs)

Как я уже говорил, алгоритм Кука-Торренса хорошо подходит для металлов. Конечно вставив в свой шейдер эти формулы вы не получите металл :)
Для этого еще необходимо подобрать цвета и добавить отражения. И в итоге у вас может получиться вот такой золотой заяц:

bunny.jpg | Быстрая реализация модели освещения Кука-Торренса с использованием GLSL

Ссылки

Более подробно о модели Кука-Торренса на английском языке
Модель Кука-Торренса на Википедии
Аппроксимация Шлика

#Cook-Torrance, #эффекты, #GLSL, #OpenGL, #specular, #освещение

15 июня 2009 (Обновление: 8 июля 2009)

Комментарии [47]