This repository has been archived by the owner on Jan 13, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
OrbitCamera.cpp
153 lines (127 loc) · 3.29 KB
/
OrbitCamera.cpp
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#include "OrbitCamera.h"
#include <sstream>
#include "ChiliWin.h"
OrbitCamera::OrbitCamera(int width, int height, float fovY_rad, float ratio_wh, float near_z, float far_z)
: width(width), height(height), fovY_rad(fovY_rad), ratio_wh(ratio_wh), near_z(near_z), far_z(far_z)
{
reset();
}
void OrbitCamera::set_target(const Vec3f& t)
{
target = t;
}
Mat4f OrbitCamera::get_view()
{
Vec3f cur = get_camera_position();
return Transform3::view(cur, target - cur, UP);
}
Mat4f OrbitCamera::get_persp()
{
return Transform3::persp(fovY_rad, ratio_wh, near_z, far_z);
}
void OrbitCamera::update(Mouse& m, Keyboard& k) {
static std::pair<int, int> origin{ -1, -1 };
static std::pair<int, int> def{ -1, -1 };
bool f = false;
// 左shift复位
if (k.KeyIsPressed(VK_SHIFT)) {
reset();
return; // 让此时后续调整无效
}
// 左键
if (m.LeftIsPressed()) {
f = true;
if (origin == def)
origin = m.GetPos();
std::pair<int, int> cur = m.GetPos();
update_phi_theta(
(float)(cur.first - origin.first) / height,
(float)(cur.second - origin.second) / height
);
// std::stringstream ss;
//ss << "origin: (" << origin.first << ", " << origin.second << "), "
// << "cur: (" << cur.first << ", " << cur.second << ")";
//OutputDebugString(ss.str().c_str());
origin = cur;
}
// 右键
if (m.RightIsPressed()) {
f = true;
if (origin == def)
origin = m.GetPos();
std::pair<int, int> cur = m.GetPos();
update_target(
(float)(cur.first - origin.first) / height,
(float)(cur.second - origin.second) / height
);
origin = cur;
}
if (!f) {
origin = def;
}
// 滚轮
update_zoom(m);
}
void OrbitCamera::update_phi_theta(float x, float y)
{
// xy是横纵向位移与窗口高度之比,(这里只取高度,避免因为宽高比影响不同方向的速度)
float d_theta = y * 2 * PI; // 转为弧度
float d_phi = x * 2 * PI;
phi -= d_phi * rotate_speed;
theta -= d_theta * rotate_speed;
//phi = Math::clamp(phi, MIN_PHI, MAX_PHI); // 不限制左右转
theta = Math::clamp(theta, MIN_THETA + EPSILON, MAX_THETA - EPSILON); // 上下转(俯仰)限制一下,避免更新“向上方向”
}
void OrbitCamera::update_target(float x, float y)
{
Vec3f cur = get_camera_position();
Vec3f forward = (target - cur).normalize();
Vec3f left = UP.cross(forward);
Vec3f up = forward.cross(left);
float factor = distance * (float)tan(fovY_rad / 2) * 2;
Vec3f dx = x * factor * left;
Vec3f dy = y * factor * up;
target += dx + dy;
}
void OrbitCamera::update_zoom(Mouse& m) {
int i = 0;
while (!m.IsEmpty()) {
const auto e = m.Read();
if (!e.has_value()) continue;
switch (e.value().GetType()) {
case Mouse::Event::Type::WheelUp:
i++;
break;
case Mouse::Event::Type::WheelDown:
i--;
break;
}
}
distance *= pow(0.95, i);
}
void OrbitCamera::reset(void)
{
static const float DEFAULT_PHI = 0;
static const float DEFAULT_THETA = PI / 2;
static const float DEFAULT_DISTANCE = 10.0f;
phi = DEFAULT_PHI;
theta = DEFAULT_THETA;
distance = DEFAULT_DISTANCE;
set_target();
}
Vec3f OrbitCamera::get_camera_position()
{
float x = distance * std::sin(theta) * std::cos(phi);
float y = distance * std::sin(theta) * std::sin(phi);
float z = distance * std::cos(theta);
// 注意坐标系的变化
return Vec3f(
target.x + y,
target.y + z,
target.z + x
);
}
Vec3f OrbitCamera::get_camera_dir()
{
return target - get_camera_position();
}