Начальный код взят из прошлого урока — «Камера — часть 1». В этом уроке мы научимся вращать камеру.
Итак, приступим.
файл init.cpp остается без изменений.
В файл main.h мы добавим только прототип функции вращения в класс камеры:
public:
…….
…….
…….
// Эта ф-я вращает камеру вокруг позиции в зависимости от переданных параметров.
// Ротация сделана как осево-угловое вращение. Это значит, что вы передаете
// ф-ии угол вращения и ось, вокруг которой нужно вращатся.
void RotateView(float angle, float x, float y, float z);
};
Далее мы напишем реализацию вращения камеры.
Добавим новую функцию в файл camera.cpp:
/////
///// Вращение камеры вокруг оси
/////
///////////////////////////////// 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) & 0x80)
g_Camera.MoveCamera(kSpeed);if(GetKeyState(VK_DOWN) & 0x80)
g_Camera.MoveCamera(—kSpeed);//Вращаем вокруг оси Y
if(GetKeyState(VK_LEFT) & 0x80) // Если нажали «влево»
g_Camera.RotateView(kSpeed*2,0,1,0); // Вращаем с положит. скоростьюif(GetKeyState(VK_RIGHT) & 0x80) // Если «вправо»
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().
Позже мы сделаем управление мышью, как в большинстве шутеров.
Также можно сделать какие-нибуть стены и уровни, чтобы можно было даже пройтись по нашему миру =)