Главная Статьи Ссылки Скачать Скриншоты Юмор Почитать Tools Проекты Обо мне Гостевая Форум |
Традиционные модели освещения, например Фонга, рассматривают так называемые анизотропные поверхности. Для этих поверхностей их свойства в точке не зависят от ориентации плоскости, т.е. поворот поверхности вокруг нормали к точке не изменяет то, как мы ее видим.
Рис 1. Изотропное освещение.
Фактически, для подобных поверхностей модель освещения использует только взаимные углы между векторами i, v и n и не зависят от ориентации поверхности (при сохранении этих углов).
Однако в реальной жизни мы достаточно часто сталкиваемся с другим классом поверхностей (точнее материалов из которых они сделаны) - анизотропными.
Простейшим примером такой поверхности является компакт диск. На нем кольцевая структура треков оказывает очень сильное влияние на то, какой мы ее видим.
Другими примерами анизотропных поверхностей являются отполированный металл, одежда из определенных типов тканей и т.п.
Фактически все эти поверхности характеризуются наличием на них структуры линий, обладающими строго определенной ориентации.
Рис 2. Примеры анизотропных поверхностей.
Рассмотрим каким образом можно построить модель освещенности для такого класса поверхностей.
Наличие линий на такой поверхности позволяет описывать структуру подобной поверхности при помощи поля касательных векторов - для каждой точки задается единичный вектор t, касательный к линии в данной точке.
Тем самым, вместо карты нормалей мы будем использовать карту касательных (tangent map), в который в виде цветов будут храниться касательные вектора.
На следующих рисунках приведены карты касательных для поверхностей с рисунка 2.
Рис 3. Примеры карт касательных.
При этом мы можем рассматривать поверхность как состоящую из набора бесконечно тонких линий (волосков) и строить модель освещения для одного такого волоска.
Все, чем описывается такой волосок - это касательный вектор, вектор нормали определяется неоднозначно.
Рис 4. Волос.
Поскольку такой волос считается бесконечно тонким (по крайней мере тоньше, чем размер пиксела), то для определения освещенности исходят из следующего соображения - из всего множества нормалей к волосу в точке выбирается тот, который дает наибольшую яркость, причем отдельно для диффузной и бликовой частей.
Рассмотрим это на примере вычисления диффузного освещения в точке.
Мы хотим найти такой вектор нормали n (т.е. единичный вектор ортогональный касательному вектору), для которого выражение (l,n) достигает своего максимума для заданного единичного вектора направления на источник света l.
Для нахождения соответствующего вектора нормали разложим вектор l на две части - часть lt параллельную касательному вектору t и нормальную часть ln, ортогональную касательному вектору.
Рис 5. Разложение вектора l на касательную и нормальную компоненты.
lt = t(l,t)
ln = l - t(l,t)
Тогда вектор l может быть представлен в следующем виде:
l = lt + ln
Подставив это представление в скалярное произведение (l,n) мы получаем
(l,n) = (ln,n)
Из этой записи сразу видно, что максимум скалярного произведения достигается только в том случае, когда вектор n будет параллелен вектору ln.
Тогда мы получим следующее выражение для диффузной компоненты освещенности:
Id = Kd*C*(1 - (t,l)2)1/2
Аналогично для бликовой составляющей мы получаем следующее выражение:
Is = Ks*(1 - (t,h)2)p/2
Таким образом, мы получили выражение для освещенности для волоса и, значит, и в произвольной точке поверхности.
Самым простым способом реализации попиксельного анизотропного освещения является использование фрагментных и вершинных программ.
Задача вершинной программы - подготовить вектора l и h, поэтому мы можем спокойно использовать ту же вершинную программу, что и для обычного освещения.
Фрагментная программы нормирует полученные значения векторов l и h, находит их скалярное произведение с касательным вектором из карты касательных и вычисляет освещенность.
Соответствующая фрагментная программа приводится ниже.
!!ARBfp1.0 # # simple anisotropic fragment shader # on entry: # fragment.texcoord [0] - texture coordinates # fragment.texcoord [1] - l in tangent space # fragment.texcoord [2] - h in tangent space # ATTRIB l = fragment.texcoord [1]; ATTRIB h = fragment.texcoord [2]; PARAM amb = { 0, 0, 0.5 }; PARAM one = 1; PARAM two = 2; PARAM shininess = 20; PARAM specColor = { 1, 1, 1 }; PARAM scale = 0.03; PARAM diffusePower = 1; PARAM specularPower = 30; TEMP t, t2, dots, color, h2, l2, temp, diffuse, dist, atten; TEX t, fragment.texcoord [0], texture [0], 2D; # get tangent MAD t, t, two, -one; # normalize l DP3 dist.w, l, l; RSQ l2.w, dist.w; MUL l2.xyz, l, l2.w; # normalize h DP3 h2.w, h, h; RSQ h2.w, h2.w; MUL h2.xyz, h, h2.w; DP3 dots.x, l2, t; DP3 dots.y, h2, t; MUL dots.xy, dots, dots; ADD dots.xy, one, -dots; POW dots.x, dots.x, diffusePower.x; POW dots.y, dots.y, specularPower.x; # diffuse TEX temp, fragment.texcoord [0], texture [1], 2D; MUL diffuse, temp, dots.x; # now diffuse holds diffuse lighting # compute resulting color MAD_SAT result.color, specColor, dots.y, diffuse; END
Вместо явного возведения в степень можно было использовать текстуру, задающую зависимость освещенности от величины соответствующего скалярного произведения.
Ниже приводится несколько изображений, полученных при использовании анизотропной модели освещения.
Исходный код, демонстрирующий работы анизотропной модели освещения можно скачать Исходный код, демонстрирующий работы анизотропной модели освещения можно скачать здесь. В этот код также включены несколько скриптов на языке Python для построения ряда простейших касательных карт.