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

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

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






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



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

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

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

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

Различие эмпиризма и рационализма Родоначальником эмпиризма стал английский философ Ф. Бэкон. Основной тезис эмпиризма гласит: в разуме нет ничего такого...

Индекс гингивита (PMA) (Schour, Massler, 1948) Для оценки тяжести гингивита (а в последующем и ре­гистрации динамики процесса) используют папиллярно-маргинально-альвеолярный индекс (РМА)...

Методика исследования периферических лимфатических узлов. Исследование периферических лимфатических узлов производится с помощью осмотра и пальпации...

Йодометрия. Характеристика метода Метод йодометрии основан на ОВ-реакциях, связанных с превращением I2 в ионы I- и обратно...

Броматометрия и бромометрия Броматометрический метод основан на окислении вос­становителей броматом калия в кислой среде...

Метод Фольгарда (роданометрия или тиоцианатометрия) Метод Фольгарда основан на применении в качестве осадителя титрованного раствора, содержащего роданид-ионы SCN...

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