теория, алгоритмы, примеры на С++ и 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 ();

}

 

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


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

 

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