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

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

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






В данном разделе мы рассмотрим как можно смоделировать управление примитивным летательным аппаратом. Предположим, что сцена, вокруг которой должен летать наш самолет, представляет собой три стоящие недалеко друг от друга геометрические фигуры: куб, тетраэдр и додекаэдр. Мы хотим смоделировать изменения сцены, которые могли бы наблюдаться из окна летательного аппарата при управлении тремя характерными для всех летательных аппаратов углами: крена, атаки и курса (азимута), которые влияют на положение в пространстве самого летательного аппарата. Мы будем хранить эти значения в трех глобальных переменных: 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; просмотров: 503. Нарушение авторских прав; Мы поможем в написании вашей работы!



Композиция из абстрактных геометрических фигур Данная композиция состоит из линий, штриховки, абстрактных геометрических форм...

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

ТЕОРЕТИЧЕСКАЯ МЕХАНИКА Статика является частью теоретической механики, изучающей условия, при ко­торых тело находится под действием заданной системы сил...

Теория усилителей. Схема Основная масса современных аналоговых и аналого-цифровых электронных устройств выполняется на специализированных микросхемах...

Виды сухожильных швов После выделения культи сухожилия и эвакуации гематомы приступают к восстановлению целостности сухожилия...

КОНСТРУКЦИЯ КОЛЕСНОЙ ПАРЫ ВАГОНА Тип колёсной пары определяется типом оси и диаметром колес. Согласно ГОСТ 4835-2006* устанавливаются типы колесных пар для грузовых вагонов с осями РУ1Ш и РВ2Ш и колесами диаметром по кругу катания 957 мм. Номинальный диаметр колеса – 950 мм...

Философские школы эпохи эллинизма (неоплатонизм, эпикуреизм, стоицизм, скептицизм). Эпоха эллинизма со времени походов Александра Македонского, в результате которых была образована гигантская империя от Индии на востоке до Греции и Македонии на западе...

Выработка навыка зеркального письма (динамический стереотип) Цель работы: Проследить особенности образования любого навыка (динамического стереотипа) на примере выработки навыка зеркального письма...

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

Правила наложения мягкой бинтовой повязки 1. Во время наложения повязки больному (раненому) следует придать удобное положение: он должен удобно сидеть или лежать...

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