观察空间(View Space)

Direction

相机方向 = 相机位置 - 相机目标位置

Right

右轴 = 上向量 x 相机方向

Up

上轴 = 相机方向 x 右轴

LookAt

其中R是右向量,U是上向量,D是方向向量P是摄像机位置向量。

glm::mat4 view;
view = glm::lookAt(glm::vec3(0.0f, 0.0f, 3.0f), 
           glm::vec3(0.0f, 0.0f, 0.0f), 
           glm::vec3(0.0f, 1.0f, 0.0f));

相机移动

deltaTime

在每帧中计算deltaTime

float currentFrame = glfwGetTime();
deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame;

键盘输入改变位置

通过键盘的输入,来改变相机的位置

void processInput(GLFWwindow *window)
{
    float cameraSpeed = 2.5f * deltaTime;
    if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
        cameraPos += cameraSpeed * cameraFront;
    if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
        cameraPos -= cameraSpeed * cameraFront;
    if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
        cameraPos -= glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
    if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
        cameraPos += glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
}

视角移动

欧拉角

欧拉角(Euler Angle)是可以表示3D空间中任何旋转的3个值,一共有3种欧拉角:俯仰角(Pitch)、偏航角(Yaw)和滚转角(Roll)。

---

direction.x = cos(glm::radians(pitch)) * cos(glm::radians(yaw));
direction.y = sin(glm::radians(pitch));
direction.z = cos(glm::radians(pitch)) * sin(glm::radians(yaw));

鼠标回调函数

glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);

glfwSetCursorPosCallback(window, mouse_callback);
void mouse_callback(GLFWwindow* window, double xpos, double ypos);

  1. 计算鼠标距上一帧的偏移量。
  2. 把偏移量添加到摄像机的俯仰角和偏航角中。
  3. 对偏航角和俯仰角进行最大和最小值的限制。
  4. 计算方向向量。
void mouse_callback(GLFWwindow* window, double xpos, double ypos)
{
    float xoffset = xpos - lastX;
    float yoffset = lastY - ypos; 
    lastX = xpos;
    lastY = ypos;

    float sensitivity = 0.05; //灵敏度
    xoffset *= sensitivity;
    yoffset *= sensitivity;

    yaw   += xoffset;
    pitch += yoffset;

    //在90度时视角会发生逆转,所以我们把89度作为极限
    if(pitch > 89.0f)
        pitch = 89.0f;
    if(pitch < -89.0f)
        pitch = -89.0f;

    //计算
    glm::vec3 front;
    front.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch));
    front.y = sin(glm::radians(pitch));
    front.z = sin(glm::radians(yaw)) * cos(glm::radians(pitch));
    cameraFront = glm::normalize(front);
}

相机缩放

鼠标滚轮回调函数

glfwSetScrollCallback(window, scroll_callback);

void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{
  if(fov >= 1.0f && fov <= 45.0f)
    fov -= yoffset;
  if(fov <= 1.0f)
    fov = 1.0f;
  if(fov >= 45.0f)
    fov = 45.0f;
}
projection = glm::perspective(glm::radians(fov), WIDTH / HEIGHT, 0.1f, 100.0f);

摄像机类

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>

enum Camera_Movement {
	FORWARD,
	BACKWARD,
	LEFT,
	RIGHT
};

#pragma once
class Camera
{
public :
	Camera(glm::vec3 position, glm::vec3 worldup, float yaw, float pitch);
	~Camera();
	glm::mat4 GetViewMatrix();
	void ProcessMouseScroll(float yoffset);
	void ProcessMouseMovement(float xoffset, float yoffset, bool constrainPitch);
	void ProcessKeyboard(Camera_Movement direction, float deltaTime);

	glm::vec3 Position = glm::vec3(0.0f, 0.0f, 0.0f);
	glm::vec3 Up;
	glm::vec3 Right;
	glm::vec3 Front;
	glm::vec3 WorldUp;
	float Pitch;
	float Yaw;
	float Fov;
	float MovementSpeed;
	float MouseSensitivity;

private :
	void UpdateCameraVectors();
};
#include "Camera.h"

//偏航角
const float YAW			= -90.0f;
//俯仰角
const float PITCH		= 0.0f;
//视野(Field of View)
const float FOV			= 45.0f;
//移动速度
const float SPEED		= 5.0f;
//鼠标灵敏度
const float SENSITIVITY = 0.1f;

Camera::Camera(glm::vec3 position = glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3 worldup = glm::vec3(0.0f, 1.0f, 0.0f), float yaw = YAW, float pitch = PITCH) : Front(glm::vec3(0.0f, 0.0f, -1.0f)), MovementSpeed(SPEED), MouseSensitivity(SENSITIVITY), Fov(FOV)
{
	Position = position;
	Yaw = yaw;
	Pitch = pitch;
	WorldUp = worldup;
	UpdateCameraVectors();
}

Camera::~Camera()
{

}

glm::mat4 Camera::GetViewMatrix()
{
	return glm::lookAt(Position, Position + Front, Up);
}

void Camera::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;
}

void Camera::ProcessMouseScroll(float yoffset)
{
	Fov -= yoffset;
	if (Fov < 1.0f)
		Fov = 1.0f;
	if (Fov > 45.0f)
		Fov = 45.0f;
}

void Camera::ProcessMouseMovement(float xoffset, float yoffset, bool constrainPitch) 
{
	xoffset *= MouseSensitivity;
	yoffset *= MouseSensitivity;

	Yaw += xoffset;
	Pitch += yoffset;

	if (constrainPitch)
	{
		if (Pitch > 89.0f)
			Pitch = 89.0f;
		if (Pitch < -89.0f)
			Pitch = -89.0f;
	}
	UpdateCameraVectors();
}


void Camera::UpdateCameraVectors()
{
	glm::vec3 front = glm::vec3(0);
	front.x = glm::cos(glm::radians(Yaw)) * glm::cos(glm::radians(Pitch));
	front.y = glm::sin(glm::radians(Pitch));
	front.z = glm::sin(glm::radians(Yaw)) * glm::cos(glm::radians(Pitch));
	Front = glm::normalize(front);
	Right = glm::normalize(glm::cross(Front, WorldUp));
	Up = glm::normalize(glm::cross(Front, Right));
}

完整工程代码Github:

[github repo="acgloby/LearnOpenGL"]

最后更新于 2022-07-27