-
Notifications
You must be signed in to change notification settings - Fork 0
/
camera.py
171 lines (133 loc) · 4.87 KB
/
camera.py
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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
import numpy as np
from OpenGL.GLUT import *
from utils import *
__all__ = ['Camera']
def glut_warp_pointer(x: int, y: int):
glutWarpPointer(x, y)
class Camera:
""" Keeps data about camera position and provides methods
to control camera with mouse and keyboard.
Configured camera position and orientation are used then
in rendering pipeline.
"""
step_size = 1
margin = 100
def __init__(self, pos, target, up, window_width, window_height,
warp_pointer=glut_warp_pointer):
self._pos = np.array(pos)
self._target = normalize(np.array(target))
self._up = normalize(np.array(up))
self._window_width = window_width
self._window_height = window_height
self._h_angle = 0.0
self._v_angle = 0.0
self._on_upper_edge = False
self._on_lower_edge = False
self._on_left_edge = False
self._on_right_edge = False
self._mouse_pos_x = window_width // 2
self._mouse_pos_y = window_height // 2
self._warp_pointer = warp_pointer
self.setup()
def setup(self):
# horizontal target
h_target = np.array([self._target[0], 0, self._target[2]])
h_target = normalize(h_target)
x, y, z = h_target
if z >= 0.0:
if x >= 0.0:
self._h_angle = 360.0 - to_degree(math.asin(z))
else:
self._h_angle = 180.0 + to_degree(math.asin(z))
else:
if x >= 0.0:
self._h_angle = to_degree(math.asin(-z))
else:
self._h_angle = 90.0 + to_degree(math.asin(-z))
self._v_angle = -to_degree(math.asin(y))
# glutWarpPointer(int(self._mouse_pos_x), int(self._mouse_pos_y))
self._warp_pointer(int(self._mouse_pos_x), int(self._mouse_pos_y))
@property
def pos(self):
return self._pos
@property
def target(self):
return self._target
@property
def up(self):
return self._up
def keyboard(self, key):
""" Moving camera position in horizontal plane relative to camera's target vector"""
if key == GLUT_KEY_UP:
self._pos += (self._target * self.step_size)
return True
elif key == GLUT_KEY_DOWN:
self._pos -= (self._target * self.step_size)
return True
elif key == GLUT_KEY_LEFT:
left = np.cross(self._target, self._up)
left = (left / np.linalg.norm(left)) * self.step_size
self._pos += left
return True
elif key == GLUT_KEY_RIGHT:
right = np.cross(self._up, self._target)
right = (right / np.linalg.norm(right)) * self.step_size
self._pos += right
return True
return False
def mouse(self, x, y):
""" Camera degree changing on mouse movement """
delta_x = x - self._mouse_pos_x
delta_y = y - self._mouse_pos_y
self._mouse_pos_x = x
self._mouse_pos_y = y
self._h_angle += delta_x / 20.0
self._v_angle += delta_y / 20.0
if delta_x == 0:
if x <= self.margin:
self._on_left_edge = True
elif x >= (self._window_width - self.margin):
self._on_right_edge = True
else:
self._on_left_edge = False
self._on_right_edge = False
if delta_y == 0:
if y <= self.margin:
self._on_upper_edge = True
elif y >= (self._window_height - self.margin):
self._on_lower_edge = True
else:
self._on_upper_edge = False
self._on_lower_edge = False
self.update()
def render(self):
update = False
edge_step = 0.5
if self._on_left_edge:
self._h_angle -= edge_step
update = True
elif self._on_right_edge:
self._h_angle += edge_step
update = True
if self._on_upper_edge and self._v_angle > -90.0:
self._v_angle -= edge_step
update = True
elif self._on_lower_edge and self._v_angle < 90.0:
self._v_angle += edge_step
update = True
if update:
self.update()
def update(self):
""" Applies changes of camera position and rotation """
# rotate the view vector by the horizontal angle around the vertical axis
v_axis = np.array([0.0, 1.0, 0.0])
view = np.array([1.0, 0.0, 0.0])
view = rotate(view, self._h_angle, v_axis)
view = normalize(view)
# rotate the view vector by the vertical angle around the horizontal axis
h_axis = np.cross(v_axis, view)
h_axis = normalize(h_axis)
view = rotate(view, self._v_angle, h_axis)
view = normalize(view)
self._target = view
self._up = normalize(np.cross(self._target, h_axis))