Студопедия — Перемещение в пространстве
Студопедия Главная Случайная страница Обратная связь

Разделы: Автомобили Астрономия Биология География Дом и сад Другие языки Другое Информатика История Культура Литература Логика Математика Медицина Металлургия Механика Образование Охрана труда Педагогика Политика Право Психология Религия Риторика Социология Спорт Строительство Технология Туризм Физика Философия Финансы Химия Черчение Экология Экономика Электроника

Перемещение в пространстве






В данном разделе мы рассмотрим как можно смоделировать управление примитивным летательным аппаратом. Предположим, что сцена, вокруг которой должен летать наш самолет, представляет собой три стоящие недалеко друг от друга геометрические фигуры: куб, тетраэдр и додекаэдр. Мы хотим смоделировать изменения сцены, которые могли бы наблюдаться из окна летательного аппарата при управлении тремя характерными для всех летательных аппаратов углами: крена, атаки и курса (азимута), которые влияют на положение в пространстве самого летательного аппарата. Мы будем хранить эти значения в трех глобальных переменных: gdRoll — угол крена, gdPitch — угол атаки (или тангаж), и gdHeading — угол курса.

Функция Fly, преобразующая сцену OpenGL должна учитывать эти углы и изменять матрицу моделироваия так, чтобы векторы координат вершин примитивов сцены (которые будут умножены справа на матрицу моделирования) изменялись согласно положениям рулей-элеронов.

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

class Point3D

{

public:

double x, y, z;

 

Point3D() { x = y = z = 0.; }

Point3D (double xx, double yy, double zz) { x = xx; y = yy; z = zz; }

Point3D (double v[3]) { x = v[0]; y = v[1]; z = v[2]; }

Point3D operator+ (Point3D& p) { return Point3D (x+p.x, y+p.y, z+p.z); }

Point3D operator- (Point3D& p) { return Point3D (x-p.x, y-p.y, z-p.z); }

void operator+= (Point3D& p) { x += p.x; y += p.y; z += p.z; }

void operator-= (Point3D& p) { x -= p.x; y -= p.y; z -= p.z; }

Point3D operator* (double d) { return Point3D (x*d, y*d, z*d); }

Point3D operator* (Point3D& p)

{

return Point3D (y*p.z - z*p.y, z*p.x - x*p.z, x*p.y - y*p.x);

}

double operator! () { return sqrt (x*x + y*y + z*z); }

double Dist (Point3D& p) { return!Point3D (*this - p); }

 

Point3D ToUnit ()

{

double r =!*this;

return Point3D (x/r, y/r, z/r);

}

 

Point3D& Rotate (Point3D& p, double dr)

{

glMatrixMode (GL_MODELVIEW);

glLoadIdentity();

glRotated (dr, p.x, p.y, p.z);

 

double

mm[16],

t[3] = { x, y, z },

v[3];

glGetDoublev (GL_MODELVIEW_MATRIX, mm);

 

for (int i=0; i<3; i++)

{

v[i] = 0.;

for (int j=0; j<3; j++)

v[i] += mm[(i<<2) + j] * t[j];

}

x = v[0]; y = v[1]; z = v[2];

return *this;

}

};

 

const double PI = acos(-1.), ToRad = PI/180.; // Вспомогательные константы

//==== Направление вверх, положение центра сцены и позиция глаза наблюдателя

Point3D gU (0,1,0), gC, gE (0, 0, gDist);

double gSpeed = 0.1, gDist = 14; // Скорость и расстояние от глаза до центра сцены

Прежде всего напишем тела функций, которые задают списки команд для изображения сцены, то есть фигур ландшафта. Пусть первой фигурой будет зеленый куб. Просмотрите файл glut.h и найдите функции для изображения различных трехмерных фигур (например, glutSolideCube). Используйте их для создания объектов ландшафта.

void Cube()

{

static double green[3] = { 0.5, 0.75, 0.5 };

 

glNewList(1, GL_COMPILE);

glColor3dv(green);

//=== Здесь ваш код создания куба

//..........

glEndList();

}

Вторым элементом ландшафта (вторым списком команд) пусть будет тетраэдр. Его можно создать и вручную.

void Tetrahedron()

{

static double blue[3] = { 0.6667, 0.5, 1.0 };

 

double r = 1./sqrt(3); // To normalize normals

 

glNewList (2, GL_COMPILE);

glColor3dv (blue);

 

glBegin (GL_TRIANGLES); // Draw the four faces of the tetrahedron

 

glNormal3d (-r,-r,-r); // Left-Down-Rear

glVertex3d (1,-1,-1);

glVertex3d (-1,-1, 1);

glVertex3d (-1, 1,-1);

 

glNormal3d (-r, r, r); // Left-Up-Front

glVertex3d (1, 1, 1);

glVertex3d (-1, 1,-1);

glVertex3d (-1,-1, 1);

 

glNormal3d (r, r,-r); // Right-Up-Rear

glVertex3d (1, 1, 1);

glVertex3d (1,-1,-1);

glVertex3d (-1, 1,-1);

 

glNormal3d (r,-r, r); // Right-Down-Front

glVertex3d (1, 1, 1);

glVertex3d (-1,-1, 1);

glVertex3d (1,-1,-1);

 

glEnd();

glEndList();

}

Наконец, изобразим додекаэдр. Вручную его изобразить довольно сложно. Додекаэдр — это правильный многогранник из 12 пятиугольных граней и 20 вершин. Готовые коды можно найти во многих источниках, но проще использовать glut-функцию.

void Dodecahedron()

{

glNewList (3, GL_COMPILE); // Display list for Dodecahedron (12 pentagon faces, 20 vertices)

glColor3d (0.9, 0.6, 0.7); // DeepPurple

glutSolidDodecahedron ();

glEndList();

}

Создайте еще несколько деталей ландшафта, а затем соберите сцену из готовых деталей.

void DrawScene()

{

glPushMatrix();

glTranslated (-1.5, 0., 0.);

glCallList(1); // Первая фигура (куб) смещена влево (x = -1.5)

 

// Сместите как-то систему координат (2-ю фигуру относительно 1-й), чтобы тетраэдр был отделен от куба

// и нарисуйте тетраэдр (пирамиду)

glPopMatrix();

glPushMatrix();

glTranslated (1.5, 0., -5.);

glCallList (2);

// Еще раз сместите и поверните, с тем, чтобы додекаэдр стоял отдельно/ и нарисуйте Dodecahedron

//.......

//===== Продолжайтев том же духе, пока не будет готова вся сцена

}

Функция перерисовки может иметь вид:

void OnPaint()

{

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

Fly(); // Учет воздействия рулей управления и перерисовка

glutSwapBuffers();

}

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

void Fly ()

{

glMatrixMode (GL_MODELVIEW);

glLoadIdentity();

 

gluLookAt (gE.x, gE.y, gE.z, gC.x, gC.y, gC.z, gU.x, gU.y, gU.z);

DrawScene();

}

Инициализация сцены (Init) выполняет традиционные действия и кроме того, вызывает функции подготовки элементов ландшафта.

void Init()

{

glClearColor (0, 0, 0, 0);

glShadeModel (GL_SMOOTH);

 

glEnable (GL_DEPTH_TEST);

glEnable (GL_LIGHTING);

glEnable (GL_LIGHT0);

glEnable (GL_LIGHT1);

 

glEnable (GL_COLOR_MATERIAL);

glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);

 

float spec[] = { 1, 1, 1 };

glMaterialfv (GL_FRONT, GL_SPECULAR, spec);

glMaterialf (GL_FRONT, GL_SHININESS, 128);

 

float pos0[] = { -3, 3, 3, 0 };

glLightfv (GL_LIGHT0, GL_POSITION, pos0);

 

float amb[] = { 0.3f, 0.3f, 0.3f, 0 };

glLightfv (GL_LIGHT0, GL_AMBIENT, amb);

 

float pos1[] = { 3, 3, -3, 0 };

glLightfv (GL_LIGHT1, GL_POSITION, pos1);

 

glLightModeli (GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);

glLightModeli (GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);

 

Cube();

Tetrahedron();

Dodecahedron();

 

glNewList (3, GL_COMPILE);

glColor3d (0.61424, 0.04136, 0.04136);

glutSolidTorus(0.275, 0.8, 16, 16);

glEndList();

 

glNewList (4, GL_COMPILE);

glColor3d(0,0,1);

glutSolidCone(0.4, 1.4, 16, 16);

glEndList();

 

glNewList (5, GL_COMPILE);

glColor3d(0,1,1);

glutSolidCone(0.3, 1.8, 16, 16);

glEndList();

glNewList (6, GL_COMPILE);

glColor3d (0.61424, 0.04136, 0.04136);

glutSolidSphere(0.5, 16, 16);

glEndList();

}

Управление углами летательного аппарата возложим на цифровые клавиши правой части клавиатуры (keypad) так как обозначено в функции main:

void main()

{

glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);

glutInitWindowSize(500, 500);

glutCreateWindow ("KeyPad: 2-8, 4-6, 7-9, 5-0, 1-3, Space, Up-Down");

 

Init();

 

glutSpecialFunc (OnSpecialKey);

glutKeyboardFunc(OnKey);

 

glutReshapeFunc(OnSize);

glutDisplayFunc(OnPaint);

glutMainLoop();

}

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

void OnKey (unsigned char ch, int x, int y)

{

switch (ch)

{

case '7': Roll(-1); break;

case '9': Roll(1); break;

case '8': Pitch(-1); break;

case '2': Pitch(1); break;

case '4': Head(-1); break;

case '6': Head(1); break;

case '5': // Движение вперед

{

Point3D pt ((gE-gC) * gSpeed);

gE -= pt;

gC -= pt;

Fly();

break;

}

case '3': // Движение назад

{

// Реализуйте по аналогии с движением вперед

Fly();

break;

}

case ' ':

cout <<"\nE = (" <<gE.x<<", "<<gE.y<<", "<<gE.z<<')'

<<"\nC = (" <<gC.x<<", "<<gC.y<<", "<<gC.z<<')'

<<"\nU = (" <<gU.x<<", "<<gU.y<<", "<<gU.z<<")\n";

break;

case 27: exit(0); break;

}

glutPostRedisplay();

}

Приведем возможный способ реализации функции, реагирующей на изменение тангажа.

void Pitch (int angle)

{

Point3D v = gC - gE,

n = v * gU;

gC = gE + v.Rotate(n, angle);

gU.Rotate (n, angle);

Fly();

}

Обработку WM_SIZE можно взять такой

void OnSize (int w, int h)

{

glViewport (0, 0, w, h);

glMatrixMode (GL_PROJECTION);

glLoadIdentity ();

gluPerspective(35, double(w)/h,.1, 1000);

}

Чтобы не затеряться в бескрайних небесных просторах, введите следующий код в реакцию на нажатие клавиши 0 (на Key Pad). Нажатие на эту клавишу должно возвращать сцену в первоначальное состояние.

case '0': // Возврат в исходное состояние

gC = Point3D (0, 0, 0);

gU = Point3D (0, 1, 0);

gE = Point3D (0, 0, gDist);

Fly();

break;

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







Дата добавления: 2015-10-19; просмотров: 501. Нарушение авторских прав; Мы поможем в написании вашей работы!



Аальтернативная стоимость. Кривая производственных возможностей В экономике Буридании есть 100 ед. труда с производительностью 4 м ткани или 2 кг мяса...

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

Расчетные и графические задания Равновесный объем - это объем, определяемый равенством спроса и предложения...

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

Прием и регистрация больных Пути госпитализации больных в стационар могут быть различны. В цен­тральное приемное отделение больные могут быть доставлены: 1) машиной скорой медицинской помощи в случае возникновения остро­го или обострения хронического заболевания...

ПУНКЦИЯ И КАТЕТЕРИЗАЦИЯ ПОДКЛЮЧИЧНОЙ ВЕНЫ   Пункцию и катетеризацию подключичной вены обычно производит хирург или анестезиолог, иногда — специально обученный терапевт...

Ситуация 26. ПРОВЕРЕНО МИНЗДРАВОМ   Станислав Свердлов закончил российско-американский факультет менеджмента Томского государственного университета...

Демографияда "Демографиялық жарылыс" дегеніміз не? Демография (грекше демос — халық) — халықтың құрылымын...

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

ЛЕЧЕБНО-ПРОФИЛАКТИЧЕСКОЙ ПОМОЩИ НАСЕЛЕНИЮ В УСЛОВИЯХ ОМС 001. Основными путями развития поликлинической помощи взрослому населению в новых экономических условиях являются все...

Studopedia.info - Студопедия - 2014-2024 год . (0.009 сек.) русская версия | украинская версия