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

Важно то, что в первом случае мы перемещаем глаз наблюдателя, а во втором — объекты сцены. Рассмотрим пример, который моделирует ходьбу по горизонтальной поверхности, окруженной стенами и потолком. В нем перемещение будет реализовано на основе второго подхода. Направление перемещения выбирает пользователь. Пусть клавиши ¬ и ® вращают сцену вокруг оси Y, а клавиши и ¯ перемещают объекты сцены (вперед-назад). Важно понять, что как вращение, так и перемещение должны производиться в направлении противоположном движению глаза наблюдателя (идущего человека).

При создании сложных сцен OpenGL объекты обычно собирают из множества треугольников (tesselated images), так как они являются минимальными многоугольниками, которые единственным образом задают плоскость, а значит и нормаль к ней. Последняя важна при расчете освещенности. Вы помните, что через три точки проходит единственная плоскость. Сборка элементов поверхностей из фигур с 4-мя и более точками (из примитивов типа GL_QUADS или GL_POLYGON) менее надежна, так как ошибки в задании координат сразу делают фигуру не плоской. Это приводит к искажениям в расчете нормали, а, следовательно, и освещенности.

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

bool light, blend, amb, lp, bp, fp, ap;  // Lighting ON/OFF, Blending, Ambient light model

const float toDeg = 180 / acos(-1.0f);

float

heading, xpos, ypos = 0.6f, zpos, speed = 0.1f, step = 0.25f,

angleY,       // Y Rotation

wave = 0,   // Vertical shift (while walking)

advance = 0,  // Horizontal displacement

upDown = 0,   // Pitch angle

ambModel[]=  { 0.2f, 0.2f, 0.2f, 1 },

ambient[]=  { 0.61f, 0.61f, 0.61f, 1 },

diffuse[]=  { 1, 1, 1, 1 },

specular[]=  { 1, 1, 1, 1 },

position[]= { 0, 0, 1, 1};

const UINT lineSize = 128; // File string line length

UINT filter, texture[3]; // Filter and textures

TCHAR curDir[MAX_PATH], *pFile[2];

Другим новым моментом рассматриваемого примера является то, что пространственные и текстурные координаты объектов окружения заданы в текстовом файле. Это позволяет редактировать сцену, не трогая кода приложения. В файле данных будут храниться как пространственные, так и текстурные координаты каждого треугольника. Кроме того, если мы хотим включить освещение, то все треугольники должны быть снабжены вектором нормали. В связи с этим, удобно ввести в рассмотрение следующие структуры данных.

struct Vertex { float x, y, z, s, t; };  // Spatial & texture coordinates

struct Tria

{

Vertex v[3];       // Three vertex

float nx, ny, nz;  // One normal vector

};

struct Object

{

int nTria;

Tria* t; // Triangles array

};

Object object; // Scene object

Для чтения данных из файла World.txt и заполнения рассмотренных структур необходимо ввести еще пару функций. Логика их алгоритма объясняется тем, что в файле предусмотрен заголовок (в нем содержится общее число треугольников объекта). Кроме того в файле предусмотрены отдельные строки с комментариями. Они начинаются символом / и при чтении их надо пропускать. Первая функция, ReadLine, читает одну значимую текстовую строку и пропускает все строки с комментариями. Вторая, SetupWorld, пользуется услугами первой для того, чтобы прочесть все данные о геометрии помещения и заполнить поля структуры object.

void ReadLine (FILE *fp, char *s) // Reads in one line of text

{

fgets (s, lineSize, fp);

while (s[0] == '/' || s[0] == '\n')

fgets (s, lineSize, fp);

}

bool SetupWorld() // Read and fill object data

{

if (pFile[1] != 0)

return true;

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

pFile[1] = strcat (pFile[1], "/Data/world.txt");

FILE *fp = fopen (pFile[1], "rt");

char line[lineSize];

ReadLine (fp, line);

sscanf (line, "Number of polygons: %d\n", &object.nTria);

object.t = new Tria [object.nTria];

if (!object.t)

{

MessageBox (HWND_DESKTOP,"Wrong data","Error", MB_OK | MB_ICONEXCLAMATION);

return false;

}