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