Трехмерные графики функций

Что такое драйвер Понять, что такое драйвер, мы попробуем на типовом примере взаимодействия прикладной программы с драйвером.
Код прикладной программы исполняется в пользовательском режиме работы процессора. В этом случае имеется ряд серьезных ограничений, связанных с доступом к памяти, аппаратным обеспечением и привилегированными инструкциями процессора. Когда возникает необходимость в преодолении этих ограничений, прикладная программа обращается к ядру ОС, код которого исполняется процессором в режиме ядра. Режим ядра лишен всех упомянутых ограничений. Для расширения функциональных возможностей ядра служат драйверы ядра (kernel mode drivers). Как они работают? Теоретическая механика Под вызовом драйвера здесь подразумевается не обычный вызов функции, а передача так называемого запроса ввода/вывода.

 

Подготовка изображения

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

Курс лекций Сопротивление материалов