Урок 2. Основы освещения в OpenGL
Ну вот наконец-то и пришел 2 урок =). Задержался он немного, так как были проблемы с жестким диском и с инетом. Но вот вышел второй урок =). В этом уроке я раскажу про освещение.
Часть 1. Подготавливаемся
Что нам нужно для того, чтобы изучать освещение? Нам нужны:
—
OpenGL(как же без него);
—
glut;
—
IDE (хотя можно и без него, я, например, пишу все свои программы в gedit (что то вроде блокнота на винде только круче), иногда в CodeBlocks (ну это только если проект большой, чтобы легче было) );
— ну и конечно нужен компилятор (как же без него), я использую компилятор
gcc для Linux и
mingw для Windows;
— и еще очень пригодится
желание учиться (без него никак).
Часть 2. Пример простой программы
Тут я просто напишу пример программы, в которой используется освещение.
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
void init()
{
glClearColor(0.3, 0.3, 0.3, 1.0);
glEnable(GL_LIGHTING);
glLightModelf(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
glEnable(GL_NORMALIZE);
}
void reshape(int width, int height)
{
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1.2, 1.2, -1.2, 1.2, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void init_l()
{
float light0_diffuse[] = {0.4, 0.7, 0.2};
float light0_direction[] = {0.0, 0.0, 1.0, 0.0};
glEnable(GL_LIGHT0);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);
glLightfv(GL_LIGHT0, GL_POSITION, light0_direction);
}
void display()
{
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
init_l();
GLfloat x, y;
glBegin(GL_QUADS);
glNormal3f(0.0, 0.0, -1.0);
for (x = -1.0; x < 1.0; x += 0.005)
{
for (y = -1.0; y < 1.0; y += 0.005)
{
glVertex3f(x, y, 0.0);
glVertex3f(x, y + 0.005, 0.0);
glVertex3f(x + 0.005, y + 0.005, 0.0);
glVertex3f(x + 0.005, y, 0.0);
}
}
glEnd();
glDisable(GL_LIGHT0);
glutSwapBuffers();
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowPosition(50, 100);
glutInitWindowSize(500, 500);
glutCreateWindow("Light");
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
}
Код без коментариев так что то бы понять суть освещения нодо читать дальше =)
Часть 3. Небольшой разбор примера
Начнем разирать код примера.
Я все не буду пояснять, так как почти все есть в предыдушем уроке.
void init()
{
glClearColor(0.3, 0.3, 0.3, 1.0);
glEnable(GL_LIGHTING);
glLightModelf(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
glEnable(GL_NORMALIZE);
}
Тут мы инициализируем всякое =)
glClearColor(0.3, 0.3, 0.3, 1.0); //очищаем экран в цвет, установленый параметрами r,g,b,a
glEnable(GL_LIGHTING); //тут мы включаем расчет освещения
glLightModelf(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);//делаем так, чтобы освещались обе стороны полигона
glEnable(GL_NORMALIZE);//делам нормали одинаковой величины во избежание артефактов
void init_l()
{
float light0_diffuse[] = {0.4, 0.7, 0.2};
float light0_direction[] = {0.0, 0.0, 1.0, 0.0};
glEnable(GL_LIGHT0);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);
glLightfv(GL_LIGHT0, GL_POSITION, light0_direction);
}
Здесь инициализируется освещение.
float light0_diffuse[] = {0.4, 0.7, 0.2};//устанавливаем диффузный цвет света
float light0_direction[] = {0.0, 0.0, 1.0, 0.0};//устанавливаем направление света
glEnable(GL_LIGHT0);//разрешаем использовать light0
glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);//устанавливаем источнику света light0 диффузный свет, который указали ранее
glLightfv(GL_LIGHT0, GL_POSITION, light0_direction);//устанавливаем направление источника света указанным ранее
void display()
{
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
init_l();
GLfloat x, y;
glBegin(GL_QUADS);
glNormal3f(0.0, 0.0, -1.0);
for (x = -1.0; x < 1.0; x += 0.005)
{
for (y = -1.0; y < 1.0; y += 0.005)
{
glVertex3f(x, y, 0.0);
glVertex3f(x, y + 0.005, 0.0);
glVertex3f(x + 0.005, y + 0.005, 0.0);
glVertex3f(x + 0.005, y, 0.0);
}
}
glEnd();
glDisable(GL_LIGHT0);
glutSwapBuffers();
}
Здесь происходит вся прорисовка.
init_l();//выполняем инициализацию освещения
GLfloat x, y;//высота и ширина плоскости
glBegin(GL_QUADS);//начинаем рисовать плоскость
glNormal3f(0.0, 0.0, -1.0);//указываем направление нормалей (это обязательно)
//тут рисуем плоскость
glEnd();//закончили рисовать
glDisable(GL_LIGHT0);//отключаем освещение
Ну, вот вроде с примером разобрались. Далее будем изучать освещение.
Часть 4. Изучаем освещение
Вначале включим расчет освещения командой glEnable(GL_LIGHTING);
далее надо разблокировать источник света командой glEnable(GL_LIGHT);
GL_LIGHT может принимать только 8 значений (по крайней мере в OpenGL 2.1, как и у меня), то есть GL_LIGHT0..GL_LIGHT7.
Теперь надо создать источник света. У каждого источника света есть свои параметры по умолчанию, например, если вы просто разблокируете 2 источника света GL_LIGHT0 и GL_LIGHT1, то будет виден только 0, так как в нем параметры по умолчанию отличаються от остальных (у всех остальных они идентичны).
Источники света имеют несколько параметров, таких как: цвет, позиция и направление.
Команда, используемая для указания всех параметров света – это glLight*(). Она принимает три аргумента: идентификатор источника света, имя свойства и желаемое для него значение.
void glLight{if} (GLenum light, GLenum pname, TYPE param);
void glLight{if}v (GLenum light, GLenum pname, TYPE *param);
GLenum light — это выбор источника, например, GL_LIGHT0
GLenum pname — это параметры источника света (далее будут приведены все ее параметры)
TYPE param — это значение, которое принимает GLenum pname
Если у вас стоит void glLight{if}v (GLenum light, GLenum pname, TYPE *param), значит используется векторная версия команды; param представляет собой вектор величин.
Например:
float light_ambient[] = {0.0,0.0,0.0,1.0};
glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
Или, если нет, то тогда это единственное значение.
Например:
glLightf(GL_LIGHT0, GL_GL_SPOT_CUTOFF, 180);
Вот листинг значений
GLenum pname
(читаеться так: первая строчка — это название параметра, вторая — это значение поумолчанию и третья — это пояснение; если вы видите что-то типа (1.0,1.0,1.0,1.0) или (0.0,0.0,0.0,1.0), то это значит, что первая скобка — это значение по умолчанию для нулевого источника, а вторая скобка — это для остальных):
GL_AMBIENT
(0.0,0.0,0.0,1.0)
Интенсивность фонового света
GL_DIFFUSE
(1.0,1.0,1.0,1.0)
или
(0.0,0.0,0.0,1.0)
Интенсивность диффузного света (значение по умолчанию
для 0-го источника - белый свет, для остальных - черный)
GL_SPECULAR
(1.0,1.0,1.0,1.0)
или
(0.0,0.0,0.0,1.0)
Интенсивность зеркального света (значение по умолчанию для 0-го источника - белый свет, для остальных - черный)
GL_POSITION
(0.0,0.0,1.0,0.0)
Положение источника света (x,y,z,w)
GL_SPOT_DIRECTION
(0.0,0.0,-1.0)
Направление света прожектора (x,y,z)
GL_SPOT_EXPONENT
0.0
Концентрация светового луча
GL_SPOT_CUTOFF
180.0
Угловая ширина светового луча
GL_CONSTANT_ATTENUATION
1.0
Постоянный фактор ослабления
GL_LINEAR_ATTENUATION
0.0
Линейный фактор ослабления
GL_QUADRATIC_ATTENUATION
0.0
Квадратичный фактор ослабления
вот пример использования освещения:
float light_ambient[] = {0.0,0.0,0.0,1.0};
float light_diffuse[] = {1.0,1.0,1.0,1.0};
float light_specular[] = {1.0,1.0,1.0,1.0};
float light_position[] = {1.0,1.0,1.0,0.0};
glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
Часть 5. Изучаем параметры света
1.Цвет
Diffuse
Параметр GL_DIFFUSE, наверное, наиболее точно совпадает с тем, что вы привыкли называть «цветом света». Он определяет RGBA цвет диффузного света, который отдельный источник света добавляет к сцене.
Ambient
Параметр GL_AMBIENT влияет на цвет зеркального блика на объекте. В реальном мире на объектах вроде стеклянной бутылки имеется зеркальный блик соответствующего освещению цвета (часто белого).
Specular
Параметр GL_SPECULAR влияет на интенсивность зеркального блика на объектах.
2.Позиция
Position
Параметр GL_POSITION имеет 3 значения положения и одно, указывающее на то, какой источник света будет использоваться.
GL_POSITION (x,y,z,w)
Первые 3 параметра понятны — это положение, а вот 4-й параметр указывает, будет ли использоваться бесконечно удаленный свет или точечный. Если значение w = 0, то источник света бесконечно удаленный (что-то вроде солнца). Если w = 1, то этот источник света точечный (что то вроде лампочки).
Если w = 0, то первые 3 параметра — это вектор от центра системы координат (0,0,0).
3.Прожектор
GL_SPOT_DIRECTION
Направление света прожектора
GL_SPOT_EXPONENT
Концентрация светового луча
GL_SPOT_CUTOFF
Угловая ширина светового луча
Я думаю тут все понятно, единственное, нужно уточнить, что позиция должна быть с w = 1.
4.Ослабление
Если вам нужно ослаблять интенсивность света от центра(тоесть чем дальше от центра, тем тускнее), то вам надо настроить параметры: GL_CONSTANT_ATTENUATION, GL_LINEAR_ATTENUATION, GL_QUADRATIC_ATTENUATION.
Но так не удобно и можно расчитать по формуле:
Fatt = 1 / (Kc + Kl * d + Kq * (d * d))
где:
d — расстояние между позицией источника света и точкой где конец,
Kc — GL_CONSTANT_ATTENUATION (постоянный фактор ослабления),
Kl — GL_LINEAR_ATTENUATION (линейный фактор ослабления),
Kq — GL_QUADRATIC_ATTENUATION (квадратичный фактор ослабления).
Если вы не совсем поняли, как это применить, то у меня уже есть готовая заготовка:
float kQ;
float kL;
float kC;
float radius;
float att;
attn = 1;
radius = 5;
kQ = att / (3* radius * radius);
kL = att / (3 * radius);
kC = att / 3;
glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, kC);
glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, kL);
glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, kQ);
Тут вы задаете радиус от центра до конца =)
Также, если вам надо уменьшить общую интенсивность, вы можете изменить параметр att
Часть 6. Выбор модели освещения
OpenGL понятие модели освещения разделяется на 4 компонента:
-Интенсивность глобального фонового света.
-Считается ли положение точки наблюдения локальным к сцене или бесконечно удаленным.
-Должен ли расчет освещенности производиться по-разному для лицевых и обратных граней объектов.
-Должен ли зеркальный цвет отделяться от фонового и диффузного и накладываться на объект после операций текстурирования.
glLightModel*() – это команда, используемая для задания всех параметров модели освещения. glLightModel*() принимает два аргумента: имя параметра модели освещения в виде константы и значение для этого параметра.
void glLightModel{if} (GLenum pname, TYPE param);
void glLightModel{if}v (GLenum pname, TYPE *param);
Устанавливаемая характеристика модели освещения определяется аргументом pname; param задает величину, в которую устанавливается pname.
GL_LIGHT_MODEL_AMBIENT
(0.2,0.2,0.2,1.0)
RGBA интенсивность всей сцены
GL_LIGHT_MODEL_LOCAL_VIEWER
0.0 или GL_FALSE
способ вычисления углов зеркального отражения
GL_LIGHT_MODEL_TWO_SIDE
0.0 или GL_FALSE
выбор между односторонним и двухсторонним освещением
GL_LIGHT_MODEL_COLOR_CONTROL
GL_SINGLE_COLOR
вычисляется ли зеркальный цвет отдельно от фонового и диффузного
Часть 7. Заключение
Ну вот и все, с освещением закончили =)
Теперь вы можете создавать отличные источники света.
Вот тут есть отличный пример использования всех источников света, найденый мною в недрах интернета.
Lesson2_Light(Linux, Windows).
В архиве лежит исходный код программы (мною подредактированый) и исполняемые файлы под Linux и под Windows.
Также, если вы компилируете под Windows с помощю компилятора mingw, то там компиляция немного отличается.Надо писать:
i586-mingw32msvc-g++ file.cpp -lopengl32 -lglu32 -lglut32win -o file.exe
Также вам надо будет скачать библиотеку glut для mingw (в гугле есть точно),
а если под линукс с помощью gcc, то там как обычно:
g++ file.cpp -lglut -lGLU -o file
Комментарии (21)
rss свернуть / развернутьсвернуть ветку
свернуть ветку
Только код без комментариев меня немного смутил :) Все таки не для профи пишем, а для людей, которым что-то не ясно, которые разобраться хотят (имхо).
свернуть ветку
там вначале пример весь закоментирован
да и дальше почти каждую строчку пояснял
если что не так то напиши что исправить я подправлю
свернуть ветку
Просто в самом коде комментов нет и если кто-то очень ленивый вначале копи-пастит, а потом только разбираться начинает, то туго ему бедненькому придется :)
Хотя это уже его проблемы мы для лентяев не стараемся :)))
Кстати по-поводу лентяев, а у тебя есть такой же код только на C#? :)))
свернуть ветку
так а там изменять почти ничего не надо
только перед gl ставить GL. и все (вроде)
я на шарпе уже давно не программировал
так как мне больше С++ понравился =)
хотя так скучаю по формачкам и кнопочкам =)
свернуть ветку
Там перед каждым из параметров внутри функции например glutInitDisplayMode(...) или др. нужно Gl. ставить. Ну ни чего, блокнот мне в руки ;)
свернуть ветку
ты скачай пример, там класно =) мне понравился
правда я там убрал один прикол
а зря, с ним лучше было, ты просто делай так:
напиши в первой строчке GL. и скопируй ее и потом просто везде Ctrl + V
ну и на стрклочках строчку ниже и Home чт бы в начало строчки
там быстро тогда
свернуть ветку
ты сделай на консоле, почти ничего не надо
и вобще чет меня занесло, может ты не про пример тот говоришь =))
там просто есть исполняемый файл для винды и для линукса
свернуть ветку
Кстати, если захочешь, когда код будет готов я могу тебе скинуть (или сразу Anvi), чтобы он в конце урока ссылку на C#+TaoFramework проект сделал. Мало ли, вдруг людям пригодится :)
свернуть ветку
свернуть ветку
Еще, просьба ко всем, кто создает новые уроки, ознакомиться с пожеланиями к урокам. Это поможет не упустить несколько важных вещей для создания качественных, полных уроков.
свернуть ветку
свернуть ветку
свернуть ветку
Ща попробую в mingw, а то у меня OGl там не компилился. После чего, я mingw и забросил.
Побольше бы Linux-а в нашу жизнь!;)))
свернуть ветку
может быть когда нить сделаю что нить по типу блога про линукс =) там как компилировать в разных средах, как подключать файлы, Makefiles
сейчас просто времени не очень много
но вскоре думаю сделаю
свернуть ветку
свернуть ветку
свернуть ветку
Это очень классно.
Буду надеяться на то, что времени у тебя станет побольше.))
Ну и у меня заодно)))
свернуть ветку
вот смотрю я тут и не могу понять к чему эти разные приставки например
m_Surface — что означает эта m_ ??
и какие еще приставки знаете? а то я как то все называю без приставок, может если кто читает и ему будет с приставками понятнее
свернуть ветку
свернуть ветку