GLSL: Практика: Toon-шейдер — Версия III

Прежде, чем закончить эти уроки, сделаем ещё одну вещь: используем свет OpenGL вместо переменной lightDir. Таким образом мы сможем объявлять свет в OpenGL и использовать его направление в шейдерах. Учтите, включать освещение в OpenGL функцией glEnable нет необходимости, так как мы не будем использовать глобальное освещение OpenGL.

Мы обьявим первый источник света в OpenGL (GL_LIGHT0) как направленный свет.

GLSL предоставляет доступ к части функционала OpenGL, в том числе — к параметрам освещения. В GLSL обьявлена структура для данных света, и массив для хранения структур всех источников света.


struct gl_LightSourceParameters {
vec4 ambient;
vec4 diffuse;
vec4 specular;
vec4 position;
...
};

uniform gl_LightSourceParameters gl_LightSource[gl_MaxLights];


Это значит, что у нас есть доступ к направлению света (поле position для направленного источника) в вершинном шейдере. Опять же, направление света должно быть нормализовано в приложении OpenGL.

Спецификация OpenGL указывает, что когда инициализируется источник света, его позиция автоматически устанавливается в позицию нашего «глаза» — камеры. При этом вектор его направления нормализован (если мы остаемся в ортогональной матрице 3×3, а при использовании gluLookAt () это мы в ней, пока не используем glScalef () и другие scalers).

Нам нужно конвертировать нормаль в координаты нашего «взгляда», чтобы вычислить dot product и др.

Чтобы трансформировать нормаль в координаты «взгляда», мы используем заранее объявленную uniform-переменную mat3 gl_NormalMatrix. Эта матрица — результат инвертирования 3×3 право-верхней саб-матрицы из матрицы моделей. Сделаем трансформацию нормалей на каждую вершину. Таким образом вершинный шейдер получится таким:

Файл toon.vert

    varying vec3 normal;

void main()
{

normal = gl_NormalMatrix * gl_Normal;

gl_Position = ftransform();
}

 

В пикселном шейдере нам нужно получить доступ к позиции источника света, чтобы вычислить интенсивность.

Файл toon.frag:

    varying vec3 normal;

void main()
{
float intensity;
vec4 color;
vec3 n = normalize(normal);

intensity = dot(vec3(gl_LightSource[0].position),n);

if (intensity > 0.95)
color = vec4(1.0,0.5,0.5,1.0);
else if (intensity > 0.5)
color = vec4(0.6,0.3,0.3,1.0);
else if (intensity > 0.25)
color = vec4(0.4,0.2,0.2,1.0);
else
color = vec4(0.2,0.1,0.1,1.0);

gl_FragColor = color;
}

 

Ну а теперь перейдём к коду программы. Возьмите его из первого практического урока.

Файл main.cpp:

// В самом начале добавим поддержку библиотеки glut:
#pragma comment (lib, «glut32.lib»)
#include <gl/glut.h>// Инициализируем переменные:
GLuint v,f,f2,p;        // Дескрипторы программ и шейдеров
float lpos[4] = {1,0.5,1,0};    // Позиция источника света
float a = 0;            // Хранит угол вращения///////////////////////////////////////////////////
// В функции setShaders () изменим, название файлов шейдеров:
vs = textFileRead(«toon.vert»);
fs = textFileRead(«toon.frag»);

// Теперь в функцию RenderScene () добавим создание чайника:
glutSolidTeapot(1);

 

Всё, компилируем и смотрим результат.
Скачайте и посмотрите исходники, если что-то пойдет не так.

Исходные коды к уроку

Понравилась статья? Поделиться с друзьями: