- •Часть 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
3. Пример: построение икосаэдра
Для демонстрации приемов, перечисленных в п.2., рассмотрим фрагменты программы, выполняющей построение икосаэдра. Икосаэдр – это правильный многогранник, имеющий 12 вершин и 20 граней (каждая грань – равносторонний треугольник). Икосаэдр можно считать грубой аппроксимацией сферы. Во фрагменте программы 4.1а в массивах заданы вершины икосаэдра и списки вершин каждой грани. После описания и инициализации массивов приведен цикл рисования этих граней.
const double X = .525731112119133606;
const double Z = .850650808352039932;
double vdata[12][3] = {
{-X, 0.0, Z}, {X, 0.0, Z}, {-X, 0.0, -Z}, {X, 0.0, -Z},
{0.0, Z, X}, {0.0, Z, -X}, {0.0, -Z, X}, {0.0, -Z, -X},
{Z, X, 0.0}, {-Z, X, 0.0}, {Z, -X, 0.0}, {-Z, -X, 0.0}
};
int tindices[20][3] = {
{0,4,1}, {0,9,4}, {9,5,4}, {4,5,8}, {4,8,1},
{8,10,1}, {8,3,10}, {5,3,8}, {5,2,3}, {2,7,3},
{7,10,3}, {7,6,10}, {7,11,6}, {11,0,6}, {0,1,6},
{6,1,10}, {9,0,11}, {9,11,2}, {9,2,5}, {7,2,11} };
for ( int i = 0; i < 20; i++ ) {
/* Здесь могут быть вызовы функций для задания цвета */
glBegin( GL_TRIANGLES );
glVertex3dv( &vdata[tindices[i][0]][0] );
glVertex3dv( &vdata[tindices[i][1]][0] );
glVertex3dv( &vdata[tindices[i][2]][0] );
glEnd();
}
Фрагмент программы 4.1а. Рисование икосаэдра.
Константы X и Z выбраны такими, чтобы расстояние от начала координат до каждой вершины икосаэдра равнялось 1.0. Координаты 12-ти вершин хранятся в массиве vdata[][]: 0-я вершина имеет координаты {-X, 0.0, Z}, 1-я – {X, 0.0, Z} и т.д. Массив tindices[][] задает правила построения треугольных граней из вершин. Например, первый треугольник формируется из 0-й, 4-й и 1-й вершины. Вершины треугольников в массиве tindices[][] перечислены так, что все грани будут иметь одинаковую ориентацию.
В строке с комментарием о цветовой информации можно вызвать функцию, задающую разный цвет для каждой (i-й) грани. Если всем граням присвоить одинаковый цвет, то на изображении они будут сливаться. При закраске граней одним цветом необходимо задавать нормали вершин и применять направленное освещение.
Если вершины полигональной сетки не задаются явно, как во фрагменте 4.1а, а рассчитываются по какому-либо алгоритму, целесообразно выполнять расчеты только один раз и затем хранить рассчитанные координаты вершин и нормалей в массивах или ваших собственных структурах данных.
3.1 Вычисление нормалей к граням икосаэдра
Для применения направленного освещения надо задать вектор нормали для каждой вершины икосаэдра. На плоских гранях икосаэдра вектор нормали одинаков у всех трех вершин (это нормаль к плоскости этой грани). Следовательно, для каждого набора из трех вершин нормаль надо задавать только один раз. Фрагмент программы 4.1б можно разместить в тех строках фрагмента 4.1а, которые отмечены комментарием "вызовы функций для задания цвета".
double d1[3], d2[3], norm[3];
for ( int j = 0; j < 3; j++ ) {
d1[j] = vdata[tindices[i][1]][j] - vdata[tindices[i][0]][j];
d2[j] = vdata[tindices[i][2]][j] - vdata[tindices[i][0]][j];
}
normcrossprod( d2, d1, norm );
glNormal3dv( norm );
Фрагмент программы 4.1б. Вычисление нормалей для вершин i-й грани икосаэдра.
Функция normcrossprod() вычисляет нормированное векторное произведение двух векторов (см. фрагмент 4.1в).
void normalize( double v[3] )
{
double d = sqrt( v[0]*v[0]+v[1]*v[1]+v[2]*v[2] );
if ( d == 0.0 )
{
// Ошибка: вектор нулевой длины
return;
}
v[0] /= d; v[1] /= d; v[2] /= d;
}
void normcrossprod(const double v1[3], const double v2[3], double out[3])
{
out[0] = v1[1]*v2[2] - v1[2]*v2[1];
out[1] = v1[2]*v2[0] - v1[0]*v2[2];
out[2] = v1[0]*v2[1] - v1[1]*v2[0];
normalize(out);
}
Фрагмент программы 4.1в. Вычисление нормированного векторного произведения.
Нормали вершин не обязательно вычислять как нормаль к плоскости грани. Способ вычисления нормалей зависит от решаемой задачи. Допустим, вы хотите использовать икосаэдр в качестве аппроксимации сферической поверхности. Тогда нормали вершин надо вычислять как перпендикуляры к поверхности сферы, а не перпендикуляры к граням. Для сферы векторы нормали вычислить очень легко: вектор нормали для данной точки сферы совпадает с направлением радиуса для данной точки. В программе 4.1 вершины икосаэдра рассчитывались для икосаэдра, вписанного в единичную сферу. Поэтому в качестве координат нормалей можно взять координаты вершин (см. фрагмент 4.1г).
for ( int i = 0; i < 20; i++)
{
glBegin( GL_POLYGON );
glNormal3dv( &vdata[tindices[i][0]][0] );
glVertex3dv( &vdata[tindices[i][0]][0] );
glNormal3dv( &vdata[tindices[i][1]][0] );
glVertex3dv( &vdata[tindices[i][1]][0] );
glNormal3dv( &vdata[tindices[i][2]][0] );
glVertex3dv( &vdata[tindices[i][2]][0] );
glEnd();
}
Фрагмент программы 4.1г. Рисование икосаэдральной аппроксимации сферы (в предположении, что используется направленное освещение).
