Каркас Windows-приложения. Особенности нового каркаса. Перемещение в пространстве (с текстурированными стенами), страница 15

Запустите приложение и проверьте его в работе. Для того, чтобы понять, как заданы координаты стен, а точнее, вершин треугольников, из которых они собираются (см. файл World.txt), приведем рисунок, который представляет собой вид всей сцены сверху. На рисунке обозначены мировые координаты некоторых опорных точек. Потолок помещения имеет координату y = 1, а пол y = 0. Уровню глаз соответствует значение y = 0.6.

Структура данных и технология управления ими позволяют относительно быстро изменить план помещения, что вы сможете сделать, если поймете структуру данных файла World.txt. Комментарии в файле данных помогают понять какой элемент объекта сцены задается cледующей серией чисел. Они указывают номер квадранта и номер детали (стены). Из рисунка видно, что в каждом квадранте имеется 4 стены.

Каждая стена собирается из двух треугольников, вершины которых заданы в порядке обхода против часовой стрелки. Все стены, идущие с запада на восток, (для простоты) имеют нормаль, направленную на юг, а стены, идущие с юга на север, имеют нормаль, направленную на восток.

Правило обхода вершин против часовой стрелки играет важную роль. Направление обхода должно быть согласовано с направлением нормали — именно это определяет лицевую и изнаночную поверхности каждого треугольника. Эффект изнанки в нашем случае выключен, так как, расхаживая по помещениям, мы хотим видеть обе поверхности стен. Установка GL_LIGHT_MODEL_TWO_SIDE указывает конвейеру OpenGL, что при расчете освещенности обе поверхности трактуются как лицевые. На самом деле в этом случае OpenGL для изнанок просто переворачивает нормаль. Чтобы увидеть эффект изнанки надо убрать установку GL_LIGHT_MODEL_TWO_SIDE и включить освещение.

Имитация ходьбы создается благодаря синусоидальному изменению позиции глаза наблюдателя (см. алгоритм управления переменной wave). Вы можете проходить сквозь стены и возвращаться назад. При этом направления: право-лево и верх-низ не изменяютя, как было в первом опыте с кубом. Это достигается согласованным изменением переменных: heading (направление движения), xpos, zpos (координатные смещения сцены) и angleY (угол поворота корпуса). Чтобы понять алгоритм их изменения, анализируйте код реакции на нажатие клавиш управления курсором (см. функцию Update).

Режимы заполнения внутренних областей

Вы уже знаете, что при изображении многоугольников (polygons) OpenGL выбирает один из способов заполнения внутренней области. Эти способы задаются тремя константами:

q  Режим заливки (GL_FILL),

q  Режим прорисовки контура (wireframe, или GL_LINE),

q  Режим обозначения вершин (GL_POINT).

Следующий пример иллюстрирует первые два режима, изображая текстурированный флаг. Обратите внимание на то, что для двух поверхностей одного и того же флага заданы разные режимы заполнения. Это делается с помощью команд:

glPolygonMode (GL_BACK, GL_FILL); // Задняя поверхность имеет сплошную заливку

glPolygonMode (GL_FRONT, GL_LINE);      // Передняя поверхность обозначена контуром

Этот пример также показывает, как создать волнообразное движение полотна. Добавьте к проекту новый файл Wave.cpp, скопируйте в него старый код и внесите изменения, как показано ниже.

const int nPoints = 45;

float pts[nPoints][nPoints][3];   // The array of grid points

UINT texture;

TCHAR curDir[MAX_PATH], *pFile = 0;

bool LoadTexture (TCHAR *fn, UINT *pTexture)

{

if (fn == 0)

return false;

AUX_RGBImageRec *p = auxDIBImageLoad (fn);

if (p == 0)

return false;

glGenTextures (1, pTexture);

glBindTexture (GL_TEXTURE_2D, *pTexture);

glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

glTexImage2D (GL_TEXTURE_2D, 0, 3, p->sizeX, p->sizeY, 0,

GL_RGB, GL_UNSIGNED_BYTE, p->data);

if (p->data)

free(p->data);

free(p);

return true;

}

bool Init ()

{

::GetCurrentDirectory (MAX_PATH-1, curDir);

if (pFile == 0)

{

pFile = strcpy (new TCHAR[MAX_PATH], curDir);

pFile = gInfo.bFull ? strcat (pFile, "/Data/Tim.bmp") : FileDlg (true);