Как вы наверное могли уже понять нам понадобятся кватернионы и классы для работы с DirectInput'ом (статьи по этим темам можно посмотреть на этом сайте в разделах Алгоритмы и DirectX->DirectInput8 соответственно). Поэтому приступим сразу к реализации камеры.
Первым делом нам надо настроить сопособ проецирования (между ортогональной проекцией и перспективной мы ни минуты не сомневаясь выберем последнюю). Делается это так:
//выбираем матрицу которую будем устанавливать glMatrixMode( GL_PROJECTION ); //загружаем единичную матрицу glLoadIdentity(); //устанавливаем перспективную проекцию с углом обзора в 60 градусов //ближней плоскостью отсечения на расстоянии 1 и дальней на расстоянии 1000 //здесь же 1.33 – это отношение ширины экрана к высоте (800/600) gluPerspective( 60 , 1.33 , 1 , 1000 );
Как вы видите мы здесь использовали функцию gluPerspective, которая как видно про префиксу «glu» является частью библиотеки утилит. Для того чтобы компиляция прошла без ошибок, вам надо будет подключить файл glu.h и либку glu32.lib. Например так:
#pragma comment ( lib , "glu32.lib" )
Реализация класса камеры.
class Camera{ public: Vector4 target , norm , eye; Camera( void ){} Camera( Vector4 e , Vector4 n , Vector4 t ){ eye = e; norm = n; target = t; } //basik movement functions void MoveLeft( void ); void MoveRight( void ); void MoveForward( void ); void MoveBackward( void ); void MoveUp( void ); void MoveDown( void ); //input functions void KeyboardInput( Keyboard & ); void MouseInput( Mouse & , int , int ); //init functions void ReInitCamera( void ); void InitCamera( Vector4 , Vector4 , Vector4 ); //camera rotation functions void SpinAlongY( float );//Y - norm };
Здесь поля target , norm , eye - это соответственно вектор направления взгляда, вектор вертикали вида, и координаты точки визирования. Для облегчения восприятия рекомендую обратить свой взор на рисунок:
Теперь быстренько пробежимся по методам класса. «Быстренко» потому что они до безобразия простые.
void Camera::MoveUp( void ){ eye += CAM_VELOSITY * norm; } void Camera::MoveDown( void ){ eye -= CAM_VELOSITY * norm; } void Camera::MoveLeft( void ){ eye += CAM_VELOSITY * ( norm * target ); } void Camera::MoveRight( void ){ eye += CAM_VELOSITY * ( target * norm ); } void Camera::MoveForward( void ){ eye += CAM_VELOSITY * target; } void Camera::MoveBackward( void ){ eye -= CAM_VELOSITY * target; } void Camera::KeyboardInput( cKeyboard &Keyboard ){ Keyboard.GetKeyboardState(); if( Keyboard.GetButtonState( DIK_W ) )MoveForward(); if( Keyboard.GetButtonState( DIK_S ) )MoveBackward(); if( Keyboard.GetButtonState( DIK_A ) )MoveLeft(); if( Keyboard.GetButtonState( DIK_D ) )MoveRight(); ReInitCamera(); } void Camera::ReInitCamera( void ){ glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); gluLookAt( eye.x , eye.y , eye.z , eye.x + target.x , eye.y + target.y , eye.z + target.z , norm.x , norm.y , norm.z ); } void Camera::InitCamera( cVector4 EYE , cVector4 TARGET , cVector4 NORM ){ eye = EYE; target = TARGET; norm = NORM; ReInitCamera(); } void Camera::SpinAlongX( float Angle ){ cQuaternion ry; ry.fRy( Angle ); target = ry * target; } void Camera::MouseInput( cMouse &Mouse , int SCREEN_WIDTH , int SCREEN_HEIGHT ){ float x( Mouse.GetOffset( 0 ) ); float AngleX( ( ( float ) -x ) / 300 ); SpinAlongX( AngleX ); SetCursorPos( SCREEN_WIDTH / 2 , SCREEN_HEIGHT / 2 ); ReInitCamera(); }
Здесь CAM_VELOSITY – это некоторая константа, которая хранит скорость перемещения камеры. Далее:
//сообщаем системе, что сейчас будем менять матрицу вида glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); //передаем параметры положения камеры gluLookAt( eye.x , eye.y , eye.z , eye.x + target.x , eye.y + target.y , eye.z + target.z , norm.x , norm.y , norm.z );
Вот вроде и все. Просто да?
Исходники можно скачать здесь.