Подготовка
изображения
Разработаем
код функции DrawScene, которая готовит и запоминает изображение на основе координат
вершин, хранимых в контейнере m_cPoints. Изображение по выбору пользователя
формируется либо в виде криволинейных четырехугольников (GL_QUADS), либо в виде
полосы связанных четырехугольников (GL_QUAD_STRIP). Точки изображаемой поверхности
расположены над регулярной координатной сеткой узлов в плоскости (X, Z). Размерность
этой сетки хранится в переменных m_xSize и m_zSize. Несмотря на двухмерный характер
сетки, для хранения координат вершин мы используем линейный (одномерный) контейнер
m_cPoints, так как это существенно упрощает объявление контейнера и работу с
ним. В частности, упрощаются файловые операции. Выбор четырех смежных точек
генерируемого примитива (например, GL_QUADS) происходит с помощью четырех индексов
(n, i, j, k). Индекс п последовательно пробегает по всем вершинам в порядке
слева направо. Более точно алгоритм перебора вершин можно определить так: сначала
проходим по сетке узлов вдоль оси X при Z = 0, затем увеличиваем Z и вновь проходим
вдоль X и т. д. Индексы i, j, k вычисляются относительно индекса п. В ветви
связанных четырехугольников (GL_QUAD_STRIP) работают только два индекса.
В контейнер
m_cPoints данные попадают после того, как они будут прочитаны из файла. Для
того чтобы при открытии приложения в его окне уже находился график функции,
необходимо заранее создать файл с данными по умолчанию, открыть и прочесть его
содержимое. Это будет сделано в коде функций
DefaultGraphic
и SetGraphPoints. Алгоритм функции DrawScene разработан в предположении, что
контейнер точек изображаемой поверхности уже существует. Флаг m_bQuad используется
для выбора способа создания полигонов: в виде отдельных (GL_QUADS) или связанных
(GL_QUAD_STRIP) четырехугольников. Позднее мы введем команду меню для управления
этой регулировкой:
void
COGView: : DrawScene
()
{
//======
Создание списка рисующих команд
glNewList
(1, GL_COMPILE) ;
//======
Установка режима заполнения
//======
внутренних точек полигонов
glPolygonMode
(GL_FRONT_AND_BACK, m_FillMode) ;
//======
Размеры изображаемого объекта
UINTnx
= m_xSize-l, nz = m_zSize-l;
//======
Выбор способа создания полигонов
if
(m_bQuad)
glBegin
(GL_QUADS) ;
//======
Цикл прохода по слоям изображения (ось Z)
for
(UINT z=0, i=0; z<nz; z++)
//======
Связанные полигоны начинаются
//======
на каждой полосе вновь
if
(!m_bQuad)
glBegin
(GLJ2UAD_STRIP) ;
//======
Цикл прохода вдоль оси X
for
(UINT x=0; x<nx; x++)
//
i, j, k, n — 4 индекса вершин примитива при
//
обходе в направлении против часовой стрелки
int
j = i + m_xSize, // Индекс узла с большим Z
k
= j+1/ // Индекс узла по диагонали
n
= i+1; // Индекс узла справа
//===
Выбор координат 4-х вершин из контейнера
float
xi
= m_cPoints [i] .x,
yi
= m_cPoints [i] .у,
zi
= m_cPoints [i] . z,
xj
= m_cPoints [ j ] .x,
yj
= m_cPoints [ j ] .y,
zj
= m_cPoints [ j ] . z,
xk
= m_cPoints [k] .x,
yk
= m_cPoints [k] .y,
zk
= m cPoints [k] . z,
xn
= m_cPoints [n] .x,
yn
= m_cPoints [n] .y,
zn
= m_cPoints [n] . z,
//===
Координаты векторов боковых сторон ах = xi-xn, ay = yi-yn,
by
= yj-yi, bz = zj-zi,
//======
Вычисление вектора нормали
vx
= ay*bz, vy = -bz*ax, vz = ax*by,
//======
Модуль нормали
v
= float (sqrt (vx*vx + vy*vy + vz*vz) ) ;
//======
Нормировка вектора нормали
vx
/= v; vy /= v; vz /= v;
//======
Задание вектора нормали
glNorma!3f
(vx,vy,vz);
//
Ветвь создания несвязанных четырехугольников
if
(m_bQuad)
{
//====
Обход вершин осуществляется
//====
в направлении против часовой стрелки
glColorSf
(0.2f, 0.8f, l.f);
glVertexSf
(xi, yi, zi) ;
glColor3f
(0.6f, 0.7f, l.f);
glVertexSf
(xj, у j , zj);
glColorSf
(0.7f, 0.9f, l.f);
glVertexSf
(xk, yk, zk) ;
glColor3f
(0.7f, 0.8f, l.f);
glVertexSf
(xn, yn, zn) ;
}
else
//====
Ветвь создания цепочки четырехугольников
{
glColor3f
(0.9f, 0.9f, l.0f);
glVertexSf
(xn, yn, zn) ;
glColorSf
(0.5f, 0.8f, l.0f);
glVertexSf
(xj, у j , zj);
//======
Закрываем блок команд GL_QUAD_STRIP
if
(!m_bQuad) glEnd ( ) ; } //====== Закрываем блок команд GL_QUADS
if
(m_bQuad)
glEnd()
;
//
====== Закрываем список команд OpenGL
glEndList()
;
}
При анализе
кода обратите внимание на тот факт, что вектор нормали вычисляется по упрощенной
формуле, так как линии сетки узлов, над которой расположены вершины поверхности,
параллельны осям координат (X, Z). В связи с этим равны нулю компоненты az и
bх векторов боковых сторон в формуле для нормали (см. раздел «Точное вычисление
нормалей» в предыдущем уроке).