OpenGL: Камера — часть 2 — Вращение

Начальный код взят из прошлого урока — «Камера — часть 1». В этом уроке мы научимся вращать камеру.
Итак, приступим.

файл init.cpp остается без изменений.

В файл main.h мы добавим только прототип функции вращения в класс камеры:

class CCamera:
public:
.......
.......
.......
// Эта ф-я вращает камеру вокруг позиции в зависимости от переданных параметров.
// Ротация сделана как осево-угловое вращение. Это значит, что вы передаете
// ф-ии угол вращения и ось, вокруг которой нужно вращатся.
void RotateView(float angle, float x, float y, float z);
};

 

Далее мы напишем реализацию вращения камеры.
Добавим новую функцию в файл camera.cpp:

///////////////////////////////// ROTATE VIEW \\\\*
/////
/////                     Вращение камеры вокруг оси
/////
///////////////////////////////// ROTATE VIEW \\\\*void CCamera::RotateView(float angle, float x, float y, float z)
{
CVector3 vNewView;
CVector3 vView;// Получим наш вектор взгляда (направление, куда мы смотрим)
vView.x = m_vView.x m_vPosition.x;    //направление по X
vView.y = m_vView.y m_vPosition.y;    //направление по Y
vView.z = m_vView.z m_vPosition.z;    //направление по Z// Теперь, имея вектор взгляда, хранящийся в CVector3 «vView», мы можем вращать его.
// Эта ф-я будет вызыватся, когда нужно повернутся налево-направо.
// Итак, нам нужно вращаться вокруг нашей позиции. Представьте это примерно так:
// скажем, мы стоим на месте, смотря вперед. Мы смотрим в какую-то точку, верно?
// Теперь, если мы повернем голову налево или направо, направление взгляда изменится.
// Соответственно переместится точка, на которую мы смотрим (вектор взгляда).
// Вот почему мы изменяем m_vView — потому что это и есть вектор
// взгляда. Мы будем вращать m_vView вокруг m_vPosition
// по кругу, чтобы реализовать всё это.
// Чтобы вращать что-то, используем синус и косинус. Для использования sin () & cos () мы
// ранее подключили math.h.
//
// Чтобы реализовать вращение камеры, мы будем использовать axis-angle вращение.
// Я должен предупредить, что формулы для рассчета вращения не очень просты, но
// занимают не много кода. Axis-angle вращение позволяет нам вращать точку в пространстве
// вокруг нужной оси. Это значит, что мы можем взять нашу точку взгляда (m_vView) и
// вращать вокруг нашей позиции.
// Чтобы лучше понять следующие рассчеты, советую вам посмотреть детальное
// описание: http://astronomy.swin.edu.au/~pbourke/geometry/rotate/// Рассчитаем 1 раз синус и косинус переданного угла
float cosTheta = (float)cos(angle);
float sinTheta = (float)sin(angle);

// Найдем новую позицию X для вращаемой точки
vNewView.x  = (cosTheta + (1 cosTheta) * x * x)   * vView.x;
vNewView.x += ((1 cosTheta) * x * y z * sinTheta)   * vView.y;
vNewView.x += ((1 cosTheta) * x * z + y * sinTheta)   * vView.z;

// Найдем позицию Y
vNewView.y  = ((1 cosTheta) * x * y + z * sinTheta)   * vView.x;
vNewView.y += (cosTheta + (1 cosTheta) * y * y)   * vView.y;
vNewView.y += ((1 cosTheta) * y * z x * sinTheta)   * vView.z;

// И позицию Z
vNewView.z  = ((1 cosTheta) * x * z y * sinTheta)   * vView.x;
vNewView.z += ((1 cosTheta) * y * z + x * sinTheta)   * vView.y;
vNewView.z += (cosTheta + (1 cosTheta) * z * z)   * vView.z;

// Теперь просто добавим новый вектор вращения к нашей позиции, чтобы
// установить новый взгляд камеры.
m_vView.x = m_vPosition.x + vNewView.x;
m_vView.y = m_vPosition.y + vNewView.y;
m_vView.z = m_vPosition.z + vNewView.z;
}

 

Теперь включим вращение в нашем главном файле, main.cpp.
Кроме того, мы уберём обработку клавиш из WinProc (), так как это не самый быстрый способ.

Файл main.cpp

// Добавим в файл функцию обработки ввода:
//////////////////////////// CHECK FOR MOVEMENT \\\*
/////
/////   Эта функция обрабатывает нажатия клавиатуры быстрее WinProc ()
/////
//////////////////////////// CHECK FOR MOVEMENT \\\*void CheckForMovement()
{
// Функция GetKeyState () возвращает true или false
// в зависимости от того, нажата ли переданная ей клавиша.
if(GetKeyState(VK_UP) & 0×80)
g_Camera.MoveCamera(kSpeed);if(GetKeyState(VK_DOWN) & 0×80)
g_Camera.MoveCamera(kSpeed);//Вращаем вокруг оси Y
if(GetKeyState(VK_LEFT) & 0×80)         // Если нажали «влево»
g_Camera.RotateView(kSpeed*2,0,1,0);    // Вращаем с положит. скоростьюif(GetKeyState(VK_RIGHT) & 0×80)        // Если «вправо»
g_Camera.RotateView(kSpeed*2,0,1,0);   // С отрицательной
}

// Далее, немного изменим функцию MainLoop (). Перед вызовом функции
// RenderScene () вызовем только что написанную CheckForMovement ():
///////////////////////////////// MAIN GAME LOOP \\\\*
/////
/////               Основной игровой цикл
/////
///////////////////////////////// MAIN GAME LOOP \\\\*

WPARAM MainLoop()
{
.............................................
.............................................
.............................................
CheckForMovement();
RenderScene();
.............................................
.............................................
}

// Немного изменим функцию RenderScene (). Вместо одного треугольника
// нарисуем 10, расположенных вертикально:

void RenderScene()
{
.............................................
//Рисуем треугольнег =)
glBegin (GL_TRIANGLES);

//Нарисуем 10 3угольников в ряд
for(float i = 10; i < 0; i++){
glColor3ub(255, 0, 0);
glVertex3f(0, 1, i);

glColor3ub(0, 255, 0);
glVertex3f(1, 0, i);

glColor3ub(0, 0, 255);
glVertex3f(1, 0, i);
}

glEnd();
SwapBuffers(g_hDC);
}

// Ну и наконец WinProc (). Уберём из него обработку всех клавиш кроме VK_ESCAPE:
case WM_KEYDOWN:
switch(wParam) {
case VK_ESCAPE:
PostQuitMessage(0);
break;
}
break;

 

В этом уроке мы научили камеру вращатся. Также мы поправили ввод с клавиатуры, убрав его из WinProc ().
Позже мы сделаем управление мышью, как в большинстве шутеров.
Также можно сделать какие-нибуть стены и уровни, чтобы можно было даже пройтись по нашему миру =)

Исходные коды к уроку

Понравилась статья? Поделиться с друзьями: