В цикле уроков «Камера» мы научимся двигатся в нашем мире, управляя клавиатурой, а впоследствии и мышью. Этот, первый урок камеры, задаст базу для дальнейшего развития.
Здесь мы создадим класс камеры и научимся хоть как-то двигаться.

Первоначальный код взят из предидущего урока, «FPS».

Итак, первый файл, main.h.
В него мы добавим обьявления классов CVector и CCamera.
Возможно, вы обратите внимание, что этот хидер немного беспорядочный — позже мы создадим другой хидер и разделим данные.

Также в хидер мы добавим глобальный экземпляр класса CCamera — gCamera.
Таким образом любой файл сможет получить доступ к позиции и направлению камеры.

Файл main.h:

// К остальным инклудам добавим math.h — он нам пригодится.
#include <math.h>// *Vector Class*
// Это начало нашего класса «Vector». В начале он будет совсем простой, но по мере роста класс
// повысит функциональность, возникнет больше типов данных.
// Отныне мы будем использовать его для класса камеры.
// Пока что нам нужно просто запоминание X,Y,Z. Пока это будет больше похоже на
// структуру, а не на класс. class CVector3 {    // Буква «C» перед именем означает, что перед нами класс.

public:     // Мы не будем использовать контроль доступа и запихнем всё в public.
float x, y, z;  // Просто float для X,Y,Z
};

// *Camera Class*
// Будет использоватся для запоминания позиции камеры, нашего взгляда и вертикального вектора.
// Сейчас у нас есть 3 CVector’а, которые будут запоминать эту информацию.
// Кроме того, пара вспомогательных функций. Мы сделаем все данные
// public, чтобы в любой момент узнать свою позицию.
// Т.к. все данные — public, можно было использовать структуру.
// Но я стараюсь все, что содержит в себе методы, делать классом.

class CCamera {

public:

CVector3 m_vPosition;   // Позиция камеры.
CVector3 m_vView;   // Направление камеры.
CVector3 m_vUpVector;   // Вертикальный вектор.

//В начале переменных подписываем «m», т.к. это «member»-переменные.
//»v» добавляем, т.к. это члены класса Vector (начинается на V).

// Конструктор класса Camera
CCamera();

// Тут изменяется положение, направление и верт. вектор камеры.
// В основном используется при инициализации.
void PositionCamera(float positionX, float positionY, float positionZ,
float viewX,     float viewY,     float viewZ,
float upVectorX, float upVectorY, float upVectorZ);

// Эта ф-я передвигает камеру вперед/назад
void MoveCamera(float speed);
};

// Ну и наконец добавим глобальную переменную данных камеры.
extern CCamera  g_Camera;           // Глобальные данные камеры

// Все остальное в файле остаётся без изменений.

 

Файл Init.cpp остался без изменений.

Теперь переходим к файлу camera.cpp, в котором будет описана реализация класса камеры.
Для начала реализуем простое перемещение вперед-назад, усложнять будем в следующих уроках.
Файл camera.cpp:

// Включаем наш хидер
#include «main.h»///////////////////////////////// CCAMERA \\\\\\\\\\\\\\\\*
/////
/////   Конструктор класса CCamera
/////
///////////////////////////////// CCAMERA \\\\\\\\\\\\\\\\*CCamera::CCamera()
{
//Инициализируем вектор нашей позиции в нулевые координаты
CVector3 vZero = { 0.0, 0.0, 0.0 };
CVector3 vView = { 0.0, 1.0, 0.5 };     // Иниц. вектор взгляда
CVector3 vUp = { 0.0, 0.0, 1.0 };       // Вертикальный вектор

m_vPosition = vZero;
m_vView = vView;
m_vUpVector = vUp;
}

///////////////////////////////// POSITION CAMERA \\\\\\\\\\\\\\\\*
/////
/////   Устанавливает позицию, взгляд, верт. вектор камеры
/////
///////////////////////////////// POSITION CAMERA \\\\\\\\\\\\\\\\*

GLvoid CCamera::PositionCamera(float positionX, float positionY, float positionZ,
float viewX, float viewY, float viewZ,
float upVectorX, float upVectorY, float upVectorZ)
{
CVector3 vPosition  = {positionX, positionY, positionZ};
CVector3 vView      = {viewX, viewY, viewZ};
CVector3 vUpVector  = {upVectorX, upVectorY, upVectorZ};

//Обширный код просто делает легче назначение переменных.
//Можно просто сразу присвоить переменным класса переданные функции значения.

m_vPosition = vPosition;
m_vView = vView;
m_vUpVector = vUpVector;
}

///////////////////////////////// MOVE CAMERA \\\\\\\\\\\\\\\\*
/////
/////   Движение камеры вперед-назад с заданной скоростью
/////
///////////////////////////////// MOVE CAMERA \\\\\\\\\\\\\\\\*

void CCamera::MoveCamera(float speed)
{
CVector3 vVector = {0};     //Иниц. вектор направления взгляда

// Получаем вектор направления. Чтобы получить вектор из 2х
// точек, мы вычитаем первую точку из второй.
// Это дает нам направление, куда мы смотрим.
// Позже мы напишем ф-ю, вычисляющую направление
// по-другому.

//Получаем направление взгляда (напр-е, куда мы повернуты «лицом»)
vVector.x = m_vView.x m_vPosition.x;      //Направление по X
vVector.y = m_vView.y m_vPosition.y;      //Направление по Y
vVector.z = m_vView.z m_vPosition.z;      //Направление по Z

// Следующий код двигает камеру вперед или назад.
// Мы прибавляем к текущему положению направление взгляда, помноженное на скорость.
// Может быть, вы думаете, что проще было бы просто прибавить к позиции скорость. Да,
// сейчас это сработает — вы смотрите прямо по оси Х. Но как только начнется вращение, код
// перестанет действовать. Поверьте мне.
// Итак, если мы смотрим в направлении 45 градусов, мы и пойдем в этом направлении.
// Если движемся назад — просто передаём в ф-ю отрицательную скорость.

m_vPosition.x += vVector.x * speed;
m_vPosition.z += vVector.z * speed;
m_vView.x += vVector.x * speed;
m_vView.y += vVector.z * speed;

}

// Это всё. Совсем не сложный класс, позволяющий нам хоть как-то двигаться в мире =)

 

Ну а теперь используем наш новый класс.
Файл main.cpp:

// Где-нибуть вверху файла добавьте:
#define kSpeed  0.03f           //Как быстро движется камера// Обьявим класс камеры, определённый как extern в main.h :
CCamera g_Camera;// В функцию Init() добавим определение камеры.
// Теперь функция выглядит так:
void Init(HWND hWnd)
{
g_hWnd = hWnd;
GetClientRect(g_hWnd, &g_rRect);
InitializeOpenGL(g_rRect.right, g_rRect.bottom);

Font = new CFont(«arial.ttf»,16,16);
FPS=0;

// Ниже мы инициализируем камеру. Устанавливаем позицию, из которой будем смотреть на
// цветной треугольник.
// Помните, эта инициализация необходима только _единожды_,
// и больше мы её вызывать не будем.

//          Позиция      Напр-е     верт. вектор
g_Camera.PositionCamera(0, 0.5f, 6,   0, 0.5f, 0,   0, 1, 0);
}

//*************************************************************************
// В функции RenderScene(), после вызова CalculateFrameRate(), добавьте:

// Скормим OpenGL данные камеры
gluLookAt(g_Camera.m_vPosition.x, g_Camera.m_vPosition.y, g_Camera.m_vPosition.z,
g_Camera.m_vView.x,     g_Camera.m_vView.y,     g_Camera.m_vView.z,
g_Camera.m_vUpVector.x, g_Camera.m_vUpVector.y,g_Camera.m_vUpVector.z);

// И рисуем треугольнег =)
glBegin (GL_TRIANGLES);
glColor3ub(255, 0, 0);
glVertex3f(0, 1, 0);

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

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

//*************************************************************************

// И, наконец, внесём изменения в функцию WinProc, в секцию обработки клавиш.
// Теперь код case WM_KEYDOWN выглядит так:
case WM_KEYDOWN:
switch(wParam)
{
case VK_ESCAPE:
PostQuitMessage(0); // Выходим
break;

case VK_UP:         // Если нажали «вверх»
// Движемся вперед — с положительной скоростью
g_Camera.MoveCamera(kSpeed);
RenderScene();      // Перерисовываем сцену
break;

case VK_DOWN:           // Если «вниз»
// Движемся назад — с отрицательной скоростью
g_Camera.MoveCamera(kSpeed);
RenderScene();          // Перерисовываем сцену
break;
}
break;
//*************************************************************************

 

Это всё. Если вы скомпилируете программу, то сможете двигатся вперед назад около небольшого треугольника, нарисованного для ориентировки.
В дальнейших уроках мы расширим функционал камеры, добавим вращение, стрейф и многое другое.

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