| Китай |
Свет и материалы в OpenGL
Источники света и их свойства
Дошла очередь и до рассмотрения источников света. Источники света характеризуются набором свойств, включая цвет, яркость, положение, ориентацию и т.д., которые могут очень сильно влиять на вид сцены. Свойства источников света, в нашем примере, устанавливаются функцией glLightfv(), которая вызывается несколько раз для настройки свойств источника, но каждый раз с разными аргументами настройки. В общем случае создания и настройки источников света имеет вид
void glLight{if}(GLenum light, GLenum pname, TYPE param);
void glLight{if}v(GLenum light, GLenum pname, TYPE *param);Параметр light имеет значения GL_LIGHT0, ..., GL_LIGHT7, которые определяют номерное имя создаваемого источника. Настраиваемое свойство указывается одним из значений перечисления pname, приведенных в таблице ниже. Аргумент param - это собственно значение настраиваемого свойства pname или указатель на набор значений (в векторной версии).
OpenGL поддерживает по меньшей мере 8 независимый источников света, расположенных в любых точках сцены или даже вне отображаемого (отсекающего) объема. Мы можем поместить источник света в бесконечности, сделав его лучи параллельными, или заставить близлежащий источник света излучать во все стороны. Можно установить источник света, излучающий в пределах заданного конуса, и приписать ему любые характеристики.
Но всегда следует помнить, что добавление каждого нового источника света и наделение его всякими (зачастую, не нужными) свойствами требует значительных вычислений при рисовании, т.е. существенно сказывается на производительности программы. Как видно из таблицы, OpenGL позволяет связать с каждым источником света три различных параметра цвета: GL_AMBIENT, GL_DIFFUSE, GL_SPECULAR.
Для того, чтобы использовать источники света, системе необходима дополнительная информация о нормалях к вершинам поверхностей. До сих пор мы эти нормали не вычисляли, хотя и строили освещенные сферы. Но нормали вычислялись неявно самой используемой нами сервисной функцией
glutSolidSphere(1.0, 20, 16);
Под нормалью к вершине поверхности подразумевается вектор, исходящий прочь от поверхности и перпендикулярный к семейству касательных, проведенных через вершину. Обычно используются единичные векторы нормали.
После создания и настройки источников света их необходимо включить с помощью команды glEnable(GL_LIGHTING), тем самым сообщив OpenGL о необходимости принимать во внимание при рисовании сцены условия освещенности.
Модель самолета с нулевым освещением (JetNight)
Приведем пример, когда OpenGl получила инструкцию учитывать освещение, но само освещение осталось не заданным.
-
Скопируйте
в новый файл JetNight.h содержимое
файла Jet.h
-
Добавьте
в коде файла JetNight.h к именам функций
и их прототипам окончание Night,
чтобы не было конфликта имен в проекте приложения, например,
для прототипов
|
void Jet() ; |
-> | void JetNight() ; |
|
void RenderSceneJet(void) ; |
-> |
void RenderSceneJetNight(void) ; |
|
void ChangeSizeJet(int, int) ; |
-> | void ChangeSizeJetNight(int, int) ; |
-
Поместите
в самое начало функции ChangeSizeJetNight() код
включения освещения
// Индивидуальные настройки освещения glEnable(GL_LIGHTING);
-
Добавьте
в файл LightAndMaterial.cpp код, подключающий
новое упражнение
// LightAndMaterial.cpp : Defines the entry point for the console application.
//
//**********************************************************
// Подключение стандартного файла с библиотекой OpenGL
#include "stdafx.h"
//**********************************************************
// Прототипы функций
void ExecuteMenu(int); // Контекстное меню первого уровня
void TimerFunc(int); // Обработчик события таймера
void SpecialKeys(int, int, int); // Обработка нажатия клавиш
void RenderScene(void); // Функция рендеринга
void ChangeSize(int, int); // Функция установки отсекающего объема
// Глобальная переменная выбранного варианта основного меню
int choice = 1;
// Глобальные переменные для создания вращения
// в градусах
GLfloat xRot = 0.0f;
GLfloat yRot = 0.0f;
GLfloat zRot = 0.0f;
GLint w, h; // Ширина и высота экрана
//**********************************************************
// Подключение файлов с упражнениями
#include "ColorCube.h" // Упражнение 1: "1) Куб цвета"
#include "Jet.h" // Упражнение 2: "2) Самолет без освещения"
#include "LightSphere.h" // Упражнение 3: "3) Рисование освещенной сферы"
#include "MultiMaterial.h" // Упражнение 4: "4) Рисование с разными материалами"
#include "ColorSphere.h" // Упражнение 5: "5) Способ согласования цветов"
#include "JetNight.h" // Упражнение 6: "6) Самолет с нулевым освещением"
//**********************************************************
// Функция обратного вызова обработки выбора пользователя
void ExecuteMenu(int choice)
{
// Сбрасываем углы вращения прежнего варианта
xRot = yRot = zRot = 0;
// Выключаем освещение
glDisable(GL_LIGHTING);
// Выключаем режим согласования цветов
glDisable(GL_COLOR_MATERIAL);
// Запоминаем выбор в глобальную переменную
::choice = choice;
switch(::choice)
{
case 1:
ChangeSizeColorCube(w, h);
break;
case 2:
ChangeSizeJet(w, h);
break;
case 3:
ChangeSizeLightSphere(w, h);
break;
case 4:
ChangeSizeMultiMaterial(w, h);
break;
case 5:
ChangeSizeColorSphere(w, h);
break;
case 6:
ChangeSizeJetNight(w, h);
break;
}
// Вызвать принудительно визуализацию
glutPostRedisplay();
}
//**********************************************************
// Функция обратного вызова для рисования сцены
void RenderScene(void)
{
// Сохранить прежние настройки OpenGL в стеке атрибутов
glPushAttrib(GL_LIGHTING_BIT);
switch(::choice)
{
case 1:
RenderSceneColorCube();
break;
case 2:
RenderSceneJet();
break;
case 3:
RenderSceneLightSphere();
break;
case 4:
RenderSceneMultiMaterial();
break;
case 5:
RenderSceneColorSphere();
break;
case 6:
RenderSceneJetNight();
break;
}
// Восстановить прежние настройки OpenGL из стека атрибутов
glPopAttrib();
}
//**********************************************************
// Вызывается библиотекой GLUT при изменении размеров окна
void ChangeSize(int width, int height)
{
w = width;
h = height;
switch(::choice)
{
case 1:
ChangeSizeColorCube(width, height);
break;
case 2:
ChangeSizeJet(width, height);
break;
case 3:
ChangeSizeLightSphere(width, height);
break;
case 4:
ChangeSizeMultiMaterial(width, height);
break;
case 5:
ChangeSizeColorSphere(width, height);
break;
case 6:
ChangeSizeJetNight(width, height);
break;
}
}
//**********************************************************
// Обработчик события таймера
void TimerFunc(int value)
{
glutPostRedisplay(); // Перерисовка сцены
glutTimerFunc(30, TimerFunc, 1); // Заряжаем новый таймер
}
//**********************************************************
// Управление с клавиатуры стрелками
// для задания новых значений матрицы поворота
void SpecialKeys(int key, int x, int y)
{
if(key == GLUT_KEY_UP) // Стрелка вверх
xRot -= 5.0f;
if(key == GLUT_KEY_DOWN)// Стрелка вниз
xRot += 5.0f;
if(key == GLUT_KEY_LEFT)// Стрелка влево
yRot -= 5.0f;
if(key == GLUT_KEY_RIGHT)// Стрелка вправо
yRot += 5.0f;
xRot = (GLfloat)((const int)xRot % 360);
yRot = (GLfloat)((const int)yRot % 360);
// Для упражнения 5 смены материала
if(key == GLUT_KEY_F1) // Меняем красный
{
diffuseMaterial[0] += 0.1;
*diffuseMaterial = *diffuseMaterial > 1.0 ? 0.0 : *diffuseMaterial;
glColor4fv(diffuseMaterial);
}
if(key == GLUT_KEY_F2) // Меняем зеленый
{
diffuseMaterial[1] += 0.1;
*(diffuseMaterial + 1) = diffuseMaterial[1] > 1.0 ? 0.0 : diffuseMaterial[1];
glColor4fv(diffuseMaterial);
}
if(key == GLUT_KEY_F3) // Меняем синий
{
diffuseMaterial[2] += 0.1;
*(diffuseMaterial + 2) = diffuseMaterial[2] > 1.0 ? 0.0 : diffuseMaterial[2];
glColor4fv(diffuseMaterial);
}
// Вызвать принудительно визуализацию с помощью RenderScene()
glutPostRedisplay();
}
//**********************************************************
void main(int argc, char* argv[])
{
glutInit(&argc, argv);
// Двойная буферизация, цветовая модель RGB, буфер глубины
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(300, 300); // Начальные размеры окна
glutCreateWindow("Свет и материалы"); // Заголовок окна
glutDisplayFunc(RenderScene); // Обновление сцены при разрушении окна
glutReshapeFunc(ChangeSize); // При изменении размера окна
glutTimerFunc(100, TimerFunc, 1); // Создали таймер
glutSpecialFunc(SpecialKeys); // Для управления с клавиатуры
// Создание меню и добавление опций выбора
glutCreateMenu(ExecuteMenu);
glutAddMenuEntry("1) Куб цвета", 1);
glutAddMenuEntry("2) Самолет без освещения", 2);
glutAddMenuEntry("3) Рисование освещенной сферы", 3);
glutAddMenuEntry("4) Рисование с разными материалами", 4);
glutAddMenuEntry("5) Способ согласования цветов (F1, F2, F3)", 5);
glutAddMenuEntry("6) Самолет с нулевым освещением", 6);
glutAttachMenu(GLUT_RIGHT_BUTTON);// Присоединяем
// Конец создания меню
glutMainLoop(); // Цикл сообщений графического окна
}
Листинг
23.23.
Код подключения модели самолета с нулевым освещением в файле LightAndMaterial.cpp
-
Запустите
приложение и выполните упражнение 6, результат должен быть
примерно таким, как на первом рисунке
Обратите внимание, что объект остается абсолютно неосвещенным только тогда, когда мы вызываем упражнение 6 первым после запуска приложения. После выполнения других упражнений, где задаются источники света и материалы, мы уже не получим абсолютно неосвещенного объекта в упражнении 6, поскольку OpenGL приобретет от других упражнений некоторые настройки на использование освещения.



