Имитация полета крылатой ракеты на OpenGL WinApi C++

Автор: | 05.02.2018

Постановка задачи
Моделирование ландшафта
Моделирование траектории движения объектов
Моделирование сцены
Архитектура программы
Файлы-исходники приложения

Постановка задачи

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

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

Для решения задачи разработки программной системы, обеспечивающей  имитацию полета крылатой ракеты над пересеченной местностью к двигающейся цели необходимо создать модели:

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

Моделирование ландшафта

Ландшафт моделируется на основе карты высот. Для хранения карт высот используется необработанный формат файлов RAW (Terrain.raw). Этот формат просто читать, поскольку он не содержит заголовков с какой-либо информацией об изображении, такой как размер или тип изображения. Размер карты может быть произвольный, но удобней использовать квадратную, с размером стороны кратным 128: 128х128, 256х256 … 1024х1024.

В 8-разрядных картах высот каждый байт внутри файла RAW представляет высоту вершины. Значения высот варьируются от 0 до 255, где 0 представляет самую низкую высоту вершины, а 255 (FF в HEX) — максимально возможную высоту вершины. Можно расширить этот интервал, используя коэффициент масштабирования, который умножается на заданное значение высоты.

Чтобы построить ландшафт из карты высот сначала надо построить сетку вершин той же размерности, что и у карты высот, а затем использовать значение высоты точки (пикселя) из карты высот как высоту для вершины в сетке вершин. Точки выбираются через определенный шаг. Как известно, любая поверхность может быть  представлена треугольниками. Поэтому любые четыре расположенные рядом точки карты высот задают прямоугольник, который мы разбиваем на два треугольника и рисуем. В OpenGL для этой цели можно использовать примитив типа GL_TRIANGLE_STRIP .


Для раскраски ландшафта  можно применить интерполяцию цветов. Так, рисуя треугольник, необходимо каждой вершине задать разный цвет. При этом, OpenGL сам выполнит интерполяцию.

В OpenGL цвет одной точки изображения описывается тремя компонентами цвета Red, Green, Blue. Если определять все три или одну из компонент, как функцию высоты, то можно получить более качественное представление ландшафта — высокие точки будут более светлыми.

Моделирование траектории движения объектов

Над ландшафтом двигаются 2-а объекта – крылатая ракета и цель.  Траектория движения каждого из них определяется 4-я точками: pstart – начальная; ptarget – конечная; pcurrent – текущая; pnext – следующая после текущей.  Координата y точек определяется как функция высоты рельефа и координат x , z точки: y= Height(x,z).

Начальное положение цели и точка, куда она перемещается, определяются при помощи генератора случайных чисел. Координаты x и z точeк цели pstart и ptarget определяются при помощи генератора случайных чисел: x= rand(); z= rand(). Точка pstart ракеты находится в начале системы координат (при этом y= Height(0,0)), конечная точка ракеты совпадает с точкой pnext цели: pакета.ptarget = цель.pnext. Ракета и цель двигаются синхронно в пошаговом режиме – положение точек pcurrent и pnext определяется из параметрического уравнения отрезка прямой:

Поражение цели происходит при i=Ik.

Моделирование сцены

Задача решается на основе математического аппарата аффинных преобразований. Используются две системы координат.

В глобальной XYZ моделируется ландшафт, определяются точки траектории объектов и положение локальной системы координат. В локальной xyz создается модель ракеты. Модель ракеты представляется двумя взаимно-перпендикулярными треугольниками, модель цели — точкой большого размера. Положение локальной системы координат относительно глобальной определяется текущей точкой траектории ракеты, а также углами pci (рыскания), teta (тангажа) и gama (крена).

Текущие параметры определяются точками текущего положения ракеты (pcurrent и pnext ):

Запуск ракеты инициализируется нажатием на клавишу P (пуск). Параметры начального положения ракеты определяются начальным положением цели. Геометрические преобразования реализуются в OpenGL с помощью функций:

glTranslate (x, y, z) – производит перенос, прибавляя к координатам значения своих параметров;

glRotate (angle, x, y, z) – производит поворот объекта на угол angle вокруг вектора ( x,y,z );

gluLookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ) – направление взгляда на сцену.

Взрыв, когда ракета достигает цели, имитируется сферой или точкой большого размера.

Архитектура программы

Любое приложение с графическим интерфейсом должно иметь: окно для вывода изображения; возможности для создания в окне графических примитивов; возможности для взаимодействия с приложением.

Основой для создания такого приложения будет  оконное WinAPI приложении на C++ . Основными структурными компонентами оконного WinAPI приложении есть функция WinMain и оконная процедура. Первая отвечает за создание окна и организацию взаимодействия с окном (регистрация, бесконечный цикл), вторая – за обработку событий.  События идентифицируется именем константы (WM_PAINT,WM_DESTROY и др.).

Такая структуризация  позволяет программисту легко вносить изменения в программу. Выполнив изначальные настройки приложения в функции WinMain в дальнейшем он работает только с функцией окна, добавляя те или иные события и прописывая реакцию на них. Для решения задач рисования в окне не будем портить файл main.cpp, а  создадим новые блоки.

В программе реализованы следующие блоки:

  • блок, в котором происходит создание окна и обрабатываются сообщения операционной системы, реализован в файлe main.cpp;
  • графический движок, выполняющий отрисовку изображения.

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

Графические возможности оконного WinAPI приложения ограничены элементарными действиями по созданию примитивов на плоскости типа отрезка, окружности и т.п. Для их расширения необходимо создать аппарат афинных преобразований. Не будем изобретать велосипед и воспользуемся библиотекой   OpenGL, в функциях которой реализован этот аппарат.

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

Один из вариантов архитектуры системы представлен на рисунке.

Здесь в  классе Engine,  инкапсулированы данные и  функции,  устанавливающие взаимосвязь контекста устройства Windows с контекстом воспроизведения OpenGL, а также функции, обеспечивающие задание модели объекта ее преобразование и отрисовку.  В классе Track инкапсулированы текущие координаты и параметры объектов (ракеты и цели). Методы класса Land генерирует 3D-рельеф по точкам из карты высот.

Нелостатки такого разбиения:

  • объект цели не использует большое количество параметров и методов класса Track.
  • каждый из объектов класса Track имеет свой объект класса Land

Первый из недостатков можно ликвидировать благодаря схеме:

Оба недостатка можно ликвидировать благодаря схеме:

Файлы-исходники приложения

Файл рельефа земли RAW (Terrain.raw) помещается в созданную папку Data там же, где и основные файлы проекта.  Для запуска exe-шника папка Data дублируется в папке Debug проекта.

Header Files

api.h

#ifndef __API__
#define __API__
#include <windows.h> // Заголовочный файл для использования функций Windows
#include <stdio.h> // Заголовочный файл для стандартного ввода-вывода (НОВОЕ)
//#include <gl\gl.h> // Заголовочный файл библиотеки opengl32
#include <gl\glu.h> // Заголовочный файл библиотеки glu32
//#include "glaux.h" // Заголовочный файл библиотеки glaux
#include "glut.h" // Заголовочный файл библиотеки glut32
#endif

engine.h

#include "track.h"
#ifndef __ENGINE
#define __ENGINE
class Engine {
 GLsizei Height, Width;
 GLvoid DrawAxes(GLvoid); // Рисование осей
 GLvoid DrawModel(GLvoid); // Рисование модели
public:
 Track *track; // Объект - ракета
 Track *track1; // Объект - цель
 GLvoid Resize(GLsizei width, GLsizei height); // Функция, вызываемая при изменении размеров окна
 GLvoid Init(GLvoid); // Функция, для задания начальных параметров
 GLvoid Draw(GLvoid); // Отрисовка (render) сцены 
 int SetWindowPixelFormat(HDC hDC); //функция, которая устанавливает параметры контекста воспроизведения OpenGL 
};
#endif

geometry.h

#ifndef _POINT 
 struct _Point
 {
 double x, y, z;
 };
 #define _POINT
#endif

land.h

#include "api.h"
class Land {
 int MAP_SIZE; // Размер .RAW файла - количество точек по ширине (высоте)
 int STEP_SIZE; // точки рельефа выбираются через шаг 
 //BYTE *g_HeightMap; // массив точек из карты высот
 void SetVertexColor(int x, int y); // Эта функция устанавливает значение цвета в зависимости от высоты
public:
 BYTE *g_HeightMap; // массив точек из карты высот
 Land (void);
 void Init(void);
 int Height(int X, int Y); // возвращает высоту в точке
 void LoadRawFile(LPSTR strName); // Чтение и сохранение .RAW файла в g_HeightMap
 void RenderHeightMap(void); // Генерация 3D-рельефа по точкам из карты высот.
};

track.h

#include "api.h"
#include "land.h"
#include "geometry.h"

class Track {
 //int CNTRLS; // количество контрольных точек траектории
 double alpha_prev; //предыдущее значение угла alpha
public:
 int CNTRLS; // количество контрольных точек траектории
 Land *land;
 Track (void); // Конструктор для ракеты
 Track (int); // Конструктор для цели
 _Point pstart; // точка старта
 _Point ptarget; // точка цели
 _Point pcurrent; // текущая точка
 _Point pnext; // следующая точка
 double p,alpha, beta, gama, h;
 _Point CurrentPoint (int i); // Определяем текущие координаты объекта 
 void CurrentPrm (_Point &, _Point &, int); // Определяем текущие параметры объекта 
};

 

Source Files

main.cpp

//#include<windows.h>
#include "engine.h"
#include <math.h>

HWND hWnd;
HGLRC hGLRC;
HDC hDC;
Engine *engine; 
_Point mouse_point;
const unsigned int TIMER_2SEC = 1; // идентификаторы таймеров
bool p = true;
int i;
LRESULT CALLBACK WindowFunc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
float pos[4] = {3,3,3,1};
float dir[3] = {-1,-1,-1};
PAINTSTRUCT ps;
switch(msg)
{
case WM_CREATE:
 i=0;
engine = new Engine();
engine->track = new Track();
engine->track->land = new Land();
engine->track->land->Init();
engine->track1 = new Track(1);
engine->track1->land = new Land();
engine->track1->land->g_HeightMap = engine->track->land->g_HeightMap;
engine->track->pstart.y = engine->track->land->Height(engine->track->pstart.x,engine->track->pstart.z);
engine->track1->pstart.y= engine->track1->land->Height(engine->track1->pstart.x,engine->track1->pstart.z);
 // Расчет текущего положения ракеты
engine->track->CurrentPrm (engine->track->pcurrent, engine->track->pnext,0);
// Расчет текущего положения цели
engine->track1->CurrentPrm (engine->track1->pcurrent, engine->track1->pnext,0);
engine->track->ptarget = engine->track1->pstart;
//engine->track1->pstart = engine->track1->pcurrent;
hDC = GetDC(hWnd); // получаем контекст устройства нашего окна
engine->SetWindowPixelFormat(hDC); // устанавливаем параметры контекста воспроизведения OpenGL
hGLRC = wglCreateContext(hDC); // создаем контекст воспроизведения OpenGL
wglMakeCurrent(hDC, hGLRC); // делаем его текущим
engine->Init();
break;
case WM_TIMER: // обработка сообщения WM_TIMER 
 // Расчет текущего положения ракеты
engine->track->CurrentPrm (engine->track->pcurrent, engine->track->pnext,i);
// Расчет текущего положения цели
engine->track1->CurrentPrm (engine->track1->pcurrent, engine->track1->pnext,i);
engine->track->ptarget = engine->track1->pnext;
i=i+1;
if (i > engine->track->CNTRLS )KillTimer (hWnd,TIMER_2SEC); // уничтожение таймера
InvalidateRect(hWnd, NULL, FALSE); 
break;
case WM_KEYDOWN:
 int KeyPressed;
 KeyPressed = int(wParam);
 if (KeyPressed == int('P'))
 {
 if (p == true) {
 SetTimer(hWnd,TIMER_2SEC,150,NULL); // таймер срабатывает каждые две секунды
 p = false;
 } else {
 p = true;
 KillTimer (hWnd,TIMER_2SEC); // уничтожение таймеров
 }
 }
break;
case WM_DESTROY:
if (hGLRC) 
{ // удаляем созданный выше контекст воспроизведения OpenGL
wglMakeCurrent(NULL, NULL);
wglDeleteContext(hGLRC);
} // освобождаем контекст устройства нашего окна
ReleaseDC(hWnd, hDC);
PostQuitMessage(0);
break;
case WM_PAINT:
BeginPaint(hWnd, &ps);
engine->Draw();
EndPaint(hWnd, &ps);
break;
case WM_SIZE:
engine->Resize( LOWORD(lParam), HIWORD(lParam) );
break;
case WM_LBUTTONDOWN:
 mouse_point.x = LOWORD(lParam); // Координаты в системе окна
 mouse_point.y = HIWORD(lParam);
 break;
case WM_MOUSEMOVE:
 if (UINT(wParam) & MK_LBUTTON) 
 {
if (UINT(wParam) & MK_CONTROL) {
engine->track->gama += LOWORD(lParam) - mouse_point.x;
 } else {
 engine->track->alpha += (mouse_point.x - LOWORD(lParam))* 0.25;
 engine->track->beta += (mouse_point.y - HIWORD(lParam))* 0.25;
 }
 mouse_point.x = LOWORD(lParam); // Координаты в системе окна
 mouse_point.y = HIWORD(lParam);
 InvalidateRect(hWnd, NULL, FALSE);
 }
 break;
case WM_ERASEBKGND:
 return 1;
break;
default:
return DefWindowProc(hWnd,msg,wParam,lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hThisInst,HINSTANCE hPrevInst,LPSTR str,int nWinMode)
{
MSG msg;
WNDCLASS wcl;
wcl.hInstance=hThisInst;
wcl.lpszClassName = (LPCWSTR) "OpenGLWinClass";
wcl.lpfnWndProc = WindowFunc;
wcl.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
wcl.hIcon = NULL;
wcl.hCursor = LoadCursor(NULL,IDC_ARROW);
wcl.lpszMenuName = NULL;
wcl.cbClsExtra = 0;
wcl.cbWndExtra = 0;
wcl.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
RegisterClass(&wcl);
hWnd = CreateWindow((LPCWSTR) "OpenGLWinClass",L"Win32 OpenGL Template", 
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
200,
150,
400,
420,
HWND_DESKTOP, NULL,
hThisInst, NULL);
ShowWindow(hWnd,nWinMode);
UpdateWindow(hWnd);
while(1)
{
while( PeekMessage(&msg,NULL,0,0,PM_NOREMOVE) ) 
if(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
return 0;
}
return 0;
}

engine.cpp

#include "engine.h"
GLvoid Engine::Resize(GLsizei width, GLsizei height){
 if (height == 0) 
 {
 height = 1; 
 }
 glViewport(0, 0, width, height); // Устанавливается область просмотра
 Height = height;
 Width = width;
 glDepthRange(0, 1); //Глубина каждой точки записывается в z-буфер
 //с помощью которого OpenGL удаляет невидимые линии и поверхности
}
GLvoid Engine::Init(GLvoid){
 glClearColor(0.85f, 0.85f, 1.0f, 1.0f); // Устанавливается фон
 glEnable(GL_DEPTH_TEST); // Включается тест глубины
}
GLvoid Engine::Draw(GLvoid) 
{
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Очищается буфер кадра и буфер глубины
 // Текущая матрица сбрасывается на единичную
 glMatrixMode(GL_PROJECTION); // Действия будут производиться с матрицей проекции
 glLoadIdentity();
 gluPerspective (30, 1, 30, -30); // Устанавливается перспективная проекция 
 glMatrixMode(GL_MODELVIEW); // Действия будут производиться с матрицей модели
 glLoadIdentity(); 
 glTranslatef(0.0, -400, 0.0);
 gluLookAt (-1100, 1100, -1100, 0, 0, 0, 0, 1, 0); //Определяется вид ( Mview )
 DrawAxes(); //рисуются оси камеры 
 track->land->RenderHeightMap(); // Генерация 3D-рельефа по точкам из карты высот.
glPointSize(15.0);
 glColor3f(1.0,1.0,0.0);
glBegin(GL_POINTS);  
glVertex3f(track1->pcurrent.x, track1->pcurrent.y,track1->pcurrent.z );
 glEnd();
//Определяется матрица модели (Mmodel)
 glTranslatef(track->pcurrent.x, track->pcurrent.y, track->pcurrent.z); 
 glRotatef(track->alpha, 0.0, 1.0, 0.0);
 glRotatef(track->beta, 1.0, 0.0, 0.0); 
 glRotatef(track->gama, 0.0, 0.0, 1.0); 
 //определена матрица ( Mview * Mmodel)
 //определена матрица (Mprojection*Mview * Mmodel)
 // МОДЕЛИРОВАНИЕ
 //Рисуются оси модели (крылатой ракеты)
 glPushMatrix();
 glScalef(0.25, 0.25, 0.25); // Масштабирование по осям
 DrawAxes(); 
 glPopMatrix();
 //рисуется модель (крылатая ракета) 
 DrawModel();
 // моделируется взрыв
if (track->pcurrent.x== track1->pcurrent.x )
{
 glColor3d(1,0,0); // устанавливается цвет рисования
 //auxSolidSphere( 30 ); // сфера (радиус)
 glPointSize(30.0);
 glBegin(GL_POINTS);
 glVertex3f(0, 0, 0);
 glEnd();
} 
SwapBuffers(wglGetCurrentDC());
}
GLvoid Engine::DrawAxes(GLvoid) // Отрисовка осей
{
glColor3d(1,0,0);
 glBegin(GL_LINES); 
 glVertex3f (0,0,0); 
 glVertex3f (250,0,0); 
 glEnd();
glColor3d(0,1,0);
glBegin(GL_LINES); 
 glVertex3f (0,0,0); 
 glVertex3f (0,250,0); 
 glEnd();
glColor3d(0,0,250);
glBegin(GL_LINES); 
 glVertex3f (0,0,0); 
 glVertex3f (0,0,250); 
 glEnd();
 }
GLvoid Engine::DrawModel(GLvoid) // Отрисовка модели - крылатой ракеты
{
 glColor3d(1,0,0);
 glBegin(GL_TRIANGLES);
 glVertex3f(0,0,60);
 glVertex3f(0,0,0);
 glVertex3f(0,10,0);
glEnd();
glColor3d(0,0,1);
glBegin(GL_TRIANGLES);
 glVertex3f(0,0,60);
 glVertex3f(10,0,0);
 glVertex3f(-10,0,0);
glEnd();
glBegin(GL_LINES);
 glVertex3f(0,0,0);
 glVertex3f(0,0,-30);
glEnd();
 }
// код функции, которая устанавливает параметры контекста воспроизведения OpenGL. 
int Engine::SetWindowPixelFormat(HDC hDC)
{
int m_GLPixelIndex;
PIXELFORMATDESCRIPTOR pfd;
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | 
PFD_SUPPORT_OPENGL | 
PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 32;
pfd.cRedBits = 8;
pfd.cRedShift = 16;
pfd.cGreenBits = 8;
pfd.cGreenShift = 8;
pfd.cBlueBits = 8;
pfd.cBlueShift = 0;
pfd.cAlphaBits = 0;
pfd.cAlphaShift = 0;
pfd.cAccumBits = 64; 
pfd.cAccumRedBits = 16;
pfd.cAccumGreenBits = 16;
pfd.cAccumBlueBits = 16;
pfd.cAccumAlphaBits = 0;
pfd.cDepthBits = 32;
pfd.cStencilBits = 8;
pfd.cAuxBuffers = 0;
pfd.iLayerType = PFD_MAIN_PLANE;
pfd.bReserved = 0;
pfd.dwLayerMask = 0;
pfd.dwVisibleMask = 0;
pfd.dwDamageMask = 0;
// Передается на рассмотрение системе, выбранный нами формат пикселей. Функция просматривает в контексте устройства - hdc наиболее подходящий формат пикселей и выбирает его
m_GLPixelIndex = ChoosePixelFormat( hDC, &pfd);
if(m_GLPixelIndex==0) // Let's choose a default index.
{
m_GLPixelIndex = 1; 
if(DescribePixelFormat(hDC,m_GLPixelIndex,sizeof(PIXELFORMATDESCRIPTOR),&pfd)==0)
return 0;
}
// установить формат пикселей в контексте устройства
if (SetPixelFormat( hDC, m_GLPixelIndex, &pfd)==FALSE)
return 0;
return 1;
}

land.cpp

#include "land.h"
#include <stdlib.h>
#include <time.h>
#include <math.h>

Land::Land (void) 
 {
 MAP_SIZE = 1024; // количество точек по ширине (высоте)
 STEP_SIZE = 16; // точки выбираются через шаг
 //g_HeightMap = (BYTE *)malloc(sizeof(BYTE)*MAP_SIZE*MAP_SIZE); // массив точек из карты высот.
 /*LoadRawFile("Data/Terrain.raw");*/
 }
void Land::Init (void) 
 {
 g_HeightMap = (BYTE *)malloc(sizeof(BYTE)*MAP_SIZE*MAP_SIZE); // массив точек из карты высот.
 LoadRawFile((LPSTR)"Data/Terrain.raw");
 }
// Чтение и сохранение .RAW файла в pHeightMap
void Land::LoadRawFile(LPSTR strName)
{
 int nSize = MAP_SIZE * MAP_SIZE;
 FILE *pFile = NULL;
 // открытие файла в режиме бинарного чтения
 pFile = fopen(strName, "rb" );
 // Файл найден?
 if ( pFile == NULL ) 
 {
 // Выводим сообщение об ошибке и выходим из процедуры
 MessageBox(NULL, L"Can't Find The Height Map!", L"Error", MB_OK);
 return;
 }
 // Загружаем .RAW файл в массив g_HeightMap
 // Каждый раз читаем по одному байту, размер = ширина * высота
 fread( g_HeightMap, 1, nSize, pFile );
 // Проверяем на наличие ошибки
 int result = ferror( pFile );
 // Если произошла ошибка
 if (result)
 {
 MessageBox(NULL, L"Failed To Get Data!", L"Error", MB_OK);
 }
 // Закрываем файл
 fclose(pFile);
}
int Land::Height(int X, int Y) // This Returns The Height From A Height Map Index
{
 int x = X % MAP_SIZE; // Error Check Our x Value
 int y = Y % MAP_SIZE; // Error Check Our y Value
 if(!g_HeightMap) return 0; // Make Sure Our Data Is Valid
 return g_HeightMap[x + (y * MAP_SIZE)]; // Index Into Our Height Array And Return The Height
}
void Land::SetVertexColor(int x, int y)
{
 if(!g_HeightMap) return; // Данные корректны?
 float fColor = -0.15f + (Height(x, y ) / 256.0f);
 // Присвоить оттенок синего цвета для конкретной точки
 glColor3f(fColor/1.0, fColor/1.0, 0/*fColor/1.5*/);
}
void Land::RenderHeightMap(void) // This Renders The Height Map As Quads
{
 int X = 0, Y = 0; // Create Some Variables To Walk The Array With.
 int x, y, z; // Create Some Variables For Readability
 glColor3d(1,1,1); //цвет рисования
 if(!g_HeightMap) return; // Make Sure Our Height Data Is Valid
for ( X = 0; X < MAP_SIZE+1; X += STEP_SIZE )
 {
// каждая следующая вершина задает треугольник вместе с двумя предыдущими.
glBegin( GL_TRIANGLE_STRIP);
 for ( Y = 0; Y < MAP_SIZE+1; Y += STEP_SIZE*4 )
 {
 // Get The (X, Y, Z) Value For The Bottom Left Vertex
 x = X; 
 y = Height(X, Y ); 
 z = Y; 
 SetVertexColor(x, z);
 glVertex3i(x, y, z); // Send This Vertex To OpenGL To Be Rendered (Integer Points Are Faster)
// Get The (X, Y, Z) Value For The Bottom Right Vertex
 x = X + STEP_SIZE; 
 y = Height(X + STEP_SIZE, Y ); 
 z = Y;
 SetVertexColor(x, z);
 glVertex3i(x, y, z); // Send This Vertex To OpenGL To Be Rendered
 // Get The (X, Y, Z) Value For The Top Left Vertex
 x = X; 
 y = Height(X, Y + STEP_SIZE );
 //y = 0; 
 z = Y + STEP_SIZE ; 
 SetVertexColor(x, z); 
 glVertex3i(x, y, z); // Send This Vertex To OpenGL To Be Rendered
// Get The (X, Y, Z) Value For The Top Right Vertex
 x = X + STEP_SIZE; 
 y = Height(X + STEP_SIZE, Y + STEP_SIZE ); 
 //y = 0; 
 z = Y + STEP_SIZE ;
 SetVertexColor(x, z);
 glVertex3i(x, y, z); // Send This Vertex To OpenGL To Be Rendered
 }
glEnd();
}
}

track.cpp

#include "track.h"
#include <stdlib.h>
#include <time.h>
#include <math.h>
Track::Track (void) // Конструктор для ракеты
 {
 srand ( time(NULL) ); //инициализация генератора случайных чисел
 //ptarget.x= (rand() % 100)* 8 + 200; //генерация случайных чисел в диапазоне 200-1000
 //ptarget.z= (rand() % 100)* 8 + 200;
 CNTRLS = 40; // количество контрольных точек траектории
 p=0; beta=0, gama=0, h=0; alpha = atan(ptarget.x/ptarget.z)*180/3.14159;
 pstart.x= 0.0;
 pstart.z=0.0;
 }
Track::Track (int) // Конструктор для цели
 {
 srand ( time(NULL) ); //инициализация генератора случайных чисел
 ptarget.x= (rand() % 100)* 3 + 700; //генерация случайных чисел в диапазоне 200-1000
 ptarget.z= (rand() % 100)* 3 + 700;
 CNTRLS = 40; // количество контрольных точек траектории 
 p=0; beta=0, gama=0, h=0; /*alpha = atan(ptarget.x/ptarget.y)*180/3.14159;*/
 pstart.x= (rand() % 100)* 4 + 550; //генерация случайных чисел в диапазоне 200-1000
 pstart.z= (rand() % 100)* 4 + 550;
 }_Point Track::CurrentPoint(int i) // Определяем текущую точку объекта
{
 int DH = 20; // высота над поверхностью 
 _Point pcurrent; // текущая точка
 pcurrent.x = pstart.x + (ptarget.x - pstart.x) * i / (CNTRLS-1); 
 pcurrent.z = pstart.z + (ptarget.z - pstart.z) * i / (CNTRLS-1); 
 pcurrent.y = land->Height(pcurrent.x, pcurrent.z)+ DH;
 /*glPointSize(15.0);
 glColor3f(1.0,1.0,1.0);
 glBegin(GL_POINTS); 
 glVertex3i(pcurrent.x, pcurrent.y, pcurrent.z);
 glEnd();*/
return pcurrent;
}
void Track::CurrentPrm (_Point &pcurrent, _Point &pnext, int i) // Определяем текущие параметры объекта 
{
double dx,dy,dz,dl,dalpha;
// Расчет текущего положения ракеты
pcurrent = CurrentPoint(i);
pnext = CurrentPoint(i+1);
dx= pnext.x - pcurrent.x;
dy= pnext.y - pcurrent.y;
dz= pnext.z - pcurrent.z;
dl = sqrt ( pow(dx,2) + pow(dy,2)+ pow(dz,2));
beta = -(asin (dy/dl)*180/3.14159);
alpha_prev = alpha;
alpha = atan (dx/dz)*180/3.14159;
dalpha=alpha_prev - alpha;
gama = 30*dalpha;
//pstart.x += dx;
//pstart.y += dy;
//pstart.z += dz;
}

 

Автор: Николай Свирневский

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *