Array ( )
Вход:




Главная | OpenGL | GLSL | AI | Сеть | Примеры | Библиотека

OpenGL: Камера - часть 5 - Стрейф






Это последний урок по камере. Возможно, позже мы напишем пример движения камеры
по кривой безье. Этот урок показывает реализацию стрейфа камеры в стороны.
На первый взгляд всё выглядит несложно, но если вы не знаете линейной алгебры, у вас
могут возникнуть сложности.
Стрейф камеры - это движение по вектору, стоящему на 90 градусов от вектора взгляда.
Другими словами, это как если вы делаете шаг в сторону, смотря вперёд.

Поняв, что такое стрейфинг, рассмотрим, как он работает.
Мы знаем, что нам нужно двигаться в направлении 90 градусов от нашего вектора взгляда
(который == m_vView - m_vPosition). Итак, как нам получить вектор, перпендикулярный вектору
взгляда? Если вы вспомните формулу cross(), вы поймете, как это сделать. cross() - математическая
формула, принимающая 2 вектора (по сути плоскость), и возвращающая вектор, стоящий к ним на 90
градусов. Итак, у нас есть вектор взгляда. Где взять второй вектор? Приходит на ум
вертикальный вектор? Это он! Нам нужен результат cross-a между вектором взгляда и вертикальным
вектором. Результат работы функции будет нужным нам вектором. Во многих играх вертикальный вектор
будет меняться, потому как вы будете бегать, прыгать и летать в любых направлениях. Cross() даст
нам уверенность, что мы всегда стрейфимся в нужном направлении, не взирая на ориентацию камеры.

Файл init.cpp
Ничего не было изменено с прошлого урока.

Файл main.h

Внимание! Из файла убран класс камеры и помещён в camera.h!

Уберите из файла класс camera.h,
Уберите из файла строку
extern CCamera  g_Camera;


Файл camera.h
Внимание! Новый файл!
Этот файл был создан, чтобы вы могли использовать код камеры в собственных проектах,
без копипаста кода. Для этого этот файл и camera.cpp Должны быть добавлены в проект.

В класс камеры мы добавили контроль доступа к данным и несколько новых функций,
включая ф-ии управления доступом.

Содержание файла camera.h:

#ifndef _CAMERA_H
#define _CAMERA_H
 
class CCamera {
public:
CCamera();
 
/////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// *
    // Это функции для доступа извне к приватным данным
    CVector3 Position() {   return m_vPosition; }
    CVector3 View()     {   return m_vView; }
    CVector3 UpVector() {   return m_vUpVector; }
    CVector3 Strafe()   {   return m_vStrafe;}
/////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// *
 
    void PositionCamera(float positionX, float positionY, float positionZ,
                float viewX,     float viewY,     float viewZ,
                float upVectorX, float upVectorY, float upVectorZ);
 
    void RotateView(float angle, float X, float Y, float Z);
    void SetViewByMouse();
    void RotateAroundPoint(CVector3 vCenter, float X, float Y, float Z);
 
    // Новая функция - стрейф камеры
    void StrafeCamera(float speed);
 
    void MoveCamera(float speed);
 
    void CheckForMovement();
 
/////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// *
    // Функция обновляет взгляд камеры и другие данные
    void Update();
/////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// *
 
    // Функция использует gluLookAt(), чтобы сказать OpenGL, куда смотреть
    void Look();
 
private:
    CVector3 m_vPosition;
    CVector3 m_vView;
    CVector3 m_vUpVector;
    CVector3 m_vStrafe;
/////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// *
};
#endif





Файл camera.cpp
В этот файл мы добавили стрейфинг. Ещё 3 функции добавлены, чтобы ещё немного очистить main.cppp

//В начале файла включите camera.h
#include "main.h"
#include "camera.h"
 
// Добавьте в начало файла строку обьявления скорости камеры,
// а из main.cpp её удалите!
#define kSpeed  0.1f
 
 
// Удалите из файла функцию RotateAroundPoint().
 
 
///////////////////////////////// STRAFE CAMERA \\\\\\\\\\\\\\\\*
/////
/////              стрейфит камеру в стороны:
/////
///////////////////////////////// STRAFE CAMERA \\\\\\\\\\\\\\\\*
void CCamera::StrafeCamera(float speed)
{
    // добавим вектор стрейфа к позиции
    m_vPosition.x += m_vStrafe.x * speed;
    m_vPosition.z += m_vStrafe.z * speed;
 
    // Добавим теперь к взгляду
    m_vView.x += m_vStrafe.x * speed;
    m_vView.z += m_vStrafe.z * speed;
}
 
    // В функцию MoveCamera(), после строки
    // "CVector3 vVector = m_vView - m_vPosition;", добавьте:
    vVector.y = 0.0f;
    vVector = Normalize(vVector);
    // Теперь мы нормализуем наш вектор взгляда, когда двигаемся по миру.
    // Это НЕОБХОДИМО делать. Таким образом вы не будете двигатся быстрее, когда
    // стрейфитесь, т.к. вектор стрейфа тоже нормализован.
 
 
 
// Добавляем в класс следующие 3 функции:
 
//////////////////////////// CHECK FOR MOVEMENT \\\\\\\\\\\\\\*
/////
/////           обрабатываем ввод
/////
//////////////////////////// CHECK FOR MOVEMENT \\\\\\\\\\\\\\*
 
void CCamera::CheckForMovement()
{
    // нажаты ли ВВЕРХ или W
    if(GetKeyState(VK_UP) & 0x80 || GetKeyState('W') & 0x80) {
        MoveCamera(kSpeed);
    }
 
    // ВНИЗ или S
    if(GetKeyState(VK_DOWN) & 0x80 || GetKeyState('S') & 0x80) {
        MoveCamera(-kSpeed);
    }
 
    // LEFT или A
    if(GetKeyState(VK_LEFT) & 0x80 || GetKeyState('A') & 0x80) {
 
        // стрейфим влево
        StrafeCamera(-kSpeed);
    }
 
    // RIGHT или D
    if(GetKeyState(VK_RIGHT) & 0x80 || GetKeyState('D') & 0x80) {
        // стрейфим вправо
        StrafeCamera(kSpeed);
    }
}
 
 
///////////////////////////////// UPDATE \\\\\\\\\\\\\\\\*
/////
/////           Обновляет вектор взгляда и верт. вектор
/////
///////////////////////////////// UPDATE \\\\\\\\\\\\\\\\*
 
void CCamera::Update()
{
    // Ниже мы рассчитываем вектор стрейфа каждый раз, когда мы апдейтим
    // камеру. Это необходимо, т.к. значения используются во многих местах.
 
    // Иниц. переменную для результата cross
    CVector3 vCross = Cross(m_vView - m_vPosition, m_vUpVector);
 
    //Нормализуем вектор стрейфа
    m_vStrafe = Normalize(vCross);
 
    // Посмотрим, двигалась ли мыша
    SetViewByMouse();
 
    // Проверим нажатия
    CheckForMovement();
}
 
///////////////////////////////// LOOK \\\\\\\\\\\\\\\\*
/////
/////           Обновляет взгляд камеры
/////
///////////////////////////////// LOOK \\\\\\\\\\\\\\\\*
 
void CCamera::Look()
{
    // Дадим OpenGL позицию, взгляд и верт. вектор камеры
    gluLookAt(m_vPosition.x, m_vPosition.y, m_vPosition.z,
              m_vView.x,     m_vView.y,     m_vView.z,
              m_vUpVector.x, m_vUpVector.y, m_vUpVector.z);
}




Файл main.cpp

w, s, UP_ARROW, DOWN_ARROW - двигают камеру вперед-назад.
a, d, RIGHT_ARROW, LEFT_ARROW - стрейфят.
Движение мышью - изменение взгляда.
ESC - выход.

// В начале файла включите "camera.h"
#include "camera.h"

// Удалите функцию KeyPressed()

// В функции MainLoop() замените функцию KeyPressed(); на:

WPARAM MainLoop()
{
.....
.....
.....
        g_Camera.Update();
.....
.....
}

///////////////////////////////// DRAW SPIRAL TOWERS \\\\\\\\\\\\\\\\*
/////
/////   Новая функция!
/////   Рисуем спираль из пирамид в пространстве нашего мира
/////
///////////////////////////////// DRAW SPIRAL TOWERS \\\\\\\\\\\\\\\\*
 
void DrawSpiralTowers()
{
    const float PI = 3.14159f;
    const float kIncrease = PI / 16.0f;
    const float kMaxRotation = PI * 6;
    float radius = 40;
 
    for(float degree = 0; degree < kMaxRotation; degree += kIncrease)
    {
        float x = float(radius * cos(degree));
        float z = float(radius * sin(degree));
        CreatePyramid(x, 3, z, 1, 3);
        radius -= 40 / (kMaxRotation / kIncrease);
    }
}


///////////////////////////////// RENDER SCENE \\\\\\\\\\\\\\\\*
/////
/////   А RenderScene() теперь выглядит так:
/////
///////////////////////////////// RENDER SCENE \\\\\\\\\\\\\\\\*
 
void RenderScene()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
 
    // Вместо вызова gluLookAt() мы используем Look классы Camera.
    // Кроме подчистки RenderScene(), это ещё и более обьектно-ориентированный
    // подход. Если вы пишите движок, вам врядли нужны здесь специфические
    // вызовы API.
    g_Camera.Look();
 
    // Рисуем 3д сетку
    Draw3DSGrid();

    // Рисуем пирамиды спиралью в центре мира
    DrawSpiralTowers();
 
    SwapBuffers(g_hDC);
}
 
 
// В коде WinProc() в блоке WM_KEYDOWN: оставьте только обработку ESC-a:
    case WM_KEYDOWN:
        switch(wParam) {   
            case VK_ESCAPE:
                PostQuitMessage(0);
                break;
        }
        break;
 


На этом работа с классом камеры закончена.





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




Комментарии:

Войдите, чтобы оставить комментарий:












Яндекс.Метрика
 Яндекс цитирования.