- •Часть II. Основы программирования
- •Введение
- •Лекция 1. Библиотека OpenGl
- •1. Назначение библиотеки OpenGl
- •2. Основные возможности OpenGl
- •3. Макет консольного приложения, использующего библиотеку glaux
- •Программа 1.1
- •4. Имена функций OpenGl
- •5. Системы координат
- •5.1 Матрицы преобразований
- •5.2 Видовые и модельные преобразования
- •5.3 Проекционное преобразование
- •5.4 Оконное преобразование
- •6. Пример выполнения модельных преобразований
- •6.1 Параллельный перенос
- •Фрагмент программы 1.2
- •6.2 Поворот
- •Фрагмент программы 1.3
- •7. Сводка результатов
- •8. Упражнения Упражнение 1
- •Упражнение 2
- •Упражнение 3
- •Упражнение 4
- •Упражнение 5
- •Упражнение 6
- •Лекция 2. Генерация движущихся изображений
- •1. Анимация с двойной буферизацией
- •2. Обработка событий клавиатуры и мыши
- •2.1 Пример обработки события от мыши: изменение цвета вращающегося объекта по нажатию левой кнопки мыши
- •3. Композиция нескольких преобразований
- •3.1 Модель солнечной системы
- •3.2 Модель манипулятора робота
- •4. Сводка результатов
- •5. Упражнения Упражнение 1
- •Упражнение 2
- •Упражнение 3
- •Упражнение 4
- •Упражнение 5
- •Лекция 3. Геометрические примитивы
- •1. Служебные графические операции
- •1.1 Очистка окна
- •1.2 Задание цвета
- •1.3 Удаление невидимых поверхностей
- •2. Описание точек, отрезков и многоугольников
- •2.1 Точки
- •2.2 Отрезки
- •2.3 Многоугольники
- •2.4 Прямоугольники
- •2.5 Кривые
- •2.6 Задание вершин
- •2.7 Геометрические примитивы OpenGl
- •3. Свойства точек, отрезков и многоугольников
- •3.1 Точки
- •3.2 Отрезки
- •3.3 Многоугольники
- •4. Сводка результатов
- •Лекция 4. Полигональная аппроксимация поверхностей
- •1. Векторы нормали
- •2. Некоторые рекомендации по построению полигональных аппроксимаций поверхностей
- •3. Пример: построение икосаэдра
- •3.1 Вычисление нормалей к граням икосаэдра
- •3.2 Повышение точности аппроксимации сферической поверхности
- •3.3 Алгоритм разбиения треугольной грани произвольной поверхности
- •4. Плоскости отсечения
- •6. Сводка результатов
- •7. Упражнения Упражнение 1
- •Упражнение 2
- •Упражнение 3
- •Упражнение 4
- •Лекция 5. Цвет и освещение
- •1. Цветовая модель rgb
- •2. Задание способа закраски
- •3. Освещение
- •4. Освещение в реальном мире и в OpenGl
- •4.1 Излучаемый, рассеянный, диффузно отраженный и зеркально отраженный свет
- •4.2 Цвет материала
- •4.3 Значения rgb для источников света и материалов
- •5. Пример: рисование освещенной сферы
- •5.1 Вектора нормали в вершинах объектов
- •5.2 Создание, расположение и включение источников света
- •5.3 Выбор модели освещения
- •5.4 Задание свойств материалов для объектов сцены
- •6. Создание источников света
- •6.1 Цвет
- •6.2 Местоположение и затухание
- •6.3 Прожекторы
- •6.4 Использование нескольких источников света
- •6.5 Изменение местоположения источников света
- •4. Сводка результатов
- •Лекция 6. Свойства материала и спецэффекты освещения
- •1. Задание свойств материала
- •1.1 Диффузное и рассеянное отражение
- •1.2 Зеркальное отражение
- •1.3 Излучаемый свет
- •1.4 Изменение свойств материала
- •1.5 Имитация реальных материалов
- •2. Смешение цветов и прозрачность
- •2.1 Множители source (исходный пиксел) и destination (результирующего пиксела)
- •2.2 Области применения смешения цветов
- •2.3 Пример использования смешения цветов
- •3. Туман
- •3.1 Использование тумана
- •4. Сводка результатов
- •5. Упражнения Упражнение 1
- •2. Назначение текстур
- •3. Создание текстуры в оперативной памяти
- •4. Автоматическое повторение текстуры на плоском многоугольнике
- •5. Наложение текстуры на произвольную поверхность
- •6. Сводка результатов
- •7. Упражнения Упражнение 1
- •Упражнение 2
- •Задание 1.1
- •2. Объемный "тетрис"
- •Задание 2.1
1.2 Зеркальное отражение
Блики на поверхности объекта формируются за счет зеркального отражения. В отличие от рассеянного и диффузного отражения, количество зеркально отраженного света, воспринимаемого наблюдателем, зависит от его положения. Например, представьте, что вы смотрите на улице в солнечную погоду на полированный металлический шар. При повороте головы солнечный блик на шаре будет немного смещаться, но если вы повернете голову слишком сильно, то можете потерять блик из вида.
Для материала в OpenGL можно задавать цвет зеркально отраженного света (свойство GL_SPECULAR), а также управлять размером и яркостью блика (свойство GL_SHININESS). Значение блеска (GL_SHININESS) выбирается из диапазона [0.0, 128.0] – чем больше значение, тем меньше и ярче (более сфокусирован) блик.
1.3 Излучаемый свет
Свойство GL_EMISSION позволяет сделать объект светящимся. Большинство реальных объектов (кроме источников света) свет не излучают, поэтому это свойство в основном применяется для имитации ламп и других источников света. Светящиеся объекты выглядят яркими, но их излучение для расчетов освещения других объектов не используется. Чтобы светящийся объект действительно играл роль источника света, надо создать в его позиции отдельный источник света OpenGL.
1.4 Изменение свойств материала
Ниже приведен фрагмент программы 6.1 (часть функции display()) для рисования четырех сфер, расположенных в одной строке. Для этих сфер выбираются различные свойства материала.
float no_mat[] = { 0.0, 0.0, 0.0, 1.0 };
float mat_ambient[] = { 0.7, 0.7, 0.7, 1.0 };
float mat_ambient_color[] = { 0.8, 0.8, 0.2, 1.0 };
float mat_diffuse[] = { 0.1, 0.5, 0.8, 1.0 };
float mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
float no_shininess[] = { 0.0 };
float low_shininess[] = { 5.0 };
float high_shininess[] = { 100.0 };
float mat_emission[] = {0.3, 0.2, 0.2, 0.0};
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
/* Рисование сферы в первой строке, первом столбце только с диффузным отражением, без рассеянной и зеркальной компонент */
glPushMatrix();
glTranslatef (-3.75, 3.0, 0.0);
glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, no_mat);
glMaterialfv(GL_FRONT, GL_SHININESS, no_shininess);
glMaterialfv(GL_FRONT, GL_EMISSION, no_mat);
auxSolidSphere( 1.0 );
glPopMatrix();
/* Рисование сферы в первой строке, втором столбце с диффузным и зеркальным отражением. Малый блеск, нет рассеянной компоненты */
glPushMatrix();
glTranslatef (-1.25, 3.0, 0.0);
glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, low_shininess);
glMaterialfv(GL_FRONT, GL_EMISSION, no_mat);
auxSolidSphere( 1.0 );
glPopMatrix();
/* Рисование сферы в первой строке, третьем столбце с диффузным и зеркальным отражением. Высокий блеск, нет рассеянной компоненты */
glPushMatrix();
glTranslatef (1.25, 3.0, 0.0);
glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess);
glMaterialfv(GL_FRONT, GL_EMISSION, no_mat);
auxSolidSphere( 1.0 );
glPopMatrix();
/* Рисование сферы в первой строке, четвертом столбце с диффузным отражением и излучением. Нет рассеянной и зеркальной компонент */
glPushMatrix();
glTranslatef (3.75, 3.0, 0.0);
glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, no_mat);
glMaterialfv(GL_FRONT, GL_SHININESS, no_shininess);
glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission);
auxSolidSphere( 1.0 );
glPopMatrix();
Фрагмент программы 6.1. Использование материалов с различными свойствами.
Функция glMaterialfv() в программе 6.1 для задания свойств материала каждой сферы вызывается по несколько раз. Но ее можно вызывать только для тех свойств, значения которых надо изменить. Например, рассеянная и диффузная компоненты второй и третьей сферы совпадают с соответствующими значениями первой сферы. Поэтому эти свойства повторно можно не устанавливать. Вызов glMaterial*() требует некоторого времени, поэтому для увеличения скорости работы программы надо стараться уменьшать количество изменений свойств материала.
Кроме явных вызовов функции glMaterial*(), в OpenGL есть еще одно средство изменения свойств материала – функция glColorMaterial():
void glColorMaterial(GLenum face, GLenum mode);
Эта функция позволяет установить режим, при котором свойства материала будут автоматически изменяться при задании текущего цвета (функцией glColor*()). Текущий цвет будет присваиваться свойствам материала mode для сторон face. Параметр face может быть GL_FRONT, GL_BACK или GL_FRONT_AND_BACK (по умолчанию). Допустимые значения параметра mode – константы GL_AMBIENT, GL_DIFFUSE, GL_AMBIENT_AND_DIFFUSE (по умолчанию), GL_SPECULAR или GL_EMISSION.
Чтобы режим синхронного задания текущего цвета и свойств материала начал работать, надо после вызова glColorMaterial() вызвать функцию glEnable(GL_COLOR_MATERIAL). В предыдущих лекциях свойства материала задавались именно так, например:
glColorMaterial(GL_FRONT, GL_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);
glColor3f(0.2, 0.5, 0.8);
// рисование каких-либо объектов
glColor3f(0.9, 0.0, 0.2);
// рисование каких-либо объектов
glDisable(GL_COLOR_MATERIAL);
Функцию glColorMaterial() удобно применять в тех случаях, когда для объектов сцены изменяется только одно свойство материала. Если требуется менять несколько, то придется выполнять отдельные вызовы glMaterial*(). Для отключения режима glColorMaterial()надо вызвать glDisable(GL_COLOR_MATERIAL).
Далее приведена программа 6.2, которая позволяет в интерактивном режиме проверить работу функции glColorMaterial(). По нажатию трех клавиш курсора (стрелка влево, вверх и вправо) эта программа циклически изменяет одну из компонент цвета диффузного отражения.
#include <windows.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
float diffuseMaterial[4] = { 0.5, 0.5, 0.5, 1.0 };
void light_init()
{
float mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
float light_position[] = { 1.0, 1.0, 1.0, 0.0 };
glMaterialfv( GL_FRONT, GL_DIFFUSE, diffuseMaterial );
glMaterialfv( GL_FRONT, GL_SPECULAR, mat_specular );
glMaterialf( GL_FRONT, GL_SHININESS, 25.0 );
glLightfv( GL_LIGHT0, GL_POSITION, light_position );
glEnable( GL_LIGHTING );
glEnable( GL_LIGHT0 );
glDepthFunc( GL_LEQUAL );
glEnable( GL_DEPTH_TEST );
glColorMaterial( GL_FRONT, GL_DIFFUSE );
glEnable( GL_COLOR_MATERIAL );
}
void CALLBACK changeRedDiffuse()
{
diffuseMaterial[0] += 0.1f;
if ( diffuseMaterial[0] > 1.0 )
diffuseMaterial[0] = 0.0;
glColor4fv( diffuseMaterial );
}
void CALLBACK changeGreenDiffuse()
{
diffuseMaterial[1] += 0.1f;
if ( diffuseMaterial[1] > 1.0 )
diffuseMaterial[1] = 0.0;
glColor4fv( diffuseMaterial );
}
void CALLBACK changeBlueDiffuse()
{
diffuseMaterial[2] += 0.1f;
if ( diffuseMaterial[2] > 1.0 )
diffuseMaterial[2] = 0.0;
glColor4fv( diffuseMaterial );
}
void CALLBACK display()
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
auxSolidSphere( 1.0 );
glFlush();
}
void CALLBACK resize( int w, int h )
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if ( w <= h )
glOrtho( -1.5, 1.5, -1.5*(float)h/(float)w,
1.5*(float)h/(float)w, -10.0, 10.0 );
else
glOrtho( -1.5*(float)w/(float)h,
1.5*(float)w/(float)h, -1.5, 1.5, -10.0, 10.0 );
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void main()
{
auxInitDisplayMode( AUX_SINGLE | AUX_RGBA | AUX_DEPTH );
auxInitPosition( 0, 0, 400, 400 );
auxInitWindow( "Лекция 6. Программа 6.2" );
light_init();
auxKeyFunc( AUX_LEFT, changeRedDiffuse );
auxKeyFunc( AUX_UP, changeGreenDiffuse );
auxKeyFunc( AUX_RIGHT, changeBlueDiffuse );
auxReshapeFunc( resize );
auxMainLoop( display );
}
Программа 6.2. Изменение свойств материала с помощью glColorMaterial().
