OpenGL---三维世界中摄像机的构建

21 篇文章 1 订阅
12 篇文章 0 订阅

原理:《逐梦旅程:windows游戏编程之从零开始》第21章

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

utils.h

#pragma once

#include "iostream"
#include "math.h"
using namespace std;

class Vector3;
Vector3 operator - (const Vector3 &v1, const Vector3 &v2);
Vector3 operator * (const Vector3 &v, const float f);
Vector3 operator + (const Vector3 &v1, const Vector3 &v2);

class Vector3
{
public:
    float x, y, z;

    Vector3()
    {
        x = y = z = 0;
    }

    Vector3(float xx, float yy, float zz)
    {
        x = xx;
        y = yy;
        z = zz;
    }

    Vector3(Vector3 &v)
    {
        x = v.x;
        y = v.y;
        z = v.z;
    }

    void set(float dx, float dy, float dz)
    {
        x = dx;
        y = dy;
        z = dz;
    }

    void set(Vector3 &v)
    {
        x = v.x;
        y = v.y;
        z = v.z;
    }

    //翻转该向量
    void flip() 
    {
        x = -x;
        y = -y;
        z = -z;
    }

    Vector3 cross(Vector3 &v);  //返回和b叉乘的结果
    float dot(Vector3 &b);      //返回和b点积的结果
    float len();                //返回向量的长度
    void normalize();           //调整该向量到单位长度
    friend Vector3 operator - (const Vector3 &v1, const Vector3 &v2);
    friend Vector3 operator + (const Vector3 &v1, const Vector3 &v2);
    friend Vector3 operator * (const Vector3 &v, const float f);
};

utils.cpp

#include "Utils.h"

//返回和b叉乘的结果
Vector3 Vector3::cross(Vector3 &b)  
{
    Vector3 v(y*b.z - z*b.y, z*b.x - x*b.z, x*b.y - y*b.x);
    return v;
}

//返回和b点乘的结果
float Vector3::dot(Vector3 &b)
{
    return x*b.x + y*b.y + z*b.z;
}

//把该向量调整到单位长度
void Vector3::normalize()
{
    double len = x*x + y*y + z*z;
    if(len < 0.000001)
    {
        cerr << "\n零向量!";
        return;
    }
    float scale = 1.0 / sqrt(len);
    x *= scale;
    y *= scale;
    z *= scale;
}

//返回向量的长度
float Vector3::len()
{
    return sqrt(x*x + y*y + z*z);
}

Vector3 operator - (const Vector3 &v1, const Vector3 &v2)
{
    return Vector3(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
}

Vector3 operator * (const Vector3 &v, const float f)
{
    return Vector3(v.x*f,  v.y*f,  v.z*f);
}

Vector3 operator + (const Vector3 &v1, const Vector3 &v2)
{
    return Vector3(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z);
}

camera.h


#pragma once

#include <windows.h> 
#include <gl/Gl.h>
#include <gl/Glu.h>
#include <gl/glut.h>
#include "utils.h"

class CameraClass
{
private:
    //成员变量的声明
    Vector3             m_vLeftVector;         // 左分量向量
    Vector3             m_vLookVector;         // 观察方向向量
    Vector3             m_vUpVector;           // 上分量向量
    Vector3             m_vCameraPosition;     // 摄像机位置的向量
    Vector3             m_vTargetPosition;     // 目标观察位置的向量
    float               m_matView[16];

public:
    //四个Set系列函数,注意他们参数都有默认值NULL的,调用时不写参数也可以
    //设置摄像机、目标观察位置向量
    void Set(Vector3 *pCameraPosition = NULL, Vector3 *pTargetPosition = NULL);  
    void SetViewMatrix();        //设置取景变换矩阵
    void SetShape(float vAngle, float asp, float nr, float fr); //设置视椎体

public:
    // 沿各分量平移的三个函数
    void MoveAlongLeftVec(float fUnits);    // 沿left向量移动
    void MoveAlongUpVec(float fUnits);      // 沿up向量移动
    void MoveAlongLookVec(float fUnits);    // 沿look向量移动

    // 绕各分量旋转的三个函数
    void RotationLeftVec(float fAngle);     // 绕left向量旋转
    void RotationUpVec(float fAngle);       // 绕up向量旋转
    void RotationLookVec(float fAngle);     // 绕look向量旋转

public:
    //构造函数和析构函数
    CameraClass();                          // 构造函数
    virtual ~CameraClass(void);             // 析构函数
};

camera.cpp

#include "camera.h"

#define PI 3.14159265

// 构造函数
CameraClass::CameraClass()
{
    m_vLeftVector  = Vector3(1.0f, 0.0f, 0.0f);   // 默认左向量与X正半轴重合
    m_vUpVector    = Vector3(0.0f, 1.0f, 0.0f);   // 默认上向量与Y正半轴重合
    m_vLookVector  = Vector3(0.0f, 0.0f, 1.0f);   // 默认观察向量与Z正半轴重合
    m_vCameraPosition  = Vector3(0, 0, 4);        // 默认摄像机坐标
    m_vTargetPosition  = Vector3(0, 0, 0);        // 默认观察目标位置
    memset(m_matView, 0, sizeof(m_matView));
}

// 析构函数
CameraClass::~CameraClass(void) 
{

}

//设置相机位置,观察点位置
void CameraClass::Set(Vector3 *pCameraPosition, Vector3 *pTargetPosition)
{
    //先看看pCameraPosition是否为默认值NULL
    if (pCameraPosition != NULL)  
        m_vCameraPosition = (*pCameraPosition);
    else 
        m_vCameraPosition = Vector3(0.0f, 0.0f, 4.0f);

    //先看看pTargetPosition是否为默认值NULL
    if (pTargetPosition != NULL)  
        m_vTargetPosition = (*pTargetPosition);
    else 
        m_vTargetPosition = Vector3(0.0f, 0.0f, 0.0f);

    //观察点位置减摄像机位置,得到观察方向向量
    m_vLookVector = m_vCameraPosition - m_vTargetPosition; 

    SetViewMatrix();
}

//设置取景变换矩阵
void CameraClass::SetViewMatrix()
{
    m_vLeftVector = m_vUpVector.cross(m_vLookVector);      //左向量与观察向量垂直
    m_vUpVector = m_vLookVector.cross(m_vLeftVector);      //上向量与左向量、观察向量垂直

    m_vLeftVector.normalize();                             //规范化左向量
    m_vUpVector.normalize();                               //规范化上向量
    m_vLookVector.normalize();                             //规范化m_vLookVector向量

    //依次写出取景变换矩阵的第一行
    m_matView[0] = m_vLeftVector.x;           
    m_matView[1] = m_vUpVector.x;              
    m_matView[2] = m_vLookVector.x;            
    m_matView[3] = 0.0f;
    //依次写出取景变换矩阵的第二行
    m_matView[4] = m_vLeftVector.y;           
    m_matView[5] = m_vUpVector.y;              
    m_matView[6] = m_vLookVector.y;           
    m_matView[7] = 0.0f;
    //依次写出取景变换矩阵的第三行
    m_matView[8] = m_vLeftVector.z;           
    m_matView[9] = m_vUpVector.z;              
    m_matView[10] = m_vLookVector.z;            
    m_matView[11] = 0.0f;
    //依次写出取景变换矩阵的第四行
    m_matView[12] =  -m_vCameraPosition.dot(m_vLeftVector);
    m_matView[13] =  -m_vCameraPosition.dot(m_vUpVector);
    m_matView[14] =  -m_vCameraPosition.dot(m_vLookVector);
    m_matView[15] = 1.0f;

    //取景变换
    glMatrixMode(GL_MODELVIEW);
    glLoadMatrixf(m_matView);
}

//设置视椎体
void CameraClass::SetShape(float vAngle, float asp, float nr, float fr)
{
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    //gluPerspective(viewAngle, aspect, nearDis, farDis)
    //viewAngle: 视锥体的上下平面的角度,相当于眼睛睁开的程度
    //aspect: 观察平面的裁剪窗口的横纵比(w/h),最好和屏幕的一致
    //nearDis: 视截体近体距离
    //farDis: 视截体远景距离
    gluPerspective(vAngle, asp, nr, fr);
    glMatrixMode(GL_MODELVIEW);
}

// 沿left向量移动
void CameraClass::MoveAlongLeftVec(float fUnits) 
{
    //直接乘以fUnits的量来累加就行了
    m_vCameraPosition.set(m_vCameraPosition + m_vLeftVector * fUnits);

    SetViewMatrix();
}

// 沿up向量移动
void CameraClass::MoveAlongUpVec(float fUnits)
{
    //直接乘以fUnits的量来累加就行了
    m_vCameraPosition.set(m_vCameraPosition + m_vUpVector * fUnits);

    SetViewMatrix();
}

// 沿look向量移动
void CameraClass::MoveAlongLookVec(float fUnits)
{
    //直接乘以fUnits的量来累加就行了
    m_vCameraPosition.set(m_vCameraPosition + m_vLookVector * fUnits);

    SetViewMatrix();
}

// 绕left向量旋转
void CameraClass::RotationLeftVec(float fAngle)     
{
    fAngle = PI / 180 * fAngle;
    float cs = cos(fAngle);
    float sn = sin(fAngle);

    Vector3 v1(m_vUpVector);
    Vector3 v2(m_vLookVector);
    m_vUpVector.set(v1 * cs - v2 * sn);
    m_vLookVector.set(v1 * sn + v2 * cs);

    SetViewMatrix();
}

// 绕up向量旋转
void CameraClass::RotationUpVec(float fAngle)
{
    fAngle = PI / 180 * fAngle;
    float cs = cos(fAngle);
    float sn = sin(fAngle);

    Vector3 v1(m_vLookVector);
    Vector3 v2(m_vLeftVector);
    m_vLookVector.set(v1 * cs - v2 * sn);
    m_vLeftVector.set(v1 * sn + v2 * cs);

    SetViewMatrix();
}

// 绕look向量旋转
void CameraClass::RotationLookVec(float fAngle)
{
    fAngle = PI / 180 * fAngle;
    float cs = cos(fAngle);
    float sn = sin(fAngle);

    Vector3 v1(m_vLeftVector);
    Vector3 v2(m_vUpVector);
    m_vLeftVector.set(v1 * cs - v2 * sn);
    m_vUpVector.set(v1 * sn + v2 * cs);

    SetViewMatrix();
}

调用

定义:

CameraClass *camera;

初始化:

    camera = new CameraClass();
    Vector3 cameraPosition(0, 0, 4);
    Vector3 targetPosition(0, 0, 0);
    camera->Set(&cameraPosition, &targetPosition);  
    camera->SetShape(30.0f, WINDOW_WIDTH / WINDOW_HEIGHT, 0.5f, 50.0f);

响应键盘:

void myKeyboard(unsigned char key, int x, int y)
{
    switch(key)
    {
        case 'a': case 'A': camera->MoveAlongLeftVec(-0.01); break;
        case 'd': case 'D': camera->MoveAlongLeftVec(0.01); break;
        case 'w': case 'W': camera->MoveAlongUpVec(0.01); break;
        case 's': case 'S': camera->MoveAlongUpVec(-0.01); break;
        case 'q': case 'Q': camera->MoveAlongLookVec(0.01); break;
        case 'e': case 'E': camera->MoveAlongLookVec(-0.01); break;

        case 'j': case 'J': camera->RotationUpVec(1); break;
        case 'l': case 'L': camera->RotationUpVec(-1); break;
        case 'i': case 'I': camera->RotationLeftVec(1); break;
        case 'k': case 'K': camera->RotationLeftVec(-1); break;
        case 'u': case 'U': camera->RotationLookVec(1); break;
        case 'o': case 'O': camera->RotationLookVec(-1); break;
        default: break;
    }
    glutPostRedisplay();      //重新绘制
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值