Основы освещения в OpenGL (код - C/C++)

Блоговая публикация пользователя: isaer Эта публикация была перенесена из личного блога пользователя в общие разделы уровок сайта.

Основы освещения в OpenGL

Часть 1. Подготовка

Для изучения освещения необходимы:
  • OpenGL;
  • glut;
  • IDE, хотя можно воспользоваться gedit или CodeBlocks;
  • компилятор, например, gcc для Linux и mingw для Windows;
Часть 2. Пример простой программы
Рассмотрим пример программы, в которой используется освещение.

Код:
/*http://esate.ru, isaer*/

#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. Разбор кода в примере

Комментарии даны через символ // - "слэш".

Код:
/*http://esate.ru, isaer*/

void init()
{
    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); //делам нормали одинаковой величины во избежание артефактов
}


Здесь инициализируется освещение

Код:
/*http://esate.ru, isaer*/

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); // разрешаем использовать light0

    glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse); // устанавливаем источнику света light0 диффузный свет, который указали ранее 
    glLightfv(GL_LIGHT0, GL_POSITION, light0_direction); // устанавливаем направление источника света, указанное ранее 
}

Здесь происходит вся прорисовка.

Код:
/*http://esate.ru, isaer*/

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();
}

Часть 4. Изучаем освещение

Сначала включим расчет освещения командой glEnable(GL_LIGHTING). Затем надо разблокировать источник света командой glEnable(GL_LIGHT). GL_LIGHT может принимать только 8 значений (по крайней мере в OpenGL 2.1), то есть GL_LIGHT0..GL_LIGHT7.

Теперь надо создать источник света. У каждого источника света есть свои параметры по умолчанию, например, если вы просто разблокируете 2 источника света GL_LIGHT0 и GL_LIGHT1, то будет виден только 0, так как в нем параметры по умолчанию отличаються от остальных (у всех остальных они идентичны).

Источники света имеют несколько параметров, а именно: цвет, позиция и направление.

Команда, используемая для указания всех параметров света – это glLight*(). Она принимает три аргумента: идентификатор источника света, имя свойства и желаемое для него значение.

Код:
/*http://esate.ru, isaer*/

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 представляет собой вектор величин.

Например:

Код:
/*http://esate.ru, isaer*/

float light_ambient[] = {0.0,0.0,0.0,1.0};
glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);

Если нет, то тогда это единственное значение.

Например:

Код:
/*http://esate.ru, isaer*/

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), то это значит, что первая скобка - это значение по умолчанию для нулевого источника, а вторая скобка - для остальных:

Код:
/*http://esate.ru, isaer*/

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
Квадратичный фактор ослабления


Пример использования освещения:

Код:
/*http://esate.ru, isaer*/

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. Позиция

Параметр GL_POSITION (x, y, z, w) имеет 3 значения положения и одно, указывающее на то, какой источник света будет использоваться.

Первые 3 (x, y, z) параметра понятны, а 4-й (w) параметр указывает, будет ли использоваться бесконечно удаленный свет или точечный. Если значение 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.

Но так не очень удобно, поэтому можно воспользоваться формулой:

Код:
/*http://esate.ru, isaer*/

Fatt = 1 / (Kc + Kl * d + Kq  * (d * d))

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

d - расстояние между позицией источника света и точкой.

Kc - GL_CONSTANT_ATTENUATION, постоянный фактор ослабления.

Kl - GL_LINEAR_ATTENUATION, линейный фактор ослабления.

Kq - GL_QUADRATIC_ATTENUATION, квадратичный фактор ослабления.

Если вы не совсем поняли, как это применить, обратите внимание на эту заготовку:

Код:
/*http://esate.ru, isaer*/

   
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*() – это команда, используемая для задания всех параметров модели освещения. Может принимать два аргумента: имя параметра модели освещения в виде константы и значение для этого параметра.

Код:
/*http://esate.ru, isaer*/

void glLightModel{if} (GLenum pname, TYPE param);
void glLightModel{if}v (GLenum pname, TYPE *param); 

Устанавливаемая характеристика модели освещения определяется аргументом pname; param задает величину, в которую устанавливается pname.

Код:
/*http://esate.ru, isaer*/

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
вычисляется ли зеркальный цвет отдельно от фонового и диффузного


Теперь вы можете создавать отличные источники света.

Нет доступа к просмотру комментариев.

^