теория, алгоритмы, примеры на С++ и OpenGL  

Мы vkontakte.ru


Rambler's Top100 Rambler's Top100
Каталог@Mail.ru - каталог ресурсов интернет

Друзья

Словарь синонимов русского языка

Источники света

После того, как задана необходимая геометрия (нормали) необходимо разместить на сцене один или несколько источников света, настроить их свойства и включить их. В зависимости от реализации OpenGL на сцене могут присутствовать восемь и более источников света. Включить нулевой источник света можно командой:

    	glEnable(GL_LIGHT0);

Остальные включаются аналогичным способом, где вместо GL_LIGHT0 указывается GL_LIGHTi. После того, как источник включен, необходимо задать его параметры. В OpenGL существует три типа источников света:

  • источник направленного света: расположен в бесконечности и имеет выделенное направление освещения.
  • точечный источник света: расположен в конкретной точке пространства и светит равномерно во всех направлениях. Для него можно задать эффект затухания света с расстоянием.
  • прожектор: является частным случаем точечного источника, но свет от него распространяется только внутри ограничивающего конуса, а не по всем направлениям.

Для управления свойствами источника света используются команды glLight*:

	glLightf(GLenum light, GLenum pname, GLfloat param);
	glLightfv(GLenum light, GLenum pname, const GLfloat *param);

Параметр light указывает OpenGL для какого источника света задаются параметры. Команда glLightf используется для задания скалярных параметров, а glLightfv используется для задания векторных характеристик источников света.

Задание компонент излучения

Для источника света можно задать фоновую, рассеянную и зеркальную компоненты излучения.

Параметр pname команды glLightfv

Имя параметра Значение по умолчанию

Краткий комментарий

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)
цвет рассеянного излучения источника света (значение по умолчанию для GL_LIGHT0 - белый, для остальных - черный)
GL_SPECULAR
(1.0, 1.0, 1.0, 1.0)
        или
(0.0, 0.0, 0.0, 1.0)
цвет зеркального излучения источника света (значение по умолчанию для GL_LIGHT0 - белый, для остальных - черный)

Остальные параметры являются специфическими для каждого типа источников света, описанных ниже.

Источники направленного света

Источника света такого типа находится в бесконечности и свет от него распространяется в заданном направлении. Идеально подходит для создания равномерного освещения. Хорошим примером источника направленного света может служить Солнце. У источника направленного света, кроме компонент излучения, можно задать только направление.

Параметр pname команды glLightfv

Имя параметра Значение по умолчанию

Краткий комментарий

GL_POSITION
(0.0, 0.0, 1.0, 0.0)
(x, y, z, w) направление источника направленного света

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

Точечные источники света

Точечный источник света расположен в некоторой точке пространства и излучает во всех направлениях. Т.к. расстояние между источником и освещаемой точкой конечно, то можно задать закон убывания интенсивности излучения с расстоянием. Стандартные средства OpenGL позволяют задавать такой закон в виде обратно-квадратичной функции от расстояния:

f_{att}(d)=\frac{1}{k_{const} + k_{linear}d + k_{quadratic}d^2}

Т.о. для точечного источника света, кроме свойств излучения, можно задать ещё четыре параметра:

Параметр pname команды glLightfv

Имя параметра Значение по умолчанию

Краткий комментарий

GL_POSITION
(0.0, 0.0, 1.0, 0.0)
позиция источника света (по умолчанию источник света направленный)
GL_CONSTANT_ATTENUATION
1.0
постоянная k_const в функции затухания f(d)
GL_LINEAR_ATTENUATION
0.0
коэффициент k_linear при линейном члене в функции затухания f(d)
GL_QUADRATIC_ATTENUATION
0.0
коэффициент k_quadratic при квадрате расстояния в функции затухания f(d)

Как видно из таблицы, по умолчанию, интенсивность света не убывает с расстоянием.

Прим. Позиция источника света (в случае направленного источника - направление) задается в текущей модельной системе координат. Например, после выполнения кода:

      glPushMatrix();
      glLoadIdentity();
      glTranslatef(1.0, 1.0, 1.0);
      GLfloat light0_position[] = { 0.0, 0.0, 0.0, 1.0 };
      glLightfv(GL_LIGHT0, GL_POSITION, light0_position);
      glPopMatrix();

 

нулевой источник света будет расположен в точке (1.0, 1.0, 1.0) во внешней (мировой) системе координат.

Прожекторы

Одной из разновидностей точечного источника является прожектор. Для него применимы все параметры, что и для точечного источника, но кроме того прожектор позволяет ограничить распространение света конусом. Для этого конуса можно задать коэффициент убывания интенсивности, в зависимости от угла между осью конуса и лучом распространения света.

Прожектор (spotlight) в OpenGL

Параметры, специфические для прожектора:

Параметр pname команды glLightfv

Имя параметра Значение по умолчанию

Краткий комментарий

GL_SPOT_DIRECTION
(0.0, 0.0, -1.0)
(x, y, z) - направление прожектора (ось ограничивающего конуса)
GL_SPOT_CUTOFF
180.0
угол между осью и стороной конуса (он же половина угла при вершине)
GL_SPOT_EXPONENT
0.0
экспонента убывания интенсивности

Пример кода

#include <GL/glut.h>

#include <math.h>

 

#define PI 3.141592653

 

int light_sample = 1;

 

// инициализация

void init (void)

{

      // цвет фона

      glClearColor (0.3, 0.3, 0.3, 0.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 display(void)

{

      // очищаем буфер кадра и глубины

      glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

      // свойства материала

      GLfloat material_diffuse[] = {1.0, 1.0, 1.0, 1.0};

      glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, material_diffuse);

      // установка источников света

      if (light_sample == 1)

      {

            // направленный источник света

            GLfloat light0_diffuse[] = {0.4, 0.7, 0.2};

            GLfloat 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);

      }

      if (light_sample == 2)

      {

            // точечный источник света

            // убывание интенсивности с расстоянием

            // отключено (по умолчанию)

            GLfloat light1_diffuse[] = {0.4, 0.7, 0.2};

            GLfloat light1_position[] = {0.0, 0.0, 1.0, 1.0};

            glEnable(GL_LIGHT1);

            glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_diffuse);

            glLightfv(GL_LIGHT1, GL_POSITION, light1_position);

      }

      if (light_sample == 3)

      {

            // точечный источник света

            // убывание интенсивности с расстоянием

            // задано функцией f(d) = 1.0 / (0.4 * d * d + 0.2 * d)

            GLfloat light2_diffuse[] = {0.4, 0.7, 0.2};

            GLfloat light2_position[] = {0.0, 0.0, 1.0, 1.0};

            glEnable(GL_LIGHT2);

            glLightfv(GL_LIGHT2, GL_DIFFUSE, light2_diffuse);

            glLightfv(GL_LIGHT2, GL_POSITION, light2_position);

            glLightf(GL_LIGHT2, GL_CONSTANT_ATTENUATION, 0.0);

            glLightf(GL_LIGHT2, GL_LINEAR_ATTENUATION, 0.2);

            glLightf(GL_LIGHT2, GL_QUADRATIC_ATTENUATION, 0.4);

      }

      if (light_sample == 4)

      {

            // прожектор

            // убывание интенсивности с расстоянием

            // отключено (по умолчанию)

            // половина угла при вершине 30 градусов

            // направление на центр плоскости

            GLfloat light3_diffuse[] = {0.4, 0.7, 0.2};

            GLfloat light3_position[] = {0.0, 0.0, 1.0, 1.0};

            GLfloat light3_spot_direction[] = {0.0, 0.0, -1.0};

            glEnable(GL_LIGHT3);

            glLightfv(GL_LIGHT3, GL_DIFFUSE, light3_diffuse);

            glLightfv(GL_LIGHT3, GL_POSITION, light3_position);

            glLightf(GL_LIGHT3, GL_SPOT_CUTOFF, 30);

            glLightfv(GL_LIGHT3, GL_SPOT_DIRECTION, light3_spot_direction);

      }

      if (light_sample == 5)

      {

            // прожектор

            // убывание интенсивности с расстоянием

            // отключено (по умолчанию)

            // половина угла при вершине 30 градусов

            // направление на центр плоскости

            // включен рассчет убывания интенсивности для прожектора

            GLfloat light4_diffuse[] = {0.4, 0.7, 0.2};

            GLfloat light4_position[] = {0.0, 0.0, 1.0, 1.0};

            GLfloat light4_spot_direction[] = {0.0, 0.0, -1.0};

            glEnable(GL_LIGHT4);

            glLightfv(GL_LIGHT4, GL_DIFFUSE, light4_diffuse);

            glLightfv(GL_LIGHT4, GL_POSITION, light4_position);

            glLightf(GL_LIGHT4, GL_SPOT_CUTOFF, 30);

            glLightfv(GL_LIGHT4, GL_SPOT_DIRECTION, light4_spot_direction);

            glLightf(GL_LIGHT4, GL_SPOT_EXPONENT, 15.0);

      }

      if (light_sample == 6)

      {

            // несколько источников света

            GLfloat light5_diffuse[] = {1.0, 0.0, 0.0};

            GLfloat light5_position[] = {0.5 * cos(0.0), 0.5 * sin(0.0), 1.0, 1.0};

            glEnable(GL_LIGHT5);

            glLightfv(GL_LIGHT5, GL_DIFFUSE, light5_diffuse);

            glLightfv(GL_LIGHT5, GL_POSITION, light5_position);

            glLightf(GL_LIGHT5, GL_CONSTANT_ATTENUATION, 0.0);

            glLightf(GL_LIGHT5, GL_LINEAR_ATTENUATION, 0.4);

            glLightf(GL_LIGHT5, GL_QUADRATIC_ATTENUATION, 0.8);

            GLfloat light6_diffuse[] = {0.0, 1.0, 0.0};

            GLfloat light6_position[] = {0.5 * cos(2 * PI / 3), 0.5 * sin(2 * PI / 3), 1.0, 1.0};

            glEnable(GL_LIGHT6);

            glLightfv(GL_LIGHT6, GL_DIFFUSE, light6_diffuse);

            glLightfv(GL_LIGHT6, GL_POSITION, light6_position); 

            glLightf(GL_LIGHT6, GL_CONSTANT_ATTENUATION, 0.0);

            glLightf(GL_LIGHT6, GL_LINEAR_ATTENUATION, 0.4);

            glLightf(GL_LIGHT6, GL_QUADRATIC_ATTENUATION, 0.8);

            GLfloat light7_diffuse[] = {0.0, 0.0, 1.0};

            GLfloat light7_position[] = {0.5 * cos(4 * PI / 3), 0.5 * sin(4 * PI / 3), 1.0, 1.0};

            glEnable(GL_LIGHT7);

            glLightfv(GL_LIGHT7, GL_DIFFUSE, light7_diffuse);

            glLightfv(GL_LIGHT7, GL_POSITION, light7_position); 

            glLightf(GL_LIGHT7, GL_CONSTANT_ATTENUATION, 0.0);

            glLightf(GL_LIGHT7, GL_LINEAR_ATTENUATION, 0.4);

            glLightf(GL_LIGHT7, GL_QUADRATIC_ATTENUATION, 0.8);

      }

      // плоскость

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

      glDisable(GL_LIGHT1);

      glDisable(GL_LIGHT2);

      glDisable(GL_LIGHT3);

      glDisable(GL_LIGHT4);

      glDisable(GL_LIGHT5);

      glDisable(GL_LIGHT6);

      glDisable(GL_LIGHT7);

      // элемент двойной буферизации

      glutSwapBuffers();

}

 

void keyboard_function(unsigned char key, int x, int y)

{

      if (key == '1') light_sample = 1;

      if (key == '2') light_sample = 2;

      if (key == '3') light_sample = 3;

      if (key == '4') light_sample = 4;

      if (key == '5') light_sample = 5;

      if (key == '6') light_sample = 6;

      glutPostRedisplay();

}

 

void main (int argc, char** argv)

{

      glutInit (&argc, argv);

      glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);

      glutInitWindowPosition (50, 100);

      glutInitWindowSize (500, 500);

      glutCreateWindow ("4.4. Пример установки источников света в OpenGL. (с) compgraphics.info");

      init();

      glutDisplayFunc(display);

      glutReshapeFunc(reshape);

      glutKeyboardFunc(keyboard_function);

      glutMainLoop ();

}

 

Направленный источник свет Точечный источник света, убывание интенсивности с расстоянием выключено Точечный источник света, убывание интенсивности с расстоянием включено
Направленный источник света
Точечный источник света, убывание интенсивности с расстоянием выключено
Точечный источник света, убывание интенсивности с расстоянием включено


Прожектор Прожектор, включен рассчет убывания интенсивности для прожектора Несколько источников света
Прожектор
Прожектор, включен расчет убывания интенсивности для прожектора
Несколько источников света

 

Скачать исходный текст демонстрационной программы

 

 

Кулагин Денис
21 сентября 2008