Array ( )
Вход:




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

OpenGL: Камера - часть 4 - Вид от третьего лица






Этот урок демонстрирует способ программирования вида от 3 лица.
На самом деле есть еще немало вещей, связанных с ним, но тут показаны основы.
Сделано всё действительно просто. Вместо вращения вектора взгляда вокруг позиции
мы просто вращаем нашу позицию вокруг точки, куда смотрим. Я просто взял
RotateView() и поменял в ней местами m_vView и m_vPosition.
Однако, мы используем точку vCenter, так как нам может понадобится вращяться вокруг
другой точки, не вектора взгляда. Это расширяемый способ, позволяющий вращаться не только
вокруг фиксированной точки.

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

Файл main.h
В описание класса камеры мы добавили функцию RotateAroundPoin().
Это позволило нам вращать камеру вокруг некой точки (В случае игры - вокруг игрового
персонажа).

class CCamera {
public:
..........
..........
..........
    // Функция вращает камеру вокруг точки (например вашего персонажа).
    // vCenter - Точка, вокруг которой она вращается.
    void RotateAroundPoint(CVector3 vCenter, float angle, float x, float y, float z);
..........
..........
};



В класс камеры мы добавили функцию RotateAroundPoint(). Она принимает точку,
вокруг которой требуется вращаться, ось вращения и требуемый угол.

Файл camera.cpp:
///////////////////////////////// ROTATE AROUND POINT \\\\*
/////
/////   This rotates the position around a given point
/////
///////////////////////////////// ROTATE AROUND POINT \\\\*
 
void CCamera::RotateAroundPoint(CVector3 vCenter, float angle, float x, float y, float z)
{
    CVector3 vNewPosition;
 
    // Чтобы вращать нашу позицию вокруг точки, всё, что нам надо - найти вектор
    // от нашей позиции к центральной точке вращения. Один раз получив вектор,
    // мы вращаемся вокруг точки с заданной скоростью/углом.
    // Новый вектор vCenter - точка, вокруг которой мы вращаемся.
 
    // Получим центр, вокруг которого нужно вращатся
    CVector3 vPos = m_vPosition - vCenter;
 
    // Вычислим синус и косинус угла
    float cosTheta = (float)cos(angle);
    float sinTheta = (float)sin(angle);
 
    // Найдем значение X точки вращения
    vNewPosition.x  = (cosTheta + (1 - cosTheta) * x * x)       * vPos.x;
    vNewPosition.x += ((1 - cosTheta) * x * y - z * sinTheta)   * vPos.y;
    vNewPosition.x += ((1 - cosTheta) * x * z + y * sinTheta)   * vPos.z;
 
    // И значение Y
    vNewPosition.y  = ((1 - cosTheta) * x * y + z * sinTheta)   * vPos.x;
    vNewPosition.y += (cosTheta + (1 - cosTheta) * y * y)       * vPos.y;
    vNewPosition.y += ((1 - cosTheta) * y * z - x * sinTheta)   * vPos.z;
 
    // И Z...
    vNewPosition.z  = ((1 - cosTheta) * x * z - y * sinTheta)   * vPos.x;
    vNewPosition.z += ((1 - cosTheta) * y * z + x * sinTheta)   * vPos.y;
    vNewPosition.z += (cosTheta + (1 - cosTheta) * z * z)       * vPos.z;
 
    // Теперь просто прибавим новый вектор к нашей позиции,
    // чтобы установить новую позицию камеры.
    m_vPosition = vCenter + vNewPosition;
}


Файл main.cpp
Тут мы только изменяем реакцию на input, а также отрисовку сцены.

///////////////////////////////////////////////////////////////////////////
/////
/////   Добавьте эту функцию в файл main.cpp
/////   Это обработка клавиш, заменяем ею CheckForMovement()
/////
///////////////////////////////////////////////////////////////////////////
void KeyPressed()
{
    if(GetKeyState(VK_UP) & 0x80) {             // если нажата "ВВЕРХ"
        g_Camera.MoveCamera(kSpeed);            // Движемся вперед
    }
    if(GetKeyState(VK_DOWN) & 0x80) {           // Если нажата "ВНИЗ"
        g_Camera.MoveCamera(-kSpeed);           // Назад
    }
 
 
    // Мы сделали два изменения с прошлого урока. Вместо gCamera.RotateView()
    // мы используем новую ф-ю RotateAroundPoint(), передавая ей точку
    // взгляда камеры.
    if(GetKeyState(VK_LEFT) & 0x80) {
        // Вращаем вокруг оси Y с положительной скоростью
        g_Camera.RotateAroundPoint(g_Camera.m_vView, kSpeed, 0, 1, 0);
    }
    if(GetKeyState(VK_RIGHT) & 0x80) {
        // А тут - с отрицательной
        g_Camera.RotateAroundPoint(g_Camera.m_vView, -kSpeed, 0, 1, 0);
    }
}

///////////////////////////////// CREATE PYRAMID \\\\*
/////
/////   Новая функция.
/////   Создает пирамиду с центром в X,Y,Z
/////   Ширина и высота передаются в ф-ю.
/////
///////////////////////////////// CREATE PYRAMID \\\\*
 
void CreatePyramid(float x, float y, float z, int width, int height)
{
    // Ниже мы создаем пирамиду. Её составляют 4 треугольника по бокам и квадрат внизу.

    // 4 треугольника для сторон:
    glBegin(GL_TRIANGLES);
        // Задняя сторона
        glColor3ub(255, 0, 0);   glVertex3f(x, y + height, z);
        glColor3ub(0, 255, 255); glVertex3f(x - width, y - height, z - width);
        glColor3ub(255, 0, 255); glVertex3f(x + width, y - height, z - width);
 
        // Передняя сторона
        glColor3ub(255, 0, 0);   glVertex3f(x, y + height, z);
        glColor3ub(0, 255, 255); glVertex3f(x + width, y - height, z + width);
        glColor3ub(255, 0, 255); glVertex3f(x - width, y - height, z + width);
 
        // Левая сторона
        glColor3ub(255, 0, 0);   glVertex3f(x, y + height, z);
        glColor3ub(255, 0, 255); glVertex3f(x - width, y - height, z + width);
        glColor3ub(0, 255, 255); glVertex3f(x - width, y - height, z - width);
 
        // Правая сторона
        glColor3ub(255, 0, 0);   glVertex3f(x, y + height, z);
        glColor3ub(255, 0, 255); glVertex3f(x + width, y - height, z - width);
        glColor3ub(0, 255, 255); glVertex3f(x + width, y - height, z + width);
    glEnd();
 
    // Теперь дно пирамиды
    glBegin(GL_QUADS);
        glColor3ub(0, 0, 255); glVertex3f(x - width, y - height, z + width);
        glColor3ub(0, 0, 255); glVertex3f(x + width, y - height, z + width);
        glColor3ub(0, 0, 255); glVertex3f(x + width, y - height, z - width);
        glColor3ub(0, 0, 255); glVertex3f(x - width, y - height, z - width);
    glEnd();
}


///////////////////////////////// DRAW 3D GRID \\\\*
/////
/////   Ещё одна новая функция.
/////   Она создаёт простую сетку для лучшего восприятия анимации
/////
///////////////////////////////// DRAW 3D GRID \\\\*
 
void Draw3DSGrid()
{
    // Просто рисуем по 100 зеленых линий вертикально и горизонтально по осям X и Z
 
    glColor3ub(0, 255, 0);
 
    // Рисуем сетку 1х1 вдоль осей
    for(float i = -50; i <= 50; i+=1)
    {
        glBegin(GL_LINES);
            // Ось Х
            glVertex3f(-50, 0, i);
            glVertex3f(50, 0, i);
 
            // Ось Z
            glVertex3f(i, 0, -50);
            glVertex3f(i, 0, 50);
        glEnd();
    }
}

///////////////////////////////// RENDER SCENE \\\\*
/////
/////   Отрисовка сцены теперь выглядит так:
/////
///////////////////////////////// RENDER SCENE \\\\*
 
void RenderScene()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
 
 
    //Скормим 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);

    //Рисуем сетку
    Draw3DSGrid();
 
    // Создаем 4 пирамиды, просто для ориентирования в мире
    CreatePyramid(-6, 3, 6, 1, 6);
    CreatePyramid(6, 3, 6, 1, 6);
    CreatePyramid(6, 3, -6, 1, 6);
    CreatePyramid(-6, 3, -6, 1, 6);
 
    // Переместим "персонажа" в точку нашего взгляда. Таким образом
    // мы всегда будем смотреть на обьект, а обьект всегда будет перед нами,
    // куда бы мы не передвигались.
    glTranslatef(g_Camera.m_vView.x, 0, g_Camera.m_vView.z);
 
    // Теперь создаем 2 пирамиды, одна из которых перевернута.
    CreatePyramid(0, 2, 0, 1, 1);
    glRotatef(180, 1, 0, 0);
    CreatePyramid(0, -1, 0, 1, 1);



//*************************************************************************
    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glLoadIdentity();
    glOrtho( 0,SCREEN_WIDTH,SCREEN_HEIGHT, 0,0, 1 );
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
//*************************************************************************

    CalculateFrameRate();
    glDisable(GL_DEPTH_TEST);
        glColor3f(1.0f,1.0f,1.0f);
        wchar_t buf[256];
        swprintf(buf, sizeof(buf), L"Текущие FPS: %f", FPS);

        Font->Print(10,20, buf);  // Выводим текст
    glEnable(GL_DEPTH_TEST);


//*************************************************************************
    glMatrixMode( GL_PROJECTION );
    glPopMatrix();
    glMatrixMode( GL_MODELVIEW );
//*************************************************************************



 
    SwapBuffers(g_hDC);
}

// Ну и последнее, в функции MainLoop() замените вызов CheckForMovement() на KeyPressed().
 


Вот и всё. Теперь, скомпилировав программу, вы сможете клавишами влево и вправо вращаться
вокруг "персонажа", а клавишами вперед и назад - перемещать его =)







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




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

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












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