Для иллюстрации работы с массивами вершин создадим более сложный объект — икосаэдр. Это такой дссятистенный дом с острой пятиугольной крышей и таким же полом, но углы пола смещены (повернуты) на л/5 относительно углов потолка.
Икосаэдр имеет 20 треугольных граней и 12 вершин (1 + 5 на потолке и 1 + 5 на полу). Благодаря своей правильности он может быть задан с помощью всего лишь двух чисел, которые лучше вычислить один раз и запомнить. Этими числами является косинус и синус угла в три пятых окружности, то есть
static double
//====== atan(l.) - это пи/4
angle = 3. * atan(1.)/2.5, //====== 2 характерные точки
V = cos(angle), W = sin(angle);
Этот код мы вставим внутрь функции рисования, чтобы не плодить глобальные переменные и не нарываться на конфликты имен. Вот новая версия функции DrawScene:
void DrawScene() { static double
//====== 2 характерные точки
angle = 3. * atan(l.)/2.5, V = cos(angle), W = sin(angle),
//=== 20 граней икосаэдра, заданные индексами вершин
static GLuint id[20][3] =
(0,1, 4), (8,1,10), (7,3,10), (6,10,1), |
(0,4, 9), (8,10,3), (7,10,6), (9,11,0), |
(9,4, 5), (5,8, 3), (7,6,11), (9,2,11), |
(4,8, 5), (5,3, 2), (11,6,0), (9,5, 2), |
(4,1,8), (2,3,7), (0,6,1), (7,11,2) |
||
//====== Начинаем формировать список команд
glNewList (1,GL_COMPILE) ;
//====== Выбираем текущий цвет рисования
glColor3d (1., 0.4, 1 . ) ;
glBegin (GLJTRIANGLES) ;
for (int i = 0; i < 20; i++)
{
//====== Грубый подход к вычислению нормалей
glNorma!3dv(v[id[i] [0] ] ) ;
glVertex3dv(v[id[i] [0] ] ) ;
glNorma!3dv(v[id[i] [1] ] ) ;
glVertex3dv(v[id[i] [1] ] ) ;
glNorma!3dv(v[id[i] [2] ] ) ;
glVertex3dv(v[id[i] [2] ] ) ;
}
glEnd() ;
//====== Конец списка команд
glEndList ();
}
Точное вычисление нормалей
Проверьте результат и обсудите качество. В данном варианте нормали в вершинах заданы так, как будто изображаемой фигурой является сфера, а не икосаэдр. Это достаточно грубое приближение. Если поверхность произвольного вида составлена из треугольников, то вектор нормали к поверхности каждого из них можно вычислить точно, опираясь на данные о координатах вершин треугольника. Из $ курса векторной алгебры вы, вероятно, помните, что векторное произведение двух векторов а и b определяется как вектор п, перпендикулярный к плоскости, в которой лежат исходные векторы. Величина его равна площади параллелограмма, построенного на векторах а и b как на сторонах, а направление определяется так, что векторы a, b и п образуют правую тройку. Последнее означает, что если представить наблюдателя на конце вектора п, то он видит поворот вектора а к вектору b, совершаемый по кратчайшему пути против часовой стрелки. На Рисунок 6.4. изображена нормаль п (правая тройка) при различной ориентации перемножаемых векторов а и b.