Array ( )
Вход:




Главная | OpenGL | GLSL | AI | Сеть | Примеры | Библиотека

GLSL: Освещение: Направленный свет I






Формулы этого урока взяты из раздела "The Mathematics of Lighting" книги "OpenGL
Programming Guide", aka "The Red Book". Мы начнем с рассеянного света. Рассеянный
свет в OpenGL подразумевает, что свет падает на полигоны с одинаковой интенсивности
независимо от положения зрителя. Его интенсивность пропорциональна отношению диффузной
интенсивности света и коэффициенту диффузного отражения материала. Интенсивность также
пропорциональна углу между направлением света и нормалью полигона.



Следующая формула используется OpenGL для рассчета рассеянного света:


Где 'I' - интенсивность отражения (reflection), Ld = диффузный цвет источника
(gl_LightSource[0].diffuse), и Md - диффузный коэффициент материала
(gl_FrontMaterial.diffuse).

Эта формула известна как "Lambertian Reflection". "Закон косинуса Ламберта" говорит,
что яркость диффузного света на поверхности плоскости пропорциональна косинусу угла
между лучем света и нормалью плоскости. Эта формула была выведена более двухсот лет
назад (Johann Heinrich Lambert, 1728-1777)!

Чтобы применить эту формулу, вершинный шейдер будет использовать параметры света, а
именно его позицию и диффузную интенсивность. Также шейдер будет использовать диффузные
параметры материала. Для использования этого шейдера просто установить свет в OpenGL, как
делали это раньше. Однако имейте в виду, что так как мы не используем фиксированный функционал,
нет необходимости включать в OpenGL освещение (glEnable...).

Так как нам нужно вычислить косинус, сначала убедимся, что векторы нормали и направления света
(gl_LightSource[0].position) нормализованы, а затем используем формулу dot product для получения
косинуса. Учтите, что OpenGL хранит направление света как вектор от вершины к источнику света,
что противоречит вышеприведенному рисунку.

OpenGL хранит направление света в координатах нашего "взгляда", поэтому нам нужно трансформировать
нормаль в координаты "взгляда", чтобы рассчитать dot product. Чтобы трансформировать координаты
нормали будем использовать зарезервированную uniform-переменную mat3 gl_NormalMatrix. Эта
матрица - инверсия в верхне-левую подматрицу 3х3 из матрицы моделей.

Следующий вершинный шейдер показывает GLSL-код для всего этого:
    void main() {
   
        vec3 normal, lightDir;
        vec4 diffuse;
        float NdotL;
       
        /* сначала трансформируем нормаль в нужные координаты и нормализуем результат */
        normal = normalize(gl_NormalMatrix * gl_Normal);
       
        /* Теперь нормализуем направление света. Учтите, что согласно спецификации
        OpenGL, свет сохраняется в пространстве нашего взгляда. Также, так как мы
        говорим о направленном свете, поле "позиция" - это и есть направление. */

        lightDir = normalize(vec3(gl_LightSource[0].position));

        /* вычислим косинус угла между нормалью и направлением света. Свет у нас
        направленный, так что направление - константа для каждой вершины. */

        NdotL = max(dot(normal, lightDir), 0.0);
       
        /* вычисляем диффуз */
        diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;
       
        gl_FrontColor =  NdotL * diffuse;
       
        gl_Position = ftransform();
    }


Теперь всё, что остаётся на долю пикселного шейдера - установить цвет пикселов, используя
varying-переменную gl_Color:
    void main()
    {
        gl_FragColor = gl_Color;
    }


Следующее изображение показывает этот шейдер, применённый на чайнике. Заметьте, что низ
чайника очень темный. Это потому, что мы не учитываем мировое (ambient) освещение,
которое можно установить в OpenGL.



Собственно, мировое освещение рассчитать легко. Есть глобальные ambient-свет и "легкий"
ambient-свет. Формула окружающего света:



В вершинный шейдер придется внести некоторые изменения для рассчета ambient:
    void main()
    {
        vec3 normal, lightDir;
        vec4 diffuse, ambient, globalAmbient;
        float NdotL;
       
        normal = normalize(gl_NormalMatrix * gl_Normal);
        lightDir = normalize(vec3(gl_LightSource[0].position));
        NdotL = max(dot(normal, lightDir), 0.0);
        diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;
       
        ambient = gl_FrontMaterial.ambient * gl_LightSource[0].ambient;
        globalAmbient = gl_LightModel.ambient * gl_FrontMaterial.ambient;
       
        gl_FrontColor =  NdotL * diffuse + globalAmbient + ambient;
       
        gl_Position = ftransform();
    }


Следующее изображение демонстрирует результат:




В следующем разделе будет описано specular-освещение.









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

Войдите, чтобы оставить комментарий:












Яндекс.Метрика
 Яндекс цитирования.