用于OpenGl的Camera类(QT实现的3D摄像机类)

最近在搞QT上的OPENGL,有好多库都要自己写啊
哐哧哐哧写了一大顿,已经写好了,回过头来记录一下
这篇讲的时关于opengl自由摄像机的问题
写摄像机的思路是,写一个万能的摄像机基类,可以支持各种基本操作(没有添加左右晃镜头的功能)
然后如果你需要用到什么样的摄像机,继承基类,然后重写他的移动函数和改变镜头方向函数(这两个函数为虚函数)
这样的话,你不用考虑是什么类型的摄像机,把摄像机基类指针传过去然后就可以自动调用你自己写的函数
!!!!!
注意此类用的是右手坐标系
!!!!!

代码如下:

基类摄像机

// camera.h
#pragma once
#ifndef CAMERA_H
#define CAMERA_H
#include<QObject>
#include<QVector3D>
#include<QVector4D>
#include<QMatrix4x4>
#include<QtMath>
namespace LB
{
/*
     this is the coordinate be using

               ^ z
               |
               |
               |
               /----------> y
              /
             /
            V  x

*/


    class Camera:public QObject
    {
        Q_OBJECT
    public:
// pre_declare
        enum Direction{
            None=0,
            Up=1,
            Down=2,
            Left=3,
            Right=4,
            Front=5,
            Rear=6
        };
        Q_ENUMS(Direction)
// function
        Camera();
        virtual ~Camera(){}
        void setCameraPosition(QVector3D p);
        void setSpeedMove(float s);
        void setSpeedWaggle(float s);
        void setDirectionUp(QVector3D d);
        void setDirectionLook(QVector3D d);
        void setVerticalAngle(float a);
        void setAspectRatio(float a);
        void setNearPlane(float n);
        void setFarPlane(float f);
// operate function
        virtual void move(Direction d);
        virtual void waggle(Direction d);
        virtual void printInfo();   // Debug Method
// get status function
        QVector4D getCameraPosition() const;
        QVector4D getDirectionLook() const;
        QVector4D getDirectionUp() const;
        float getSpeedMove() const;
        float getSpeedWaggle() const;
        float getVerticalAngle() const;
        float getAspetRatio() const;
        float getNearPlane() const;
        float getFarPlane() const;
//  get matrix
        QMatrix4x4 getViewMatrix();
        QMatrix4x4 getViewMatrixLeftHand();
        QMatrix4x4 getProjectionMatrix();
    protected:
        QVector4D position;
        // the position of the free_camera

        QVector4D direction_look;
        //the look_direction

        QVector4D  direction_up;

        float speed_move;
        // the speed of camera moving

        float speed_waggle;
        // the speed of camera wagglling

        float vertical_angle;
        // angle of vertical field

        float aspect_ratio;
        // ration of width/height

        float near_plane;
        // the projection's near plane

        float far_plane;
        // the projection's far plane
    };
}
#endif // CAMERA_H

// camera.cpp
#include "camera.h"

LB::Camera::Camera():
    position(1.0f,0.0f,0.0f,1.0f),
    direction_look(-1.0f,0.0f,0.0f,0.0f),
    direction_up(0.0f,0.0f,1.0f,0.0f),
    speed_move(0.02f),
    speed_waggle(0.05f),
    vertical_angle(90),
    aspect_ratio(1.0f),
    near_plane(1.0f),
    far_plane(100.0f)
{}

void LB::Camera::setCameraPosition(QVector3D p)
{
    auto tem=p.toVector4D();
    tem.setW(1.0f);
    position=tem;
}

void LB::Camera::setSpeedMove(float s)
{
    speed_move=s;
}

void LB::Camera::setSpeedWaggle(float s)
{
    if(s<90&&s>0)
    speed_waggle=s;
    else
    {
        qDebug()<<"Error: can't set speed_waggle";
        qDebug()<<"Reason: speed_waggle you set  <=0 or >=90";
    }
}

void LB::Camera::setDirectionUp(QVector3D d)
{
    // new direction_up
    d.normalize();

    // direction_look
    auto d_look=direction_look.toVector3D();

    if(d==d_look||d==-d_look)
    {
        qDebug()<<"Error: set direction_up failed";
        qDebug()<<"Reason: direction_up you set is parallel to the direction_look";
        return;
    }
    else
    {
        // new direction_left
        auto d_left_n=QVector3D::crossProduct(d,d_look);

        // set direction_up
        auto up=QVector3D::crossProduct(d_look,d_left_n);
        up.normalize();
        direction_up=up.toVector4D();
    }
}

void LB::Camera::setDirectionLook(QVector3D d)
{
    // new direction_look
    d.normalize();

    // direction_look
    auto d_up=direction_up.toVector3D();

    if(d==d_up||d==-d_up)
    {
        qDebug()<<"Error: set Direction_look failed";
        qDebug()<<"Reason: Direction_look you set is Parallel to the Direction_up";
        return;
    }
    else
    {
       // set the direction_look
       direction_look=d.toVector4D();

       // set the direction_up
       auto d_left=QVector3D::crossProduct(d_up,d);
       auto up=QVector3D::crossProduct(d,d_left);
       up.normalize();
       direction_up=up.toVector4D();
    }
}

void LB::Camera::setVerticalAngle(float a)
{
    if(a>0&&a<180)
    vertical_angle=a;
    else
    {
        qDebug()<<"Error: fail to set Vertical Angle";
        qDebug()<<"Reason: value you set <= 0 or >= 180";
    }
}

void LB::Camera::setAspectRatio(float a)
{
    if(a>0||a*vertical_angle<180)
        aspect_ratio=a;
    else
    {
        qDebug()<<"Error: fail to set Aspect Angle";
        qDebug()<<"Reason: value you set <= 0 or (Vertical Angle * it >= 180_";
    }
    return;
}

void LB::Camera::setNearPlane(float n)
{
    if(n>0&&n<far_plane)
        near_plane=n;
    else
    {
        qDebug()<<"Error: fail to set Near Plane";
        qDebug()<<"Reason: value you set <=0 or >=far_plane";
    }
}

void LB::Camera::setFarPlane(float f)
{
    if(f>near_plane)
        far_plane=f;
    else
    {
        qDebug()<<"Error: fail to set Near Plane";
        qDebug()<<"Reason: value you set <=near_Plane";
    }
}

void LB::Camera::printInfo()
{
    qDebug()<<"----- Print Camera Info : -----";
    qDebug()<<" Camera Position :";
    qDebug()<<Camera::getCameraPosition();
    qDebug()<<" Camera Look Direction :";
    qDebug()<<Camera::getDirectionLook();
    qDebug()<<" Camera Up Direction :";
    qDebug()<<Camera::getDirectionUp();
    qDebug()<<"================================";
}

void LB::Camera::move(Camera::Direction d)
{
    QVector3D direction_left;
    switch (d) {
    case Camera::Up:
        position+=direction_up*speed_move;
        break;
    case Camera::Down:
        position-=direction_up*speed_move;
        break;
    case Camera::Left:
        direction_left=QVector3D::crossProduct(direction_up.toVector3D(),direction_look.toVector3D());
        direction_left.normalize();
        position+=direction_left*speed_move;
        break;
    case Camera::Right:
        direction_left=QVector3D::crossProduct(direction_up.toVector3D(),direction_look.toVector3D());
        direction_left.normalize();
        position-=direction_left*speed_move;
        break;
    case Camera::Front:
        position+=direction_look*speed_move;
        break;
    case Camera::Rear:
        position-=direction_look*speed_move;
        break;
    default:
        qDebug()<<"the direction you move is not set";
        break;
    }
}

void LB::Camera::waggle(Camera::Direction d)
{
    QMatrix4x4 matrix_rotate;
    QVector4D d_look;
    QVector3D direction_left;
    switch (d) {
    case Camera::Up:
        direction_left=QVector3D::crossProduct(direction_up.toVector3D(),direction_look.toVector3D());
        direction_left.normalize();
        matrix_rotate.rotate(-speed_waggle,direction_left);
        d_look=matrix_rotate*direction_look;
        setDirectionLook(d_look.toVector3D());
        break;
    case Camera::Down:
        direction_left=QVector3D::crossProduct(direction_up.toVector3D(),direction_look.toVector3D());
        direction_left.normalize();
        matrix_rotate.rotate(speed_waggle,direction_left);
        d_look=matrix_rotate*direction_look;
        setDirectionLook(d_look.toVector3D());
        break;
    case Camera::Left:
        matrix_rotate.rotate(speed_waggle,direction_up.toVector3D());
        d_look=matrix_rotate*direction_look;
        setDirectionLook(d_look.toVector3D());
        break;
    case Camera::Right:
        matrix_rotate.rotate(-speed_waggle,direction_up.toVector3D());
        d_look=matrix_rotate*direction_look;
        setDirectionLook(d_look.toVector3D());
        break;
    default:
        qDebug()<<"the direction you wggle is not set";
        break;
    }
}

QVector4D LB::Camera::getCameraPosition() const
{
    return position;
}

QVector4D LB::Camera::getDirectionLook() const
{
    return direction_look;
}

QVector4D LB::Camera::getDirectionUp() const
{
    return direction_up;
}

float LB::Camera::getSpeedMove() const
{
    return speed_move;
}

float LB::Camera::getSpeedWaggle() const
{
    return speed_waggle;
}

float LB::Camera::getVerticalAngle() const
{
    return vertical_angle;
}

float LB::Camera::getAspetRatio() const
{
    return aspect_ratio;
}

float LB::Camera::getNearPlane() const
{
    return near_plane;
}

float LB::Camera::getFarPlane() const
{
    return far_plane;
}

QMatrix4x4 LB::Camera::getProjectionMatrix()
{
    QMatrix4x4 matrix;
    matrix.perspective(vertical_angle,aspect_ratio,near_plane,far_plane);
    return matrix;
}

QMatrix4x4 LB::Camera::getViewMatrix()
{
    QMatrix4x4 matrix;
    matrix.lookAt(position.toVector3D(),(position+direction_look).toVector3D(),direction_up.toVector3D());
    return matrix;
}


QMatrix4x4 LB::Camera::getViewMatrixLeftHand()
{
    QVector3D p=position.toVector3D();
    QVector3D look=(position+direction_look).toVector3D();
    QVector3D up=direction_up.toVector3D();
    p.setZ(-p.z());
    look.setZ(-look.z());
    up.setZ(-up.z());
    QMatrix4x4 matrix;
    matrix.lookAt(p,look,up);
    return matrix;
}

============================================

自定义的定点摄像机:

// fixcamera.h

#pragma once
#ifndef FIXCAMERA_H
#define FIXCAMERA_H
#include <camera.h>

namespace LB
{
    class FixCamera: public Camera
    {
    public:
        FixCamera();
        FixCamera(QVector3D fixPosition);
        FixCamera(QVector3D fixPosition,QVector3D cameraPosition);
        virtual ~FixCamera(){}
        void setFixPosition(QVector3D p);

        // operate function
        virtual void move(Direction d);

        // get status function
        QVector4D getFixPosition() const;

    private:
        QVector4D fix_position;
    };
}
#endif // FIXCAMERA_H

// fixcamera.cpp

#include "fixcamera.h"


LB::FixCamera::FixCamera()
{
    Camera::Camera();
    fix_position=QVector4D(0.0f,0.0f,0.0f,1.0f);
}

LB::FixCamera::FixCamera(QVector3D fixPosition)
{
    FixCamera();
    if(fixPosition!=position.toVector3D())
    {
        Camera::setCameraPosition(position.toVector3D());
        Camera::setDirectionLook(fixPosition-position.toVector3D());
    }
    else
    {
        qDebug()<<"Error: can't set fix position";
        qDebug()<<"Reason: fix position you set is same to camera position";
    }
}

LB::FixCamera::FixCamera(QVector3D fixPosition, QVector3D cameraPosition)
{
    FixCamera();
    if(fixPosition!=cameraPosition)
    {
        position=cameraPosition;
        fix_position=fixPosition;
        setDirectionLook(fixPosition-position.toVector3D());
    }
    else
    {
        qDebug()<<"Error: can't set fix position";
        qDebug()<<"Reason: fix position you set is same to camera position";
    }
}

void LB::FixCamera::setFixPosition(QVector3D p)
{
    if(fix_position!=position)
    {
        fix_position=p;
        Camera::setDirectionLook(getFixPosition().toVector3D()-p);
        Camera::setDirectionUp(QVector3D(0.0f,0.0f,1.0f));
    }
    else
    {
        qDebug()<<"Error: can't set fix position";
        qDebug()<<"Reason: fix position you set is same to camera position";
    }
}


void LB::FixCamera::move(Camera::Direction d)
{
    QVector4D p;
    QVector4D t;
    QMatrix4x4 r;
    double distance=position.toVector3D().distanceToPoint(fix_position.toVector3D());
    float a;

    switch (d)
    {
    case Camera::Up:
        a=qRadiansToDegrees(qAsin(-Camera::getDirectionLook().z()));

        if(a+speed_waggle>=90)
            return;
        else
        {
            Camera::waggle(Camera::Down);
            Camera::setCameraPosition((getFixPosition()-Camera::getDirectionLook()*distance).toVector3D());
        }
        break;
    case Camera::Down:
        a=qRadiansToDegrees(qAsin(-Camera::getDirectionLook().z()));

        if(a-speed_waggle<=-90)
            return;
        else
        {
            Camera::waggle(Camera::Up);
            Camera::setCameraPosition((getFixPosition()-Camera::getDirectionLook()*distance).toVector3D());
        }
        break;
    case Camera::Left:
        p=Camera::getCameraPosition()-getFixPosition();
        r.rotate(-speed_waggle,QVector3D(0.0f,0.0f,1.0f));
        t=r*p;
        Camera::setCameraPosition((t+getFixPosition()).toVector3D());
        Camera::setDirectionLook((getFixPosition()-position).toVector3D());
        Camera::setDirectionUp(QVector3D(0.0f,0.0f,1.0f));

        break;
    case Camera::Right:
        p=Camera::getCameraPosition()-getFixPosition();
        r.rotate(speed_waggle,QVector3D(0.0f,0.0f,1.0f));
        t=r*p;
        Camera::setCameraPosition((t+getFixPosition()).toVector3D());
        Camera::setDirectionLook((getFixPosition()-position).toVector3D());
        Camera::setDirectionUp(QVector3D(0.0f,0.0f,1.0f));

        break;
    case Camera::Front:
        if(distance-speed_move<=0)
            return;
        else
            Camera::move(Camera::Front);
        break;
    case Camera::Rear:
        Camera::move(Camera::Rear);
        break;
    default:
        qDebug()<<"the direction you move is not set";
        break;
    }
}

QVector4D LB::FixCamera::getFixPosition() const
{
    return fix_position;
}

猜你喜欢

转载自blog.csdn.net/qq_36691714/article/details/80301562