basilisk-engine 0.1.21__py3-none-any.whl → 0.1.23__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of basilisk-engine might be problematic. Click here for more details.

Files changed (93) hide show
  1. basilisk/__init__.py +15 -15
  2. basilisk/audio/sound.py +27 -27
  3. basilisk/bsk_assets/cube.obj +48 -48
  4. basilisk/collisions/broad/broad_aabb.py +102 -102
  5. basilisk/collisions/broad/broad_bvh.py +137 -137
  6. basilisk/collisions/collider.py +95 -95
  7. basilisk/collisions/collider_handler.py +224 -224
  8. basilisk/collisions/narrow/contact_manifold.py +95 -95
  9. basilisk/collisions/narrow/dataclasses.py +34 -34
  10. basilisk/collisions/narrow/deprecated.py +46 -46
  11. basilisk/collisions/narrow/epa.py +91 -91
  12. basilisk/collisions/narrow/gjk.py +66 -66
  13. basilisk/collisions/narrow/graham_scan.py +24 -24
  14. basilisk/collisions/narrow/helper.py +29 -29
  15. basilisk/collisions/narrow/line_intersections.py +106 -106
  16. basilisk/collisions/narrow/sutherland_hodgman.py +75 -75
  17. basilisk/config.py +4 -3
  18. basilisk/draw/draw.py +100 -100
  19. basilisk/draw/draw_handler.py +175 -179
  20. basilisk/draw/font_renderer.py +28 -28
  21. basilisk/engine.py +165 -213
  22. basilisk/generic/abstract_bvh.py +15 -15
  23. basilisk/generic/abstract_custom.py +133 -133
  24. basilisk/generic/collisions.py +72 -72
  25. basilisk/generic/input_validation.py +66 -66
  26. basilisk/generic/math.py +6 -6
  27. basilisk/generic/matrices.py +35 -35
  28. basilisk/generic/meshes.py +72 -72
  29. basilisk/generic/quat.py +142 -142
  30. basilisk/generic/quat_methods.py +7 -7
  31. basilisk/generic/raycast_result.py +26 -26
  32. basilisk/generic/vec3.py +143 -143
  33. basilisk/input/mouse.py +61 -61
  34. basilisk/input/path.py +14 -14
  35. basilisk/input_output/IO_handler.py +93 -0
  36. basilisk/input_output/__init__.py +0 -0
  37. basilisk/input_output/clock.py +50 -0
  38. basilisk/input_output/keys.py +44 -0
  39. basilisk/input_output/mouse.py +62 -0
  40. basilisk/input_output/path.py +14 -0
  41. basilisk/mesh/cube.py +33 -33
  42. basilisk/mesh/mesh.py +230 -230
  43. basilisk/mesh/mesh_from_data.py +130 -130
  44. basilisk/mesh/model.py +271 -271
  45. basilisk/mesh/narrow_aabb.py +89 -89
  46. basilisk/mesh/narrow_bvh.py +91 -91
  47. basilisk/mesh/narrow_primative.py +23 -23
  48. basilisk/nodes/helper.py +28 -28
  49. basilisk/nodes/node.py +686 -684
  50. basilisk/nodes/node_handler.py +97 -96
  51. basilisk/particles/particle_handler.py +64 -64
  52. basilisk/particles/particle_renderer.py +92 -92
  53. basilisk/physics/impulse.py +112 -112
  54. basilisk/physics/physics_body.py +43 -43
  55. basilisk/physics/physics_engine.py +35 -35
  56. basilisk/render/batch.py +105 -105
  57. basilisk/render/camera.py +267 -222
  58. basilisk/render/chunk.py +106 -106
  59. basilisk/render/chunk_handler.py +165 -165
  60. basilisk/render/frame.py +99 -101
  61. basilisk/render/framebuffer.py +131 -130
  62. basilisk/render/image.py +87 -87
  63. basilisk/render/image_handler.py +120 -122
  64. basilisk/render/light.py +96 -96
  65. basilisk/render/light_handler.py +58 -58
  66. basilisk/render/material.py +219 -219
  67. basilisk/render/material_handler.py +131 -135
  68. basilisk/render/post_process.py +139 -139
  69. basilisk/render/shader.py +109 -110
  70. basilisk/render/shader_handler.py +83 -80
  71. basilisk/render/sky.py +120 -120
  72. basilisk/scene.py +279 -276
  73. basilisk/shaders/batch.frag +276 -276
  74. basilisk/shaders/batch.vert +115 -115
  75. basilisk/shaders/crt.frag +31 -31
  76. basilisk/shaders/draw.frag +22 -22
  77. basilisk/shaders/draw.vert +25 -25
  78. basilisk/shaders/filter.frag +22 -22
  79. basilisk/shaders/frame.frag +12 -12
  80. basilisk/shaders/frame.vert +13 -13
  81. basilisk/shaders/geometry.frag +8 -8
  82. basilisk/shaders/geometry.vert +41 -41
  83. basilisk/shaders/normal.frag +59 -59
  84. basilisk/shaders/normal.vert +96 -96
  85. basilisk/shaders/particle.frag +71 -71
  86. basilisk/shaders/particle.vert +84 -84
  87. basilisk/shaders/sky.frag +9 -9
  88. basilisk/shaders/sky.vert +13 -13
  89. {basilisk_engine-0.1.21.dist-info → basilisk_engine-0.1.23.dist-info}/METADATA +45 -38
  90. basilisk_engine-0.1.23.dist-info/RECORD +109 -0
  91. {basilisk_engine-0.1.21.dist-info → basilisk_engine-0.1.23.dist-info}/WHEEL +1 -1
  92. basilisk_engine-0.1.21.dist-info/RECORD +0 -103
  93. {basilisk_engine-0.1.21.dist-info → basilisk_engine-0.1.23.dist-info}/top_level.txt +0 -0
basilisk/render/camera.py CHANGED
@@ -1,222 +1,267 @@
1
- import pygame as pg
2
- import glm
3
- import numpy as np
4
- from ..generic.vec3 import Vec3
5
- from ..generic.quat import Quat
6
-
7
-
8
- # Camera view constants
9
- FOV = 50 # Degrees
10
- NEAR = 0.1
11
- FAR = 350
12
-
13
- # Camera movement constants
14
- SPEED = 10
15
- SENSITIVITY = 0.15
16
-
17
- class Camera:
18
- engine: ...
19
- """Back reference to the parent engine"""
20
- scene: ...
21
- """Back reference to the parent scene"""
22
- aspect_ratio: float
23
- """Aspect ratio of the engine window"""
24
- position: glm.vec3
25
- """Location of the camera (maters)"""
26
-
27
- def __init__(self, position=(0, 0, 20), yaw=-90, pitch=0) -> None:
28
- """
29
- Camera object to get view and projection matricies. Movement built in
30
- """
31
-
32
- # Back references
33
- self.scene = None
34
- self.engine = None
35
- # fov
36
- self.fov = 50
37
- # The initial aspect ratio of the screen
38
- self.aspect_ratio = 1.0
39
- # Position
40
- self.position = glm.vec3(position)
41
- # k vector for vertical movement
42
- self.UP = glm.vec3(0, 1, 0)
43
- # Movement vectors
44
- self.up = glm.vec3(0, 1, 0)
45
- self.right = glm.vec3(1, 0, 0)
46
- self.forward = glm.vec3(0, 0, -1)
47
- # Look directions in degrees
48
- self.yaw = yaw
49
- self.pitch = pitch
50
- # View matrix
51
- self.m_view = self.get_view_matrix()
52
- # Projection matrix
53
- self.m_proj = self.get_projection_matrix()
54
-
55
- def update(self) -> None:
56
- """
57
- Updates the camera view matrix
58
- """
59
-
60
- self.update_camera_vectors()
61
- self.m_view = self.get_view_matrix()
62
-
63
- def update_camera_vectors(self) -> None:
64
- """
65
- Computes the forward vector based on the pitch and yaw. Computes horizontal and vertical vectors with cross product.
66
- """
67
- yaw, pitch = glm.radians(self.yaw), glm.radians(self.pitch)
68
-
69
- self.forward.x = glm.cos(yaw) * glm.cos(pitch)
70
- self.forward.y = glm.sin(pitch)
71
- self.forward.z = glm.sin(yaw) * glm.cos(pitch)
72
-
73
- self.forward = glm.normalize(self.forward)
74
- self.right = glm.normalize(glm.cross(self.forward, self.UP))
75
- self.up = glm.normalize(glm.cross(self.right, self.forward))
76
-
77
- def use(self):
78
- # Updated aspect ratio of the screen
79
- self.aspect_ratio = self.engine.win_size[0] / self.engine.win_size[1]
80
- # View matrix
81
- self.m_view = self.get_view_matrix()
82
- # Projection matrix
83
- self.m_proj = self.get_projection_matrix()
84
-
85
- def get_view_matrix(self) -> glm.mat4x4:
86
- return glm.lookAt(self.position, self.position + self.forward, self.up)
87
-
88
- def get_projection_matrix(self) -> glm.mat4x4:
89
- return glm.perspective(glm.radians(self.fov), self.aspect_ratio, NEAR, FAR)
90
-
91
- def get_params(self) -> tuple:
92
- return self.engine, self.position, self.yaw, self.pitch
93
-
94
- def look_at(self, other) -> None:
95
- forward = glm.normalize(other.position - self.position)
96
- self.yaw = np.degrees(np.arctan2(forward.z, forward.x))
97
- self.pitch = np.degrees(np.arctan2(forward.y, np.sqrt(forward.x ** 2 + forward.z ** 2)))
98
-
99
- def __repr__(self):
100
- return f'<Basilisk Camera | Position: {self.position}, Direction: {self.forward}>'
101
-
102
- @property
103
- def scene(self): return self._scene
104
- @property
105
- def position(self): return self._position
106
- @property
107
- def direction(self): return self.forward
108
- @property
109
- def horizontal(self): return glm.normalize(self.forward.xz)
110
- @property
111
- def rotation(self): return glm.conjugate(glm.quatLookAt(self.forward, self.UP))
112
- @property
113
- def fov(self): return self._fov
114
-
115
- @scene.setter
116
- def scene(self, value):
117
- if value == None: return
118
- self._scene = value
119
- self.engine = self._scene.engine
120
- self.use()
121
-
122
- @position.setter
123
- def position(self, value: tuple | list | glm.vec3 | np.ndarray | Vec3):
124
- if isinstance(value, glm.vec3): self._position = glm.vec3(value)
125
- elif isinstance(value, Vec3): self._position = glm.vec3(value.data)
126
- elif isinstance(value, tuple) or isinstance(value, list) or isinstance(value, np.ndarray):
127
- if len(value) != 3: raise ValueError(f'Camera: Invalid number of values for position. Expected 3, got {len(value)}')
128
- self._position = glm.vec3(value)
129
- else: raise TypeError(f'Camera: Invalid position value type {type(value)}')
130
-
131
- @direction.setter
132
- def direction(self, value: tuple | list | glm.vec3 | np.ndarray | Vec3):
133
- if isinstance(value, glm.vec3): self.forward = glm.normalize(glm.vec3(value))
134
- elif isinstance(value, Vec3): self.forward = glm.normalize(value.data)
135
- elif isinstance(value, tuple) or isinstance(value, list) or isinstance(value, np.ndarray):
136
- if len(value) != 3: raise ValueError(f'Camera: Invalid number of values for direction. Expected 3, got {len(value)}')
137
- self.forward = glm.normalize(glm.vec3(value))
138
- else: raise TypeError(f'Camera: Invalid direction value type {type(value)}')
139
-
140
- @fov.setter
141
- def fov(self, value):
142
- self._fov = value
143
- if self.engine: self.use()
144
-
145
-
146
- class FreeCamera(Camera):
147
- def __init__(self, position=(0, 0, 20), yaw=-90, pitch=0):
148
- super().__init__(position, yaw, pitch)
149
-
150
- def update(self) -> None:
151
- """
152
- Updates the camera position and rotaiton based on user input
153
- """
154
-
155
- self.move()
156
- self.rotate()
157
- self.update_camera_vectors()
158
- self.m_view = self.get_view_matrix()
159
-
160
- def rotate(self) -> None:
161
- """
162
- Rotates the camera based on the amount of mouse movement.
163
- """
164
- rel_x, rel_y = pg.mouse.get_rel()
165
- self.yaw += rel_x * SENSITIVITY
166
- self.pitch -= rel_y * SENSITIVITY
167
- self.yaw = self.yaw % 360
168
- self.pitch = max(-89, min(89, self.pitch))
169
-
170
- def move(self) -> None:
171
- """
172
- Checks for button presses and updates vectors accordingly.
173
- """
174
- velocity = (SPEED + self.engine.keys[pg.K_CAPSLOCK] * 10) * self.engine.delta_time
175
- keys = self.engine.keys
176
- if keys[pg.K_w]:
177
- self.position += glm.normalize(glm.vec3(self.forward.x, 0, self.forward.z)) * velocity
178
- if keys[pg.K_s]:
179
- self.position -= glm.normalize(glm.vec3(self.forward.x, 0, self.forward.z)) * velocity
180
- if keys[pg.K_a]:
181
- self.position -= self.right * velocity
182
- if keys[pg.K_d]:
183
- self.position += self.right * velocity
184
- if keys[pg.K_SPACE]:
185
- self.position += self.UP * velocity
186
- if keys[pg.K_LSHIFT]:
187
- self.position -= self.UP * velocity
188
-
189
-
190
- class FollowCamera(FreeCamera):
191
- def __init__(self, parent, position=(0, 0, 20), yaw=-90, pitch=0, offset=(0, 0, 0)):
192
- super().__init__(position, yaw, pitch)
193
- self.parent = parent
194
- self.offest = glm.vec3(offset)
195
-
196
- def move(self) -> None:
197
- """
198
- Moves the camera to the parent node
199
- """
200
-
201
- self.position = self.parent.position + self.offest
202
-
203
- class OrbitCamera(FreeCamera):
204
- def __init__(self, parent, position=(0, 0, 20), yaw=-90, pitch=0, distance=5, offset=(0, 0)):
205
- self.parent = parent
206
- self.distance = distance
207
- self.offset = glm.vec2(offset)
208
- super().__init__(position, yaw, pitch)
209
-
210
- def get_view_matrix(self) -> glm.mat4x4:
211
- return glm.lookAt(self.position, self.parent.position, self.up)
212
-
213
- def move(self) -> None:
214
- """
215
- Moves the camera to the parent node
216
- """
217
-
218
- self.position = self.parent.position - glm.normalize(self.forward) * self.distance
219
-
220
- class StaticCamera(Camera):
221
- def __init__(self, position=(0, 0, 20), yaw=-90, pitch=0):
222
- super().__init__(position, yaw, pitch)
1
+ import pygame as pg
2
+ import glm
3
+ import numpy as np
4
+ from ..generic.vec3 import Vec3
5
+ from ..generic.quat import Quat
6
+
7
+
8
+ # Camera view constants
9
+ FOV = 50 # Degrees
10
+ NEAR = 0.1
11
+ FAR = 350
12
+
13
+ # Camera movement constants
14
+ SPEED = 10
15
+ SENSITIVITY = 0.15/180
16
+
17
+ class Camera:
18
+ engine: ...
19
+ """Back reference to the parent engine"""
20
+ scene: ...
21
+ """Back reference to the parent scene"""
22
+ aspect_ratio: float
23
+ """Aspect ratio of the engine window"""
24
+ position: glm.vec3
25
+ """Location of the camera (maters)"""
26
+
27
+ def __init__(self, position=(0, 0, 20), rotation=(1, 0, 0, 0), yaw=-90, pitch=0) -> None:
28
+ """
29
+ Camera object to get view and projection matricies. Movement built in
30
+ """
31
+
32
+ # Back references
33
+ self.scene = None
34
+ self.engine = None
35
+ # transformations
36
+ self.rotation = glm.quat(rotation)
37
+ self.position = glm.vec3(position)
38
+ # fov
39
+ self.fov = 50
40
+ # The initial aspect ratio of the screen
41
+ self.aspect_ratio = 1.0
42
+ # View matrix
43
+ self.m_view = self.get_view_matrix()
44
+ # Projection matrix
45
+ self.m_proj = self.get_projection_matrix()
46
+
47
+ def update(self) -> None:
48
+ """
49
+ Updates the camera view matrix
50
+ """
51
+
52
+ # self.update_camera_vectors()
53
+ self.m_view = self.get_view_matrix()
54
+
55
+ # def update_camera_vectors(self) -> None:
56
+ # """
57
+ # Computes the forward vector based on the pitch and yaw. Computes horizontal and vertical vectors with cross product.
58
+ # """
59
+ # yaw, pitch = glm.radians(self.yaw), glm.radians(self.pitch)
60
+
61
+ # self.forward.x = glm.cos(yaw) * glm.cos(pitch)
62
+ # self.forward.y = glm.sin(pitch)
63
+ # self.forward.z = glm.sin(yaw) * glm.cos(pitch)
64
+
65
+ # self.forward = glm.normalize(self.forward)
66
+ # self.right = glm.normalize(glm.cross(self.forward, self.UP))
67
+ # self.up = glm.normalize(glm.cross(self.right, self.forward))
68
+
69
+ def use(self):
70
+ # Updated aspect ratio of the screen
71
+ self.aspect_ratio = self.engine.win_size[0] / self.engine.win_size[1]
72
+ # View matrix
73
+ self.m_view = self.get_view_matrix()
74
+ # Projection matrix
75
+ self.m_proj = self.get_projection_matrix()
76
+
77
+ def get_view_matrix(self) -> glm.mat4x4:
78
+ return glm.lookAt(self.position, self.position + self.forward, self.up)
79
+
80
+ def get_projection_matrix(self) -> glm.mat4x4:
81
+ return glm.perspective(glm.radians(self.fov), self.aspect_ratio, NEAR, FAR)
82
+
83
+ def get_params(self) -> tuple:
84
+ return self.engine, self.position, self.yaw, self.pitch
85
+
86
+ def look_at(self, other) -> None:
87
+ forward = glm.normalize(other.position - self.position)
88
+ self.yaw = np.degrees(np.arctan2(forward.z, forward.x))
89
+ self.pitch = np.degrees(np.arctan2(forward.y, np.sqrt(forward.x ** 2 + forward.z ** 2)))
90
+
91
+ def __repr__(self):
92
+ return f'<Basilisk Camera | Position: {self.position}, Direction: {self.forward}>'
93
+
94
+ @property
95
+ def scene(self): return self._scene
96
+ @property
97
+ def position(self): return self._position
98
+ @property
99
+ def rotation(self) -> glm.quat: return self._rotation
100
+ @property
101
+ def direction(self): return self.rotation * (0, 0, -1)
102
+ @property
103
+ def forward(self): return self.rotation * (0, 0, -1)
104
+ @property
105
+ def pitch(self): return glm.pitch(self.rotation)
106
+ @property
107
+ def yaw(self): return glm.yaw(self.rotation)
108
+ @property
109
+ def roll(self): return glm.roll(self.rotation)
110
+ @property
111
+ def UP(self):
112
+ up = (self.rotation.x, self.rotation.y, self.rotation.z)
113
+ up = (0, 1, 0) # TODO ensure that this works with all up vectors
114
+ return glm.normalize(up) if glm.length2(up) > 1e-7 else glm.vec3(0, 1, 0)
115
+ @property
116
+ def right(self): return glm.normalize(glm.cross(self.forward, self.UP))
117
+ @property
118
+ def up(self): return glm.normalize(glm.cross(self.right, self.forward))
119
+ @property
120
+ def horizontal(self): return glm.normalize(glm.cross(self.UP, self.right))
121
+ @property
122
+ def fov(self): return self._fov
123
+
124
+ @scene.setter
125
+ def scene(self, value):
126
+ if value == None: return
127
+ self._scene = value
128
+ self.engine = self._scene.engine
129
+ self.use()
130
+
131
+ @position.setter
132
+ def position(self, value: tuple | list | glm.vec3 | np.ndarray | Vec3):
133
+ if isinstance(value, glm.vec3): self._position = glm.vec3(value)
134
+ elif isinstance(value, Vec3): self._position = glm.vec3(value.data)
135
+ elif isinstance(value, tuple) or isinstance(value, list) or isinstance(value, np.ndarray):
136
+ if len(value) != 3: raise ValueError(f'Camera: Invalid number of values for position. Expected 3, got {len(value)}')
137
+ self._position = glm.vec3(value)
138
+ else: raise TypeError(f'Camera: Invalid position value type {type(value)}')
139
+
140
+ @rotation.setter
141
+ def rotation(self, value):
142
+ if isinstance(value, (glm.vec3, glm.quat)): self._rotation = glm.quat(value)
143
+ elif isinstance(value, (Vec3, Quat)): self._rotation = glm.quat(value.data)
144
+ elif isinstance(value, tuple) or isinstance(value, list) or isinstance(value, np.ndarray):
145
+ if not (2 < len(value) < 5): raise ValueError(f'Camera: Invalid number of values for rotation. Expected 3 or 4, got {len(value)}')
146
+ self._position = glm.quat(value)
147
+ else:
148
+ try:
149
+ self._rotation = glm.quat(value)
150
+ except:
151
+ raise TypeError(f'Camera: Invalid rotation value type {type(value)}')
152
+
153
+ @direction.setter
154
+ def direction(self, value: tuple | list | glm.vec3 | np.ndarray | Vec3):
155
+ if isinstance(value, glm.vec3): self.forward = glm.normalize(value)
156
+ elif isinstance(value, Vec3): self.forward = glm.normalize(value.data)
157
+ elif isinstance(value, tuple) or isinstance(value, list) or isinstance(value, np.ndarray):
158
+ if len(value) != 3: raise ValueError(f'Camera: Invalid number of values for direction. Expected 3, got {len(value)}')
159
+ self.forward = glm.normalize(value)
160
+ else: raise TypeError(f'Camera: Invalid direction value type {type(value)}')
161
+
162
+ @forward.setter
163
+ def forward(self, value):
164
+ self._rotation = glm.quatLookAt(value, self.UP)
165
+
166
+ @pitch.setter
167
+ def pitch(self, value):
168
+ self._rotation = glm.quat((value, self.yaw, self.roll))
169
+
170
+ @yaw.setter
171
+ def yaw(self, value):
172
+ self._rotation = glm.quat((self.pitch, value, self.roll))
173
+
174
+ @roll.setter
175
+ def roll(self, value):
176
+ self._rotation = glm.quat((self.pitch, self.yaw, value))
177
+
178
+ @UP.setter
179
+ def UP(self, value):
180
+ self._rotation = glm.quatLookAt(self.forward, value)
181
+
182
+ @fov.setter
183
+ def fov(self, value):
184
+ self._fov = value
185
+ if self.engine: self.use()
186
+
187
+
188
+ class FreeCamera(Camera):
189
+ def __init__(self, position=(0, 0, 20), rotation=(1, 0, 0, 0), yaw=-90, pitch=0):
190
+ super().__init__(position, rotation, yaw, pitch)
191
+
192
+ def update(self) -> None:
193
+ """
194
+ Updates the camera position and rotaiton based on user input
195
+ """
196
+
197
+ self.move()
198
+ self.rotate()
199
+ # self.update_camera_vectors()
200
+ self.m_view = self.get_view_matrix()
201
+
202
+ def rotate(self) -> None:
203
+ """
204
+ Rotates the camera based on the amount of mouse movement.
205
+ """
206
+ rel_x, rel_y = pg.mouse.get_rel()
207
+
208
+ yaw_rotation = glm.angleAxis(SENSITIVITY * rel_x, -self.UP)
209
+ pitch_rotation = glm.angleAxis(SENSITIVITY * rel_y, -self.right)
210
+ new_rotation = yaw_rotation * pitch_rotation * self.rotation
211
+
212
+ v_new = new_rotation * self.UP
213
+ pitch_angle = glm.degrees(glm.acos(glm.clamp(glm.dot(v_new, self.UP), -1.0, 1.0)))
214
+ self.rotation = new_rotation if pitch_angle < 89 else yaw_rotation * self.rotation
215
+
216
+ def move(self) -> None:
217
+ """
218
+ Checks for button presses and updates vectors accordingly.
219
+ """
220
+ velocity = (SPEED + self.engine.keys[pg.K_CAPSLOCK] * 10) * self.engine.delta_time
221
+ keys = self.engine.keys
222
+ if keys[pg.K_w]:
223
+ self.position += glm.normalize(glm.vec3(self.forward.x, 0, self.forward.z)) * velocity
224
+ if keys[pg.K_s]:
225
+ self.position -= glm.normalize(glm.vec3(self.forward.x, 0, self.forward.z)) * velocity
226
+ if keys[pg.K_a]:
227
+ self.position -= self.right * velocity
228
+ if keys[pg.K_d]:
229
+ self.position += self.right * velocity
230
+ if keys[pg.K_SPACE]:
231
+ self.position += self.UP * velocity
232
+ if keys[pg.K_LSHIFT]:
233
+ self.position -= self.UP * velocity
234
+
235
+
236
+ class FollowCamera(FreeCamera):
237
+ def __init__(self, parent, position=(0, 0, 20), rotation=(1, 0, 0, 0), yaw=-90, pitch=0, offset=(0, 0, 0)):
238
+ super().__init__(position, rotation, yaw, pitch)
239
+ self.parent = parent
240
+ self.offest = glm.vec3(offset)
241
+
242
+ def move(self) -> None:
243
+ """
244
+ Moves the camera to the parent node
245
+ """
246
+
247
+ self.position = self.parent.position + self.offest
248
+
249
+ class OrbitCamera(FreeCamera):
250
+ def __init__(self, parent, position=(0, 0, 20), rotation=(1, 0, 0, 0), yaw=-90, pitch=0, distance=5, offset=(0, 0)):
251
+ self.parent = parent
252
+ self.distance = distance
253
+ self.offset = glm.vec2(offset)
254
+ super().__init__(position, rotation, yaw, pitch)
255
+
256
+ def get_view_matrix(self) -> glm.mat4x4:
257
+ return glm.lookAt(self.position, self.parent.position, self.up)
258
+
259
+ def move(self) -> None:
260
+ """
261
+ Moves the camera to the parent node
262
+ """
263
+ self.position = self.parent.position - glm.normalize(self.forward) * self.distance
264
+
265
+ class StaticCamera(Camera):
266
+ def __init__(self, position=(0, 0, 20), rotation=(1, 0, 0, 0), yaw=-90, pitch=0):
267
+ super().__init__(position, rotation, yaw, pitch)