最近在搞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;
}