Иллюстрированный самоучитель по Visual Studio.Net

         

Класс точки в 3D


С каждой вершиной, как вы помните, связано множество параметров, определяющих качество изображения OpenGL. Мы остановимся на наборе из трех величин: координаты вершины, вектор нормали и цвет. Так как вектор нормали и координаты можно задать с помощью двух объектов одного и того же типа (три вещественных переменных х, у, z), то целесообразно ввести в рассмотрение такое понятие, как точка трехмерного пространства. И воплотить его в виде класса CPoint3D, который инкапсулирует функциональность такой точки. Введите определение класса в конец файла Sphere. срр:

//====== Точка 3D-пространства

class CPointSD

{

public: float x, у, z; // Координаты точки

// ====== Конструктор по умолчанию

CPoint3D () { х = у = z = 0; ) //====== Конструктор с параметрами

CPointSD (double cl, double c2, float c3)

{

x = float (cl) ;

z = float(c2) ;

у = float(c3) ;

}

//====== Операция присвоения

CPoint3D& operator= (const CPoint3D& pt)



{

x = pt.x;

z = pt . z ;

У = Pt.y;

return *this;

//====== Операция сдвига в пространстве

CPoint3D& operator+= (const CPoint3D& pt)

{

x += pt.x;

y += Pt.y;

z += pt . z ;

return * this ;

}

//====== Конструктор копирования

CPointSD (const CPoint3D& pt)

{

*this = pt;

}

};

Обратите внимание на тот факт, что конструктор копирования использует код уже существующей операции присвоения. Имея в своем распоряжении класс CPointSD, мы можем создать еще один тип данных — структуру, поля которой объединяют все величины, связанные с вершиной треугольника. Массив данных такого типа будет хранить информацию обо всех вершинах изображения и при этом не будет повторений:

//====== Данные о вершине геометрического примитива

struct VERT

{

CPointSD v; // Координаты вершины

CPoiivt3D n; // Координаты нормали

DWORD с; // Цвет вершины

};

Введите эту декларацию после кода, определяющего CPoint3D. Как было отмечено, функция glDrawElements в качестве параметра требует задать массив индексов вершин. В соответствии с этими индексами вершины треугольников будут выбираться из общего массива вершин.
Порядок следования индексов зависит от порядка обхода вершин при задании треугольников. Как вы помните, он должен идти против часовой стрелки, если смотреть на примитив с конца внешней нормали. В этом случае знак нормали соответствует формулам векторной алгебры,!: которые мы уже рассматривали.

Будет удобно, если мы сначала создадим структуру, которая объединяет три индекса вершин одного треугольника. Тогда массив структур такого типа сможет играть роль массива индексов, требуемого функцией glDrawElements. Введите следующее описание в продолжение файла:

struct TRIA

{

//====== Индексы трех вершин треугольника,

//====== выбираемых из массива вершин типа VERT

//====== Порядок обхода — против часовой стрелки

int i1;

int i2;

int i3;

};

Далее нам понадобятся две глобальные неременные типа CPointSD, с помощью *":' которых мы будем производить анимацию изображения сферы. Анимация, а также различие цветов при задании вершин треугольников позволят более четко передать трехмерный характер изображения. Наличие освещения подвижного объекта также заметно увеличивает его реалистичность. При создании програм-| мы мы обойдемся одним файлом, поэтому новые объявления продолжайте вставлять в конец файла Sphere.срр:

//====== Вектор углов вращения вокруг трех осей ?

CPointSD gSpin; //====== Вектор случайной девиации вектора gSpin

CPointSD gShift;

При каждой смене буферов (перерисовке изображения) мы будем вращать изоб- ; ражение сферы вокруг всех трех осей на некоторый векторный квант gshif t. Для того чтобы вращение было менее однообразным, введем элемент случайности. Функция Rand, приведенная ниже, возвращает псевдослучайное число в диапазоне (-х, х). Мы будем пользоваться этим числом при вычислении компонентов вектора gshif t. Последний, воздействуя на другой вектор gSpin, определяет новые значения трех углов вращения, которые функция glRotate использует для задания очередной позиции сферы:

inline double Rand(double x)

{

//====== Случайное число в диапазоне (-х, х)

return х - (х + х) * rand() / RAND_MAX;

}

Учитывая сказанное, можно создать алгоритм перерисовки:

void _stdcall OnDraw()

{

glClear(GL_COLOR_BUFFER_BIT) ;

//=== Сейчас текущей является матрица моделирования

glLoadldentityО;

//====== Учет вращения

glRotated(gSpin.х, 1., О, 0.) ;

glRotated(gSpin.y, 0., 1., 0.);

glRotated(gSpin.z, 0., 0., 1.) ;

//====== Вызов списка рисующих команд

glCallList(1);

//====== Подготовка следующей позиции сферы

gSpin += gShift;

//===== Смена буферов auxSwapBuffers();

}


Содержание раздела