Repository navigation
Expand file tree
/
Copy pathCamera.hpp
More file actions
131 lines (114 loc) · 4.32 KB
/
Copy pathCamera.hpp
File metadata and controls
131 lines (114 loc) · 4.32 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#pragma once
#include "vkStart.h"
#include <GLFW/glfw3.h>
// camera 只负责观察和投影,不管理模型本身的变换。
// 自由相机:左键拖拽观察,WASD 按当前朝向移动, 滚轮调整fov
class camera {
public:
glm::vec3 position = glm::vec3(0.0f, 1.2f, 3.2f);
float yaw = glm::radians(-90.0f); // -90 度让初始 front 指向 -Z
float pitch = glm::radians(-18.0f);
float fovY = glm::radians(45.0f); // 垂直视野角(Field of View)
float nearPlane = 0.2f;
float farPlane = 50.0f;
float moveSpeed = 2.5f;
float rotateSensitivity = 0.004f;
float zoomSensitivity = glm::radians(2.5f);
void AttachToWindow(GLFWwindow* window) {
glfwSetWindowUserPointer(window, this);
glfwSetScrollCallback(window, ScrollCallback);
}
// 每帧更新,适合持续的操作
void UpdateFromInput(GLFWwindow* window, float deltaTime) {
UpdateMouseInput(window);
UpdateKeyboardInput(window, deltaTime);
UpdateZoomInput();
}
glm::mat4 View() const {
const glm::vec3 front = Front();
return glm::lookAt(position, position + front, WorldUp());
}
glm::mat4 Projection(VkExtent2D extent) const {
glm::mat4 proj = glm::perspective(
fovY,
float(extent.width) / float(extent.height),
nearPlane,
farPlane);
// GLM 默认按 OpenGL 习惯生成投影矩阵,Y 方向需要翻一下才符合 Vulkan 屏幕空间。
proj[1][1] *= -1.0f;
return proj;
}
private:
bool dragging = false;
double lastCursorX = 0.0;
double lastCursorY = 0.0;
float pendingScroll = 0.0f;
static glm::vec3 WorldUp() {
return glm::vec3(0.0f, 1.0f, 0.0f);
}
glm::vec3 Front() const {
return glm::normalize(glm::vec3(
std::cos(yaw) * std::cos(pitch),
std::sin(pitch),
std::sin(yaw) * std::cos(pitch)));
}
void UpdateMouseInput(GLFWwindow* window) {
const int leftButtonDown = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT);
double cursorX = 0.0;
double cursorY = 0.0;
glfwGetCursorPos(window, &cursorX, &cursorY);
if (leftButtonDown == GLFW_PRESS) {
// 第一次按下左键时只记录起点,避免视角瞬间跳变。
if (!dragging) {
dragging = true;
lastCursorX = cursorX;
lastCursorY = cursorY;
}
else {
const float deltaX = static_cast<float>(cursorX - lastCursorX);
const float deltaY = static_cast<float>(cursorY - lastCursorY);
yaw += deltaX * rotateSensitivity;
pitch -= deltaY * rotateSensitivity;
if (pitch < glm::radians(-80.0f))
pitch = glm::radians(-80.0f);
else if (pitch > glm::radians(80.0f))
pitch = glm::radians(80.0f);
lastCursorX = cursorX;
lastCursorY = cursorY;
}
}
else {
dragging = false;
}
}
void UpdateKeyboardInput(GLFWwindow* window, float deltaTime) {
const float moveStep = moveSpeed * deltaTime;
const glm::vec3 front = Front();
const glm::vec3 right = glm::normalize(glm::cross(front, WorldUp()));
// 完全自由相机:
// W/S 沿当前完整前向前进后退,A/D 沿当前完整右向左右平移。
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
position += front * moveStep;
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
position -= front * moveStep;
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
position -= right * moveStep;
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
position += right * moveStep;
}
void UpdateZoomInput() {
if (pendingScroll == 0.0f)
return;
// 滚轮在自由相机里改成调节 FOV:值越小,镜头越“长焦”。
fovY -= pendingScroll * zoomSensitivity;
if (fovY < glm::radians(20.0f))
fovY = glm::radians(20.0f);
else if (fovY > glm::radians(90.0f))
fovY = glm::radians(90.0f);
pendingScroll = 0.0f;
}
static void ScrollCallback(GLFWwindow* window, double, double yoffset) {
if (auto* pCamera = static_cast<camera*>(glfwGetWindowUserPointer(window)))
pCamera->pendingScroll += static_cast<float>(yoffset);
}
};