В цикле уроков «Камера» мы научимся двигатся в нашем мире, управляя клавиатурой, а впоследствии и мышью. Этот, первый урок камеры, задаст базу для дальнейшего развития.
Здесь мы создадим класс камеры и научимся хоть как-то двигаться.
Первоначальный код взят из предидущего урока, «FPS».
Итак, первый файл, main.h.
В него мы добавим обьявления классов CVector и CCamera.
Возможно, вы обратите внимание, что этот хидер немного беспорядочный — позже мы создадим другой хидер и разделим данные.
Также в хидер мы добавим глобальный экземпляр класса CCamera — gCamera.
Таким образом любой файл сможет получить доступ к позиции и направлению камеры.
Файл main.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;
//*************************************************************************
Это всё. Если вы скомпилируете программу, то сможете двигатся вперед назад около небольшого треугольника, нарисованного для ориентировки.
В дальнейших уроках мы расширим функционал камеры, добавим вращение, стрейф и многое другое.