OpenGL中的观察坐标
OpenGL中的坐标变换过程如下所示:
计算机观察
观察三维世界空间的就是模拟了人通过照相机取景器看东西的过程,将物体置入观察空间,也就是让我们可以看到这个物体。
照相机的初始方向是指向 Z 轴的负方向,在大多数应用程序中,我们在原点的附近建模对象, 因此默认方位的照相机无法生成包含场景中全部对象的图像。 这样,要么把照相机移走,使之远离我们希望成像的对象;要么把对象移到照相机的前面。这两个操作是等价的,因为它们都可以 看做是在对象标架下指定照相机标架。
详细查阅 OpenGL 经典照相机模型
Camera的欧拉角
透视变换
主要是视角,比例,近面,远面
正交投影
Camera 对象
通过键鼠控制的摄像头形成自由观察
Camera.hpp,这代码来自 Learn Modern OpenGL的网站,代码拷贝过来,简单修改就能在Qt中使用。
#ifndef CAMERA_H
#define CAMERA_H
#include <QtMath>
#include <QMatrix4x4>
#include <QVector3D>
// 定义 Camera 移动的几个可能选项。用作抽象,以远离特定于窗口系统的输入方法
enum Camera_Movement {
FORWARD,
BACKWARD,
LEFT,
RIGHT
};
// 默认 Camera 值
const float YAW = -90.0f;
const float PITCH = 0.0f;
const float SPEED = 2.5f;
const float SENSITIVITY = 0.1f;
const float ZOOM = 45.0f;
// 一个抽象的相机类,用于处理输入并计算相应的欧拉角、向量和矩阵,供OpenGL使用
class Camera
{
public:
// Camera 属性
QVector3D Position;
QVector3D Front;
QVector3D Up;
QVector3D Right;
QVector3D WorldUp;
// euler Angles
float Yaw;
float Pitch;
// camera options
float MovementSpeed;
float MouseSensitivity;
float Zoom;
// 带向量的构造函数
Camera(QVector3D position = QVector3D(0.0f, 0.0f, 3.0f),
QVector3D up = QVector3D(0.0f, 1.0f, 0.0f),
float yaw = YAW, float pitch = PITCH)
: Front(QVector3D(0.0f, 0.0f, -1.0f))
, MovementSpeed(SPEED)
, MouseSensitivity(SENSITIVITY)
, Zoom(ZOOM)
{
Position = position;
WorldUp = up;
Yaw = yaw;
Pitch = pitch;
updateCameraVectors();
}
// 带标量的构造函数
Camera(float posX, float posY, float posZ,
float upX, float upY, float upZ, float yaw, float pitch)
: Front(QVector3D(0.0f, 0.0f, -1.0f))
, MovementSpeed(SPEED)
, MouseSensitivity(SENSITIVITY)
, Zoom(ZOOM)
{
Position = QVector3D(posX, posY, posZ);
WorldUp = QVector3D(upX, upY, upZ);
Yaw = yaw;
Pitch = pitch;
updateCameraVectors();
}
// 返回使用欧拉角和LookAt矩阵计算的视图矩阵
QMatrix4x4 GetViewMatrix()
{
QMatrix4x4 mat;
mat.lookAt(Position, Position + Front, Up);
return mat;
}
// 处理从任何类似键盘的输入系统接收的输入。接受相机定义ENUM形式的输入参数(从窗口系统中抽象出来)
void ProcessKeyboard(Camera_Movement direction, float deltaTime)
{
float velocity = MovementSpeed * deltaTime;
if (direction == FORWARD)
Position += Front * velocity;
if (direction == BACKWARD)
Position -= Front * velocity;
if (direction == LEFT)
Position -= Right * velocity;
if (direction == RIGHT)
Position += Right * velocity;
}
// 处理从鼠标输入系统接收的输入。期望x和y方向上的偏移值。
void ProcessMouseMovement(float xoffset, float yoffset, bool constrainPitch = true)
{
xoffset *= MouseSensitivity;
yoffset *= MouseSensitivity;
Yaw += xoffset;
Pitch += yoffset;
// 确保当 俯仰角 出界时,屏幕不会被翻转
if (constrainPitch)
{
if (Pitch > 89.0f)
Pitch = 89.0f;
if (Pitch < -89.0f)
Pitch = -89.0f;
}
// 用欧拉角更新 Front, Right and Up 向量
updateCameraVectors();
}
// 处理从鼠标滚轮事件接收的输入。只需要输入垂直轮轴
void ProcessMouseScroll(float yoffset)
{
Zoom -= (float)yoffset;
if (Zoom < 1.0f)
Zoom = 1.0f;
if (Zoom > 45.0f)
Zoom = 45.0f;
}
private:
// 从相机的欧拉角度计算前方矢量
void updateCameraVectors()
{
// 计算新的Front向量
QVector3D front;
front.setX ( cos( qDegreesToRadians(Yaw) ) * cos( qDegreesToRadians(Pitch) ) );
front.setY ( sin( qDegreesToRadians(Pitch)) );
front.setZ ( sin( qDegreesToRadians(Yaw) ) * cos( qDegreesToRadians(Pitch) ) );
Front = front.normalized ();
// 也重新计算右和向上向量
Right = QVector3D::crossProduct (WorldUp,Front).normalized ();
Up = QVector3D::crossProduct( Front, Right).normalized ();
}
};
#endif
当代码中使用了 camera 以后,投射到屏幕上的3轴显示除了熟悉的朝向,z 轴的正方向指向屏幕外,并且符合右手法。