Разработаем код функции 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х векторов боковых сторон в
формуле для нормали (см. раздел «Точное
вычисление нормалей» в предыдущем уроке). |