basilisk-engine 0.1.34__py3-none-any.whl → 0.1.36__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.
- basilisk/__init__.py +26 -26
- basilisk/audio/sound.py +27 -27
- basilisk/bsk_assets/cube.obj +48 -48
- basilisk/collisions/broad/broad_aabb.py +102 -102
- basilisk/collisions/broad/broad_bvh.py +137 -137
- basilisk/collisions/collider.py +95 -95
- basilisk/collisions/collider_handler.py +225 -224
- basilisk/collisions/narrow/contact_manifold.py +95 -95
- basilisk/collisions/narrow/dataclasses.py +34 -34
- basilisk/collisions/narrow/deprecated.py +46 -46
- basilisk/collisions/narrow/epa.py +91 -91
- basilisk/collisions/narrow/gjk.py +66 -66
- basilisk/collisions/narrow/graham_scan.py +24 -24
- basilisk/collisions/narrow/helper.py +29 -29
- basilisk/collisions/narrow/line_intersections.py +106 -106
- basilisk/collisions/narrow/sutherland_hodgman.py +75 -75
- basilisk/config.py +54 -4
- basilisk/draw/draw.py +100 -100
- basilisk/draw/draw_handler.py +175 -175
- basilisk/draw/font_renderer.py +28 -28
- basilisk/engine.py +165 -165
- basilisk/generic/abstract_bvh.py +15 -15
- basilisk/generic/abstract_custom.py +133 -133
- basilisk/generic/collisions.py +70 -70
- basilisk/generic/input_validation.py +82 -74
- basilisk/generic/math.py +6 -6
- basilisk/generic/matrices.py +35 -35
- basilisk/generic/meshes.py +72 -72
- basilisk/generic/quat.py +142 -142
- basilisk/generic/quat_methods.py +7 -7
- basilisk/generic/raycast_result.py +26 -26
- basilisk/generic/vec3.py +143 -143
- basilisk/input_output/IO_handler.py +91 -91
- basilisk/input_output/clock.py +49 -49
- basilisk/input_output/keys.py +43 -43
- basilisk/input_output/mouse.py +90 -89
- basilisk/input_output/path.py +14 -14
- basilisk/mesh/cube.py +33 -33
- basilisk/mesh/mesh.py +233 -233
- basilisk/mesh/mesh_from_data.py +150 -150
- basilisk/mesh/model.py +271 -271
- basilisk/mesh/narrow_aabb.py +89 -89
- basilisk/mesh/narrow_bvh.py +91 -91
- basilisk/mesh/narrow_primative.py +23 -23
- basilisk/nodes/helper.py +28 -28
- basilisk/nodes/node.py +704 -695
- basilisk/nodes/node_handler.py +97 -97
- basilisk/particles/particle_handler.py +64 -64
- basilisk/particles/particle_renderer.py +92 -92
- basilisk/physics/impulse.py +112 -112
- basilisk/physics/physics_body.py +43 -43
- basilisk/physics/physics_engine.py +35 -35
- basilisk/render/batch.py +103 -103
- basilisk/render/bloom.py +108 -0
- basilisk/render/camera.py +260 -260
- basilisk/render/chunk.py +108 -106
- basilisk/render/chunk_handler.py +167 -165
- basilisk/render/frame.py +107 -95
- basilisk/render/framebuffer.py +203 -192
- basilisk/render/image.py +120 -120
- basilisk/render/image_handler.py +120 -120
- basilisk/render/light.py +96 -96
- basilisk/render/light_handler.py +58 -58
- basilisk/render/material.py +232 -221
- basilisk/render/material_handler.py +133 -133
- basilisk/render/post_process.py +139 -139
- basilisk/render/shader.py +134 -134
- basilisk/render/shader_handler.py +85 -83
- basilisk/render/sky.py +120 -120
- basilisk/scene.py +289 -289
- basilisk/shaders/batch.frag +289 -276
- basilisk/shaders/batch.vert +117 -115
- basilisk/shaders/bloom_downsample.frag +43 -0
- basilisk/shaders/bloom_frame.frag +25 -0
- basilisk/shaders/bloom_upsample.frag +34 -0
- basilisk/shaders/crt.frag +31 -31
- basilisk/shaders/draw.frag +25 -22
- basilisk/shaders/draw.vert +25 -25
- basilisk/shaders/filter.frag +22 -22
- basilisk/shaders/frame.frag +12 -12
- basilisk/shaders/frame.vert +13 -13
- basilisk/shaders/geometry.frag +8 -8
- basilisk/shaders/geometry.vert +41 -41
- basilisk/shaders/normal.frag +59 -59
- basilisk/shaders/normal.vert +96 -96
- basilisk/shaders/particle.frag +71 -71
- basilisk/shaders/particle.vert +84 -84
- basilisk/shaders/sky.frag +23 -9
- basilisk/shaders/sky.vert +13 -13
- basilisk_engine-0.1.36.dist-info/METADATA +89 -0
- basilisk_engine-0.1.36.dist-info/RECORD +110 -0
- {basilisk_engine-0.1.34.dist-info → basilisk_engine-0.1.36.dist-info}/WHEEL +1 -1
- basilisk/input/__init__.py +0 -0
- basilisk/input/mouse.py +0 -62
- basilisk/input/path.py +0 -14
- basilisk_engine-0.1.34.dist-info/METADATA +0 -45
- basilisk_engine-0.1.34.dist-info/RECORD +0 -109
- {basilisk_engine-0.1.34.dist-info → basilisk_engine-0.1.36.dist-info}/top_level.txt +0 -0
basilisk/nodes/node.py
CHANGED
|
@@ -1,696 +1,705 @@
|
|
|
1
|
-
import glm
|
|
2
|
-
import numpy as np
|
|
3
|
-
from .helper import node_is
|
|
4
|
-
from ..generic.vec3 import Vec3
|
|
5
|
-
from ..generic.quat import Quat
|
|
6
|
-
from ..generic.matrices import get_model_matrix
|
|
7
|
-
from ..mesh.mesh import Mesh
|
|
8
|
-
from ..render.material import Material
|
|
9
|
-
from ..physics.physics_body import PhysicsBody
|
|
10
|
-
from ..collisions.collider import Collider
|
|
11
|
-
from ..render.chunk import Chunk
|
|
12
|
-
from ..render.shader import Shader
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class Node():
|
|
16
|
-
position: Vec3
|
|
17
|
-
"""The position of the node in meters with swizzle xyz"""
|
|
18
|
-
scale: Vec3
|
|
19
|
-
"""The scale of the node in meters in each direction"""
|
|
20
|
-
rotation: Quat
|
|
21
|
-
"""The rotation of the node"""
|
|
22
|
-
relative_position: bool
|
|
23
|
-
"""The position of this node relative to the parent node"""
|
|
24
|
-
relative_scale: bool
|
|
25
|
-
"""The scale of this node relative to the parent node"""
|
|
26
|
-
relative_rotation: bool
|
|
27
|
-
"""The rotation of this node relative to the parent node"""
|
|
28
|
-
forward: glm.vec3
|
|
29
|
-
"""The forward facing vector of the node"""
|
|
30
|
-
mesh: Mesh
|
|
31
|
-
"""The mesh of the node stored as a basilisk mesh object"""
|
|
32
|
-
material: Material
|
|
33
|
-
"""The mesh of the node stored as a basilisk material object"""
|
|
34
|
-
velocity: glm.vec3
|
|
35
|
-
"""The translational velocity of the node"""
|
|
36
|
-
rotational_velocity: glm.vec3
|
|
37
|
-
"""The rotational velocity of the node"""
|
|
38
|
-
physics: bool
|
|
39
|
-
"""Allows the node's movement to be affected by the physics engine and collisions"""
|
|
40
|
-
mass: float
|
|
41
|
-
"""The mass of the node in kg"""
|
|
42
|
-
collision: bool
|
|
43
|
-
"""Gives the node collision with other nodes in the scene"""
|
|
44
|
-
collider_mesh: str
|
|
45
|
-
"""The collider type of the node. Can be either 'box' or 'mesh'"""
|
|
46
|
-
static_friction: float
|
|
47
|
-
"""Determines the friction of the node when still: recommended value 0.0 - 1.0"""
|
|
48
|
-
kinetic_friction: float
|
|
49
|
-
"""Determines the friction of the node when moving: recommended value 0.0 - 1.0"""
|
|
50
|
-
elasticity: float
|
|
51
|
-
"""Determines how bouncy an object is: recommended value 0.0 - 1.0"""
|
|
52
|
-
collision_group: str
|
|
53
|
-
"""Nodes of the same collision group do not collide with each other"""
|
|
54
|
-
name: str
|
|
55
|
-
"""The name of the node for reference"""
|
|
56
|
-
tags: list[str]
|
|
57
|
-
"""Tags are used to sort nodes into separate groups"""
|
|
58
|
-
static: bool
|
|
59
|
-
"""Objects that don't move should be marked as static"""
|
|
60
|
-
chunk: Chunk
|
|
61
|
-
"""The parent chunk of the node. Used for callbacks to update chunk meshes"""
|
|
62
|
-
children: list
|
|
63
|
-
"""List of nodes that this node is a parent of"""
|
|
64
|
-
shader: Shader
|
|
65
|
-
"""Shader that is used to render the node. If none is given, engine default will be used"""
|
|
66
|
-
|
|
67
|
-
def __init__(self,
|
|
68
|
-
position: glm.vec3=None,
|
|
69
|
-
scale: glm.vec3=None,
|
|
70
|
-
rotation: glm.quat=None,
|
|
71
|
-
relative_position: bool=True,
|
|
72
|
-
relative_scale: bool=True,
|
|
73
|
-
relative_rotation: bool=True,
|
|
74
|
-
forward: glm.vec3=None,
|
|
75
|
-
mesh: Mesh=None,
|
|
76
|
-
material: Material=None,
|
|
77
|
-
velocity: glm.vec3=None,
|
|
78
|
-
rotational_velocity: glm.vec3=None,
|
|
79
|
-
physics: bool=False,
|
|
80
|
-
mass: float=None,
|
|
81
|
-
collision: bool=False,
|
|
82
|
-
collider_mesh: str|Mesh=None,
|
|
83
|
-
static_friction: float=None,
|
|
84
|
-
kinetic_friction: float=None,
|
|
85
|
-
elasticity: float=None,
|
|
86
|
-
collision_group: float=None,
|
|
87
|
-
name: str='',
|
|
88
|
-
tags: list[str]=None,
|
|
89
|
-
static: bool=None,
|
|
90
|
-
shader: Shader=None
|
|
91
|
-
) -> None:
|
|
92
|
-
"""
|
|
93
|
-
Basilisk node object.
|
|
94
|
-
Contains mesh data, translation, material, physics, collider, and descriptive information.
|
|
95
|
-
Base building block for populating a Basilisk scene.
|
|
96
|
-
"""
|
|
97
|
-
|
|
98
|
-
# parents
|
|
99
|
-
self.node_handler = None
|
|
100
|
-
self.scene = None
|
|
101
|
-
self.engine = None
|
|
102
|
-
self.chunk = None
|
|
103
|
-
self.parent = None
|
|
104
|
-
|
|
105
|
-
# lazy update variables
|
|
106
|
-
self.needs_geometric_center = True # pos
|
|
107
|
-
self.needs_model_matrix = True # pos, scale, rot
|
|
108
|
-
|
|
109
|
-
# node data
|
|
110
|
-
self.internal_position: Vec3 = Vec3(position) if position else Vec3(0, 0, 0)
|
|
111
|
-
self.internal_scale : Vec3 = Vec3(scale) if scale else Vec3(1, 1, 1)
|
|
112
|
-
self.internal_rotation: Quat = Quat(rotation) if rotation else Quat(1, 0, 0, 0)
|
|
113
|
-
|
|
114
|
-
# relative transformations
|
|
115
|
-
self.relative_position = glm.vec3(0, 0, 0) if relative_position else None
|
|
116
|
-
self.relative_scale = glm.vec3(0, 0, 0) if relative_scale else None
|
|
117
|
-
self.relative_rotation = glm.quat(1, 0, 0, 0) if relative_rotation else None
|
|
118
|
-
|
|
119
|
-
self.forward = forward if forward else glm.vec3(1, 0, 0)
|
|
120
|
-
self.mesh = mesh
|
|
121
|
-
self._mtl_list = material if isinstance(material, list) else [material]
|
|
122
|
-
self.material = material if material else None
|
|
123
|
-
self.velocity = velocity if velocity else glm.vec3(0, 0, 0)
|
|
124
|
-
self.rotational_velocity = rotational_velocity if rotational_velocity else glm.vec3(0, 0, 0)
|
|
125
|
-
|
|
126
|
-
self._static = static
|
|
127
|
-
|
|
128
|
-
# Physics updates
|
|
129
|
-
if physics: self.physics_body = PhysicsBody(mass = mass if mass else 1.0)
|
|
130
|
-
elif mass: raise ValueError('Node: cannot have mass if it does not have physics')
|
|
131
|
-
else: self.physics_body = None
|
|
132
|
-
|
|
133
|
-
# collider
|
|
134
|
-
if collision:
|
|
135
|
-
self.collider = Collider(
|
|
136
|
-
node = self,
|
|
137
|
-
collider_mesh = collider_mesh,
|
|
138
|
-
static_friction = static_friction,
|
|
139
|
-
kinetic_friction = kinetic_friction,
|
|
140
|
-
elasticity = elasticity,
|
|
141
|
-
collision_group = collision_group
|
|
142
|
-
)
|
|
143
|
-
elif collider_mesh: raise ValueError('Node: cannot have collider mesh if it does not allow collisions')
|
|
144
|
-
elif static_friction: raise ValueError('Node: cannot have static friction if it does not allow collisions')
|
|
145
|
-
elif kinetic_friction: raise ValueError('Node: cannot have kinetic friction if it does not allow collisions')
|
|
146
|
-
elif elasticity: raise ValueError('Node: cannot have elasticity if it does not allow collisions')
|
|
147
|
-
elif collision_group: raise ValueError('Node: cannot have collider group if it does not allow collisions')
|
|
148
|
-
else: self.collider = None
|
|
149
|
-
|
|
150
|
-
# information and recursion
|
|
151
|
-
self.name = name
|
|
152
|
-
self.tags = tags if tags else []
|
|
153
|
-
|
|
154
|
-
self.data_index = 0
|
|
155
|
-
self.children = []
|
|
156
|
-
|
|
157
|
-
# Shader given by user or none for default
|
|
158
|
-
self.shader = shader
|
|
159
|
-
|
|
160
|
-
# callback function to be added to the custom Vec3 and Quat classes
|
|
161
|
-
def position_callback():
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
self.
|
|
178
|
-
|
|
179
|
-
self.collider.
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
self.collider.
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
self.
|
|
204
|
-
self.
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
if
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
if
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
child.
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
def
|
|
318
|
-
"""
|
|
319
|
-
|
|
320
|
-
"""
|
|
321
|
-
self.
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
if
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
if isinstance(self.material,
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
@property
|
|
464
|
-
def
|
|
465
|
-
@property
|
|
466
|
-
def
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
@property
|
|
492
|
-
def
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
@
|
|
504
|
-
def
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
self.
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
self.
|
|
564
|
-
if not self.
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
@
|
|
595
|
-
def
|
|
596
|
-
if isinstance(value, glm.vec3): self.
|
|
597
|
-
elif isinstance(value, Vec3): self.
|
|
598
|
-
elif isinstance(value, tuple) or isinstance(value, list) or isinstance(value, np.ndarray):
|
|
599
|
-
if len(value) != 3: raise ValueError(f'Node: Invalid number of values for
|
|
600
|
-
self.
|
|
601
|
-
else: raise TypeError(f'Node: Invalid
|
|
602
|
-
|
|
603
|
-
@
|
|
604
|
-
def
|
|
605
|
-
if
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
else: raise TypeError(f'Node: Invalid
|
|
654
|
-
|
|
655
|
-
@
|
|
656
|
-
def
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
self.
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
if self.
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
1
|
+
import glm
|
|
2
|
+
import numpy as np
|
|
3
|
+
from .helper import node_is
|
|
4
|
+
from ..generic.vec3 import Vec3
|
|
5
|
+
from ..generic.quat import Quat
|
|
6
|
+
from ..generic.matrices import get_model_matrix
|
|
7
|
+
from ..mesh.mesh import Mesh
|
|
8
|
+
from ..render.material import Material
|
|
9
|
+
from ..physics.physics_body import PhysicsBody
|
|
10
|
+
from ..collisions.collider import Collider
|
|
11
|
+
from ..render.chunk import Chunk
|
|
12
|
+
from ..render.shader import Shader
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Node():
|
|
16
|
+
position: Vec3
|
|
17
|
+
"""The position of the node in meters with swizzle xyz"""
|
|
18
|
+
scale: Vec3
|
|
19
|
+
"""The scale of the node in meters in each direction"""
|
|
20
|
+
rotation: Quat
|
|
21
|
+
"""The rotation of the node"""
|
|
22
|
+
relative_position: bool
|
|
23
|
+
"""The position of this node relative to the parent node"""
|
|
24
|
+
relative_scale: bool
|
|
25
|
+
"""The scale of this node relative to the parent node"""
|
|
26
|
+
relative_rotation: bool
|
|
27
|
+
"""The rotation of this node relative to the parent node"""
|
|
28
|
+
forward: glm.vec3
|
|
29
|
+
"""The forward facing vector of the node"""
|
|
30
|
+
mesh: Mesh
|
|
31
|
+
"""The mesh of the node stored as a basilisk mesh object"""
|
|
32
|
+
material: Material
|
|
33
|
+
"""The mesh of the node stored as a basilisk material object"""
|
|
34
|
+
velocity: glm.vec3
|
|
35
|
+
"""The translational velocity of the node"""
|
|
36
|
+
rotational_velocity: glm.vec3
|
|
37
|
+
"""The rotational velocity of the node"""
|
|
38
|
+
physics: bool
|
|
39
|
+
"""Allows the node's movement to be affected by the physics engine and collisions"""
|
|
40
|
+
mass: float
|
|
41
|
+
"""The mass of the node in kg"""
|
|
42
|
+
collision: bool
|
|
43
|
+
"""Gives the node collision with other nodes in the scene"""
|
|
44
|
+
collider_mesh: str
|
|
45
|
+
"""The collider type of the node. Can be either 'box' or 'mesh'"""
|
|
46
|
+
static_friction: float
|
|
47
|
+
"""Determines the friction of the node when still: recommended value 0.0 - 1.0"""
|
|
48
|
+
kinetic_friction: float
|
|
49
|
+
"""Determines the friction of the node when moving: recommended value 0.0 - 1.0"""
|
|
50
|
+
elasticity: float
|
|
51
|
+
"""Determines how bouncy an object is: recommended value 0.0 - 1.0"""
|
|
52
|
+
collision_group: str
|
|
53
|
+
"""Nodes of the same collision group do not collide with each other"""
|
|
54
|
+
name: str
|
|
55
|
+
"""The name of the node for reference"""
|
|
56
|
+
tags: list[str]
|
|
57
|
+
"""Tags are used to sort nodes into separate groups"""
|
|
58
|
+
static: bool
|
|
59
|
+
"""Objects that don't move should be marked as static"""
|
|
60
|
+
chunk: Chunk
|
|
61
|
+
"""The parent chunk of the node. Used for callbacks to update chunk meshes"""
|
|
62
|
+
children: list
|
|
63
|
+
"""List of nodes that this node is a parent of"""
|
|
64
|
+
shader: Shader
|
|
65
|
+
"""Shader that is used to render the node. If none is given, engine default will be used"""
|
|
66
|
+
|
|
67
|
+
def __init__(self,
|
|
68
|
+
position: glm.vec3=None,
|
|
69
|
+
scale: glm.vec3=None,
|
|
70
|
+
rotation: glm.quat=None,
|
|
71
|
+
relative_position: bool=True,
|
|
72
|
+
relative_scale: bool=True,
|
|
73
|
+
relative_rotation: bool=True,
|
|
74
|
+
forward: glm.vec3=None,
|
|
75
|
+
mesh: Mesh=None,
|
|
76
|
+
material: Material=None,
|
|
77
|
+
velocity: glm.vec3=None,
|
|
78
|
+
rotational_velocity: glm.vec3=None,
|
|
79
|
+
physics: bool=False,
|
|
80
|
+
mass: float=None,
|
|
81
|
+
collision: bool=False,
|
|
82
|
+
collider_mesh: str|Mesh=None,
|
|
83
|
+
static_friction: float=None,
|
|
84
|
+
kinetic_friction: float=None,
|
|
85
|
+
elasticity: float=None,
|
|
86
|
+
collision_group: float=None,
|
|
87
|
+
name: str='',
|
|
88
|
+
tags: list[str]=None,
|
|
89
|
+
static: bool=None,
|
|
90
|
+
shader: Shader=None
|
|
91
|
+
) -> None:
|
|
92
|
+
"""
|
|
93
|
+
Basilisk node object.
|
|
94
|
+
Contains mesh data, translation, material, physics, collider, and descriptive information.
|
|
95
|
+
Base building block for populating a Basilisk scene.
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
# parents
|
|
99
|
+
self.node_handler = None
|
|
100
|
+
self.scene = None
|
|
101
|
+
self.engine = None
|
|
102
|
+
self.chunk = None
|
|
103
|
+
self.parent = None
|
|
104
|
+
|
|
105
|
+
# lazy update variables
|
|
106
|
+
self.needs_geometric_center = True # pos
|
|
107
|
+
self.needs_model_matrix = True # pos, scale, rot
|
|
108
|
+
|
|
109
|
+
# node data
|
|
110
|
+
self.internal_position: Vec3 = Vec3(position) if position else Vec3(0, 0, 0)
|
|
111
|
+
self.internal_scale : Vec3 = Vec3(scale) if scale else Vec3(1, 1, 1)
|
|
112
|
+
self.internal_rotation: Quat = Quat(rotation) if rotation else Quat(1, 0, 0, 0)
|
|
113
|
+
|
|
114
|
+
# relative transformations
|
|
115
|
+
self.relative_position = glm.vec3(0, 0, 0) if relative_position else None
|
|
116
|
+
self.relative_scale = glm.vec3(0, 0, 0) if relative_scale else None
|
|
117
|
+
self.relative_rotation = glm.quat(1, 0, 0, 0) if relative_rotation else None
|
|
118
|
+
|
|
119
|
+
self.forward = forward if forward else glm.vec3(1, 0, 0)
|
|
120
|
+
self.mesh = mesh
|
|
121
|
+
self._mtl_list = material if isinstance(material, list) else [material]
|
|
122
|
+
self.material = material if material else None
|
|
123
|
+
self.velocity = velocity if velocity else glm.vec3(0, 0, 0)
|
|
124
|
+
self.rotational_velocity = rotational_velocity if rotational_velocity else glm.vec3(0, 0, 0)
|
|
125
|
+
|
|
126
|
+
self._static = static
|
|
127
|
+
|
|
128
|
+
# Physics updates
|
|
129
|
+
if physics: self.physics_body = PhysicsBody(mass = mass if mass else 1.0)
|
|
130
|
+
elif mass: raise ValueError('Node: cannot have mass if it does not have physics')
|
|
131
|
+
else: self.physics_body = None
|
|
132
|
+
|
|
133
|
+
# collider
|
|
134
|
+
if collision:
|
|
135
|
+
self.collider = Collider(
|
|
136
|
+
node = self,
|
|
137
|
+
collider_mesh = collider_mesh,
|
|
138
|
+
static_friction = static_friction,
|
|
139
|
+
kinetic_friction = kinetic_friction,
|
|
140
|
+
elasticity = elasticity,
|
|
141
|
+
collision_group = collision_group
|
|
142
|
+
)
|
|
143
|
+
elif collider_mesh: raise ValueError('Node: cannot have collider mesh if it does not allow collisions')
|
|
144
|
+
elif static_friction: raise ValueError('Node: cannot have static friction if it does not allow collisions')
|
|
145
|
+
elif kinetic_friction: raise ValueError('Node: cannot have kinetic friction if it does not allow collisions')
|
|
146
|
+
elif elasticity: raise ValueError('Node: cannot have elasticity if it does not allow collisions')
|
|
147
|
+
elif collision_group: raise ValueError('Node: cannot have collider group if it does not allow collisions')
|
|
148
|
+
else: self.collider = None
|
|
149
|
+
|
|
150
|
+
# information and recursion
|
|
151
|
+
self.name = name
|
|
152
|
+
self.tags = tags if tags else []
|
|
153
|
+
|
|
154
|
+
self.data_index = 0
|
|
155
|
+
self.children = []
|
|
156
|
+
|
|
157
|
+
# Shader given by user or none for default
|
|
158
|
+
self.shader = shader
|
|
159
|
+
|
|
160
|
+
# callback function to be added to the custom Vec3 and Quat classes
|
|
161
|
+
def position_callback():
|
|
162
|
+
|
|
163
|
+
if self.chunk:
|
|
164
|
+
|
|
165
|
+
chunk_size = self.scene.engine.config.chunk_size
|
|
166
|
+
chunk_pos = self.position // chunk_size
|
|
167
|
+
|
|
168
|
+
if self.chunk.position[0] == chunk_pos.x and self.chunk.position[1] == chunk_pos.y and self.chunk.position[2] == chunk_pos.z:
|
|
169
|
+
self.chunk.node_update_callback(self)
|
|
170
|
+
else:
|
|
171
|
+
self.chunk.remove(self)
|
|
172
|
+
self.chunk.chunk_handler.add(self)
|
|
173
|
+
|
|
174
|
+
# update variables
|
|
175
|
+
self.needs_geometric_center = True
|
|
176
|
+
self.needs_model_matrix = True
|
|
177
|
+
if self.collider:
|
|
178
|
+
self.collider.needs_bvh = True
|
|
179
|
+
self.collider.needs_obb = True
|
|
180
|
+
|
|
181
|
+
def scale_callback():
|
|
182
|
+
if self.chunk:
|
|
183
|
+
self.chunk.node_update_callback(self)
|
|
184
|
+
|
|
185
|
+
# update variables
|
|
186
|
+
self.needs_model_matrix = True
|
|
187
|
+
if self.collider:
|
|
188
|
+
self.collider.needs_bvh = True
|
|
189
|
+
self.collider.needs_obb = True
|
|
190
|
+
self.collider.needs_half_dimensions = True
|
|
191
|
+
|
|
192
|
+
def rotation_callback():
|
|
193
|
+
if self.chunk:
|
|
194
|
+
self.chunk.node_update_callback(self)
|
|
195
|
+
|
|
196
|
+
# update variables
|
|
197
|
+
self.needs_model_matrix = True
|
|
198
|
+
if self.collider:
|
|
199
|
+
self.collider.needs_bvh = True
|
|
200
|
+
self.collider.needs_obb = True
|
|
201
|
+
self.collider.needs_half_dimensions = True
|
|
202
|
+
|
|
203
|
+
self.internal_position.callback = position_callback
|
|
204
|
+
self.internal_scale.callback = scale_callback
|
|
205
|
+
self.internal_rotation.callback = rotation_callback
|
|
206
|
+
|
|
207
|
+
def init_scene(self, scene: ...) -> None:
|
|
208
|
+
"""
|
|
209
|
+
Updates the scene of the node
|
|
210
|
+
"""
|
|
211
|
+
self.scene = scene
|
|
212
|
+
self.engine = scene.engine
|
|
213
|
+
self.node_handler = scene.node_handler
|
|
214
|
+
|
|
215
|
+
# Update materials
|
|
216
|
+
self.write_materials()
|
|
217
|
+
|
|
218
|
+
# Update the mesh
|
|
219
|
+
self.mesh = self.mesh if self.mesh else self.engine.cube
|
|
220
|
+
|
|
221
|
+
# Update physics and collider
|
|
222
|
+
if self.physics_body: self.physics_body.physics_engine = scene.physics_engine
|
|
223
|
+
if self.collider: self.collider.collider_handler = scene.collider_handler
|
|
224
|
+
|
|
225
|
+
def update(self, dt: float) -> None:
|
|
226
|
+
"""
|
|
227
|
+
Updates the node's movement variables based on the delta time
|
|
228
|
+
"""
|
|
229
|
+
# update based on physical properties
|
|
230
|
+
if any(self.velocity): self.position += dt * self.velocity
|
|
231
|
+
if any(self.rotational_velocity): self.rotation = glm.normalize(self.rotation.data - dt / 2 * self.rotation.data * glm.quat(0, *self.rotational_velocity))
|
|
232
|
+
|
|
233
|
+
if self.physics_body:
|
|
234
|
+
self.velocity += self.physics_body.get_delta_velocity(dt)
|
|
235
|
+
self.rotational_velocity += self.physics_body.get_delta_rotational_velocity(dt)
|
|
236
|
+
|
|
237
|
+
# update children transforms
|
|
238
|
+
for child in self.children: child.sync_data()
|
|
239
|
+
|
|
240
|
+
def sync_data(self) -> None:
|
|
241
|
+
"""
|
|
242
|
+
Syncronizes this node with the parent node based on its relative positioning
|
|
243
|
+
"""
|
|
244
|
+
# calculate transform matrix with the given input
|
|
245
|
+
transform = glm.mat4x4()
|
|
246
|
+
if self.relative_position: transform = glm.translate(transform, self.parent.position.data)
|
|
247
|
+
if self.relative_rotation: transform *= glm.transpose(glm.mat4_cast(self.parent.rotation.data))
|
|
248
|
+
if self.relative_scale: transform = glm.scale(transform, self.parent.scale.data)
|
|
249
|
+
|
|
250
|
+
# set this node's transforms based on the parent
|
|
251
|
+
if self.relative_position: self.position = transform * self.relative_position
|
|
252
|
+
if self.relative_scale: self.scale = self.relative_scale * self.parent.scale.data
|
|
253
|
+
if self.relative_rotation: self.rotation = self.relative_rotation * self.parent.rotation.data
|
|
254
|
+
|
|
255
|
+
for child in self.children: child.sync_data()
|
|
256
|
+
|
|
257
|
+
def deep_copy(self) -> ...:
|
|
258
|
+
"""
|
|
259
|
+
Creates a deep copy of this node and returns it. The new node is not added to the scene.
|
|
260
|
+
"""
|
|
261
|
+
|
|
262
|
+
copy = Node(
|
|
263
|
+
position = self.position,
|
|
264
|
+
scale = self.scale,
|
|
265
|
+
rotation = self.rotation,
|
|
266
|
+
relative_position = bool(self.relative_position),
|
|
267
|
+
relative_scale = bool(self.relative_scale),
|
|
268
|
+
relative_rotation = bool(self.relative_rotation),
|
|
269
|
+
forward = glm.vec3(self.forward),
|
|
270
|
+
mesh = self.mesh,
|
|
271
|
+
material = self.material,
|
|
272
|
+
velocity = glm.vec3(self.velocity),
|
|
273
|
+
rotational_velocity = glm.vec3(self.rotational_velocity),
|
|
274
|
+
physics = bool(self.physics_body),
|
|
275
|
+
mass = self.mass if self.physics_body else None,
|
|
276
|
+
collision = bool(self.collider),
|
|
277
|
+
static_friction = self.static_friction if self.collider else None,
|
|
278
|
+
kinetic_friction = self.kinetic_friction if self.collider else None,
|
|
279
|
+
elasticity = self.elasticity if self.collider else None,
|
|
280
|
+
collision_group = self.collision_group if self.collider else None,
|
|
281
|
+
name = self.name,
|
|
282
|
+
tags = [tag for tag in self.tags], # deep copy tags list
|
|
283
|
+
static = self.static,
|
|
284
|
+
shader = self.shader
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
return copy
|
|
288
|
+
|
|
289
|
+
def get_all(self, position: glm.vec3=None, scale: glm.vec3=None, rotation: glm.quat=None, forward: glm.vec3=None, mesh: Mesh=None, material: Material=None, velocity: glm.vec3=None, rotational_velocity: glm.quat=None, physics: bool=None, mass: float=None, collisions: bool=None, static_friction: float=None, kinetic_friction: float=None, elasticity: float=None, collision_group: float=None, name: str=None, tags: list[str]=None,static: bool=None) -> list:
|
|
290
|
+
nodes = [self] if node_is(self, position, scale, rotation, forward, mesh, material, velocity, rotational_velocity, physics, mass, collisions, static_friction, kinetic_friction, elasticity, collision_group, name, tags, static) else []
|
|
291
|
+
for node in self.children: nodes += node.get_all(position, scale, rotation, forward, mesh, material, velocity, rotational_velocity, physics, mass, collisions, static_friction, kinetic_friction, elasticity, collision_group, name, tags, static)
|
|
292
|
+
return nodes
|
|
293
|
+
|
|
294
|
+
# tree functions for managing children
|
|
295
|
+
def add(self, child: ..., relative_position: bool=None, relative_scale: bool=None, relative_rotation: glm.vec3=None) -> None:
|
|
296
|
+
"""
|
|
297
|
+
Adopts a node as a child. Relative transforms can be changed, if left bank they will not be chnaged from the current child nodes settings.
|
|
298
|
+
"""
|
|
299
|
+
if child in self.children or child is self: return
|
|
300
|
+
assert isinstance(child, Node), 'Nodes can only accept other Nodes as children.'
|
|
301
|
+
|
|
302
|
+
relative = glm.inverse(self.model_matrix) * child.model_matrix
|
|
303
|
+
position = glm.vec3(relative[3])
|
|
304
|
+
scale = glm.vec3([glm.length(relative[i]) for i in range(3)])
|
|
305
|
+
rotation = child.rotation * glm.inverse(self.rotation.data)
|
|
306
|
+
|
|
307
|
+
# compute relative transformations
|
|
308
|
+
if relative_position or (relative_position is None and child.relative_position): child.relative_position = position
|
|
309
|
+
if relative_scale or (relative_scale is None and child.relative_scale): child.relative_scale = scale
|
|
310
|
+
if relative_rotation or (relative_rotation is None and child.relative_rotation): child.relative_rotation = rotation
|
|
311
|
+
|
|
312
|
+
# add as a child to by synchronized and controlled
|
|
313
|
+
if self.node_handler: self.node_handler.add(child)
|
|
314
|
+
child.parent = self
|
|
315
|
+
self.children.append(child)
|
|
316
|
+
|
|
317
|
+
def remove(self, child: ...) -> None:
|
|
318
|
+
"""
|
|
319
|
+
Removes a child node from this nodes chlid list.
|
|
320
|
+
"""
|
|
321
|
+
if child in self.children:
|
|
322
|
+
if self.node_handler: self.node_handler.remove(child)
|
|
323
|
+
child.parent = None
|
|
324
|
+
self.children.remove(child)
|
|
325
|
+
|
|
326
|
+
def apply_force(self, force: glm.vec3, dt: float) -> None:
|
|
327
|
+
"""
|
|
328
|
+
Applies a force at the center of the node
|
|
329
|
+
"""
|
|
330
|
+
self.apply_offset_force(force, glm.vec3(0.0), dt)
|
|
331
|
+
|
|
332
|
+
def apply_offset_force(self, force: glm.vec3, offset: glm.vec3, dt: float) -> None:
|
|
333
|
+
"""
|
|
334
|
+
Applies a force at the given offset
|
|
335
|
+
"""
|
|
336
|
+
# translation
|
|
337
|
+
assert self.physics_body, 'Node: Cannot apply a force to a node that doesn\'t have a physics body'
|
|
338
|
+
self.velocity += force / self.mass * dt
|
|
339
|
+
|
|
340
|
+
# rotation
|
|
341
|
+
torque = glm.cross(offset, force)
|
|
342
|
+
self.apply_torque(torque, dt)
|
|
343
|
+
|
|
344
|
+
def apply_torque(self, torque: glm.vec3, dt: float) -> None:
|
|
345
|
+
"""
|
|
346
|
+
Applies a torque on the node
|
|
347
|
+
"""
|
|
348
|
+
assert self.physics_body, 'Node: Cannot apply a torque to a node that doesn\'t have a physics body'
|
|
349
|
+
...
|
|
350
|
+
|
|
351
|
+
# TODO change geometric variables into properties
|
|
352
|
+
def get_inverse_inertia(self) -> glm.mat3x3:
|
|
353
|
+
"""
|
|
354
|
+
Transforms the mesh inertia tensor and inverts it
|
|
355
|
+
"""
|
|
356
|
+
if not ((self.mesh or (self.collider and self.collider.mesh)) and self.physics_body): return None
|
|
357
|
+
mesh = self.collider.mesh if self.collider else self.mesh
|
|
358
|
+
inertia_tensor = mesh.get_inertia_tensor(self.scale) / 2
|
|
359
|
+
|
|
360
|
+
# mass
|
|
361
|
+
if self.physics_body: inertia_tensor *= self.physics_body.mass
|
|
362
|
+
|
|
363
|
+
# rotation
|
|
364
|
+
rotation_matrix = glm.mat3_cast(self.rotation.data)
|
|
365
|
+
inertia_tensor = rotation_matrix * inertia_tensor * glm.transpose(rotation_matrix)
|
|
366
|
+
|
|
367
|
+
return glm.inverse(inertia_tensor)
|
|
368
|
+
|
|
369
|
+
def get_vertex(self, index) -> glm.vec3:
|
|
370
|
+
"""
|
|
371
|
+
Gets the world space position of a vertex indicated by the index in the mesh
|
|
372
|
+
"""
|
|
373
|
+
return glm.vec3(self.model_matrix * glm.vec4(*self.mesh.points[index], 1))
|
|
374
|
+
|
|
375
|
+
def get_data(self) -> np.ndarray:
|
|
376
|
+
"""
|
|
377
|
+
Gets the node batch data for chunk batching
|
|
378
|
+
"""
|
|
379
|
+
|
|
380
|
+
# Get data from the mesh node
|
|
381
|
+
mesh_data = self.mesh.data
|
|
382
|
+
node_data = np.array([*self.position, *self.rotation, *self.scale, 0])
|
|
383
|
+
|
|
384
|
+
per_vertex_mtl = isinstance(self.material, list)
|
|
385
|
+
|
|
386
|
+
if not per_vertex_mtl: node_data[-1] = self.material.index
|
|
387
|
+
|
|
388
|
+
# Create an array to hold the node's data
|
|
389
|
+
width = 25 if not self.mesh.custom else 11 + mesh_data.shape[1]
|
|
390
|
+
data = np.zeros(shape=(mesh_data.shape[0], width), dtype='f4')
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
data[:,:mesh_data.shape[1]] = mesh_data
|
|
394
|
+
data[:,mesh_data.shape[1]:] = node_data
|
|
395
|
+
|
|
396
|
+
if per_vertex_mtl: data[:,-1] = self.material
|
|
397
|
+
|
|
398
|
+
if self.shader and not self.mesh.custom: data = np.take(data, self.shader.attribute_indices, axis=1)
|
|
399
|
+
|
|
400
|
+
return data
|
|
401
|
+
|
|
402
|
+
def write_materials(self):
|
|
403
|
+
"""
|
|
404
|
+
Internal function to write the material list to the material handler and get the material ids
|
|
405
|
+
"""
|
|
406
|
+
|
|
407
|
+
if isinstance(self.material, list):
|
|
408
|
+
mtl_index_list = []
|
|
409
|
+
for mtl in self._mtl_list:
|
|
410
|
+
self.engine.material_handler.add(mtl)
|
|
411
|
+
mtl_index_list.append(mtl.index)
|
|
412
|
+
mtl_index_list.append(mtl.index)
|
|
413
|
+
mtl_index_list.append(mtl.index)
|
|
414
|
+
self._material = mtl_index_list
|
|
415
|
+
|
|
416
|
+
if isinstance(self.material, type(None)):
|
|
417
|
+
self.material = self.engine.material_handler.base
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
def __repr__(self) -> str:
|
|
421
|
+
"""
|
|
422
|
+
Returns a string representation of the node
|
|
423
|
+
"""
|
|
424
|
+
|
|
425
|
+
return f'<Bailisk Node | {self.name}, {self.mesh}, ({self.position})>'
|
|
426
|
+
|
|
427
|
+
@property
|
|
428
|
+
def position(self): return self.internal_position
|
|
429
|
+
@property
|
|
430
|
+
def scale(self): return self.internal_scale
|
|
431
|
+
@property
|
|
432
|
+
def rotation(self): return self.internal_rotation
|
|
433
|
+
@property
|
|
434
|
+
def forward(self): return self._forward
|
|
435
|
+
@property
|
|
436
|
+
def mesh(self): return self._mesh
|
|
437
|
+
@property
|
|
438
|
+
def material(self): return self._material
|
|
439
|
+
@property
|
|
440
|
+
def velocity(self): return self._velocity
|
|
441
|
+
@property
|
|
442
|
+
def rotational_velocity(self): return self._rotational_velocity
|
|
443
|
+
@property
|
|
444
|
+
def mass(self):
|
|
445
|
+
if self.physics_body: return self.physics_body.mass
|
|
446
|
+
raise RuntimeError('Node: Cannot access the mass of a node that has no physics body')
|
|
447
|
+
@property
|
|
448
|
+
def static_friction(self):
|
|
449
|
+
if self.collider: return self.collider.static_friction
|
|
450
|
+
raise RuntimeError('Node: Cannot access the static friction of a node that has no collider')
|
|
451
|
+
@property
|
|
452
|
+
def kinetic_friction(self):
|
|
453
|
+
if self.collider: return self.collider.kinetic_friction
|
|
454
|
+
raise RuntimeError('Node: Cannot access the kinetic friction of a node that has no collider')
|
|
455
|
+
@property
|
|
456
|
+
def elasticity(self):
|
|
457
|
+
if self.collider: return self.collider.elasticity
|
|
458
|
+
raise RuntimeError('Node: Cannot access the elasticity of a node that has no collider')
|
|
459
|
+
@property
|
|
460
|
+
def collision_group(self):
|
|
461
|
+
if self.collider: return self.collider.collision_group
|
|
462
|
+
raise RuntimeError('Node: Cannot access the collision_group of a node that has no collider')
|
|
463
|
+
@property
|
|
464
|
+
def name(self): return self._name
|
|
465
|
+
@property
|
|
466
|
+
def tags(self): return self._tags
|
|
467
|
+
@property
|
|
468
|
+
def static(self):
|
|
469
|
+
return self._static if self._static is not None else not(self.physics or any(self.velocity) or any(self.rotational_velocity) or (self.parent and not self.parent.static))
|
|
470
|
+
@property
|
|
471
|
+
def x(self): return self.internal_position.data.x
|
|
472
|
+
@property
|
|
473
|
+
def y(self): return self.internal_position.data.y
|
|
474
|
+
@property
|
|
475
|
+
def z(self): return self.internal_position.data.z
|
|
476
|
+
|
|
477
|
+
# TODO add descriptions in the class header
|
|
478
|
+
@property
|
|
479
|
+
def model_matrix(self):
|
|
480
|
+
if self.needs_model_matrix:
|
|
481
|
+
self._model_matrix = get_model_matrix(self.position, self.scale, self.rotation)
|
|
482
|
+
self.needs_model_matrix = False
|
|
483
|
+
return self._model_matrix
|
|
484
|
+
@property
|
|
485
|
+
def geometric_center(self): # assumes the node has a mesh
|
|
486
|
+
# if not self.mesh: raise RuntimeError('Node: Cannot retrieve geometric center if node does not have mesh')
|
|
487
|
+
if self.needs_geometric_center:
|
|
488
|
+
self._geometric_center = self.model_matrix * self.mesh.geometric_center
|
|
489
|
+
self.needs_geometric_center = False
|
|
490
|
+
return self._geometric_center
|
|
491
|
+
@property
|
|
492
|
+
def center_of_mass(self):
|
|
493
|
+
if not self.mesh: raise RuntimeError('Node: Cannot retrieve center of mass if node does not have mesh')
|
|
494
|
+
return self.model_matrix * self.mesh.center_of_mass
|
|
495
|
+
@property
|
|
496
|
+
def volume(self):
|
|
497
|
+
if not self.mesh: raise RuntimeError('Node: Cannot retrieve volume if node does not have mesh')
|
|
498
|
+
return self.mesh.volume * self.scale.x * self.scale.y * self.scale.z
|
|
499
|
+
|
|
500
|
+
@property
|
|
501
|
+
def physics(self):
|
|
502
|
+
return bool(self.physics_body)
|
|
503
|
+
@property
|
|
504
|
+
def collision(self):
|
|
505
|
+
return bool(self.collider)
|
|
506
|
+
|
|
507
|
+
@property
|
|
508
|
+
def collisions(self):
|
|
509
|
+
assert self.collision, 'Node: Cannot access collision data without collisions enabled on Node'
|
|
510
|
+
return self.collider.collisions
|
|
511
|
+
|
|
512
|
+
@position.setter
|
|
513
|
+
def position(self, value: tuple | list | glm.vec3 | np.ndarray):
|
|
514
|
+
if isinstance(value, glm.vec3): self.internal_position.data = value
|
|
515
|
+
elif isinstance(value, Vec3): self.internal_position.data = value.data
|
|
516
|
+
elif isinstance(value, tuple) or isinstance(value, list) or isinstance(value, np.ndarray):
|
|
517
|
+
if len(value) != 3: raise ValueError(f'Node: Invalid number of values for position. Expected 3, got {len(value)}')
|
|
518
|
+
self.internal_position.data = glm.vec3(value)
|
|
519
|
+
else: raise TypeError(f'Node: Invalid position value type {type(value)}')
|
|
520
|
+
|
|
521
|
+
# # compute relative position if all cases passed
|
|
522
|
+
# if self.parent and self.relative_position: self.relative_position = self.internal_position.data - self.parent.position
|
|
523
|
+
|
|
524
|
+
@scale.setter
|
|
525
|
+
def scale(self, value: tuple | list | glm.vec3 | np.ndarray):
|
|
526
|
+
if isinstance(value, glm.vec3): self.internal_scale.data = value
|
|
527
|
+
elif isinstance(value, Vec3): self.internal_scale.data = value.data
|
|
528
|
+
elif isinstance(value, tuple) or isinstance(value, list) or isinstance(value, np.ndarray):
|
|
529
|
+
if len(value) != 3: raise ValueError(f'Node: Invalid number of values for scale. Expected 3, got {len(value)}')
|
|
530
|
+
self.internal_scale.data = glm.vec3(value)
|
|
531
|
+
else: raise TypeError(f'Node: Invalid scale value type {type(value)}')
|
|
532
|
+
|
|
533
|
+
# # compute relative scale
|
|
534
|
+
# if self.parent and self.relative_scale: self.relative_scale = self.internal_scale.data / self.parent.scale
|
|
535
|
+
|
|
536
|
+
@rotation.setter
|
|
537
|
+
def rotation(self, value: tuple | list | glm.vec3 | glm.quat | glm.vec4 | np.ndarray):
|
|
538
|
+
if isinstance(value, glm.quat) or isinstance(value, glm.vec4) or isinstance(value, glm.vec3): self.internal_rotation.data = glm.quat(value)
|
|
539
|
+
elif isinstance(value, Quat): self.internal_rotation.data = value.data
|
|
540
|
+
elif isinstance(value, tuple) or isinstance(value, list) or isinstance(value, np.ndarray):
|
|
541
|
+
if len(value) == 3: self.internal_rotation.data = glm.quat(glm.vec3(*value))
|
|
542
|
+
elif len(value) == 4: self.internal_rotation.data = glm.quat(*value)
|
|
543
|
+
else: raise ValueError(f'Node: Invalid number of values for rotation. Expected 3 or 4, got {len(value)}')
|
|
544
|
+
else: raise TypeError(f'Node: Invalid rotation value type {type(value)}')
|
|
545
|
+
|
|
546
|
+
# # compute relative rotation
|
|
547
|
+
# if self.parent and self.relative_rotation: self.relative_rotation = self.rotation * glm.inverse(self.parent.rotation)
|
|
548
|
+
|
|
549
|
+
@forward.setter
|
|
550
|
+
def forward(self, value: tuple | list | glm.vec3 | np.ndarray):
|
|
551
|
+
if isinstance(value, glm.vec3): self._forward = value
|
|
552
|
+
elif isinstance(value, tuple) or isinstance(value, list) or isinstance(value, np.ndarray):
|
|
553
|
+
if len(value) != 3: raise ValueError(f'Node: Invalid number of values for forward. Expected 3, got {len(value)}')
|
|
554
|
+
self._forward = glm.vec3(value)
|
|
555
|
+
else: raise TypeError(f'Node: Invalid forward value type {type(value)}')
|
|
556
|
+
|
|
557
|
+
@mesh.setter
|
|
558
|
+
def mesh(self, value: Mesh | None):
|
|
559
|
+
if isinstance(value, Mesh):
|
|
560
|
+
self._mesh = value
|
|
561
|
+
if self.chunk: self.chunk.update()
|
|
562
|
+
elif isinstance(value, type(None)):
|
|
563
|
+
self._mesh = None
|
|
564
|
+
if not self.chunk: return
|
|
565
|
+
self.chunk.remove(self)
|
|
566
|
+
self.chunk.update()
|
|
567
|
+
else: raise TypeError(f'Node: Invalid mesh value type {type(value)}')
|
|
568
|
+
|
|
569
|
+
@material.setter
|
|
570
|
+
def material(self, value: Material):
|
|
571
|
+
if isinstance(value, list):
|
|
572
|
+
self._mtl_list = value
|
|
573
|
+
if not self.node_handler:
|
|
574
|
+
self._material = value
|
|
575
|
+
else:
|
|
576
|
+
mtl_index_list = []
|
|
577
|
+
for mtl in self._mtl_list:
|
|
578
|
+
self.engine.material_handler.add(mtl)
|
|
579
|
+
mtl_index_list.append(mtl.index)
|
|
580
|
+
mtl_index_list.append(mtl.index)
|
|
581
|
+
mtl_index_list.append(mtl.index)
|
|
582
|
+
self._material = mtl_index_list
|
|
583
|
+
elif isinstance(value, Material):
|
|
584
|
+
self._material = value
|
|
585
|
+
if self.node_handler: self.engine.material_handler.add(value)
|
|
586
|
+
elif isinstance(value, type(None)):
|
|
587
|
+
if self.engine: self._material = self.engine.material_handler.base
|
|
588
|
+
else: self._material = None
|
|
589
|
+
|
|
590
|
+
else: raise TypeError(f'Node: Invalid material value type {type(value)}')
|
|
591
|
+
if not self.chunk: return
|
|
592
|
+
self.chunk.node_update_callback(self)
|
|
593
|
+
|
|
594
|
+
@velocity.setter
|
|
595
|
+
def velocity(self, value: tuple | list | glm.vec3 | np.ndarray | Vec3):
|
|
596
|
+
if isinstance(value, glm.vec3): self._velocity = glm.vec3(value)
|
|
597
|
+
elif isinstance(value, Vec3): self._velocity = glm.vec3(value.data)
|
|
598
|
+
elif isinstance(value, tuple) or isinstance(value, list) or isinstance(value, np.ndarray):
|
|
599
|
+
if len(value) != 3: raise ValueError(f'Node: Invalid number of values for velocity. Expected 3, got {len(value)}')
|
|
600
|
+
self._velocity = glm.vec3(value)
|
|
601
|
+
else: raise TypeError(f'Node: Invalid velocity value type {type(value)}')
|
|
602
|
+
|
|
603
|
+
@rotational_velocity.setter
|
|
604
|
+
def rotational_velocity(self, value: tuple | list | glm.vec3 | np.ndarray | Vec3):
|
|
605
|
+
if isinstance(value, glm.vec3): self._rotational_velocity = glm.vec3(value)
|
|
606
|
+
elif isinstance(value, Vec3): self._rotational_velocity = glm.vec3(value.data)
|
|
607
|
+
elif isinstance(value, tuple) or isinstance(value, list) or isinstance(value, np.ndarray):
|
|
608
|
+
if len(value) != 3: raise ValueError(f'Node: Invalid number of values for rotational velocity. Expected 3, got {len(value)}')
|
|
609
|
+
self._rotational_velocity = glm.vec3(value)
|
|
610
|
+
else: raise TypeError(f'Node: Invalid rotational velocity value type {type(value)}')
|
|
611
|
+
|
|
612
|
+
@mass.setter
|
|
613
|
+
def mass(self, value: int | float):
|
|
614
|
+
if not self.physics_body: raise RuntimeError('Node: Cannot set the mass of a node that has no physics body')
|
|
615
|
+
if isinstance(value, int) or isinstance(value, float): self.physics_body.mass = value
|
|
616
|
+
else: raise TypeError(f'Node: Invalid mass value type {type(value)}')
|
|
617
|
+
|
|
618
|
+
@static_friction.setter
|
|
619
|
+
def static_friction(self, value: int | float):
|
|
620
|
+
if not self.collider: raise RuntimeError('Node: Cannot set the static friction of a node that has no physics body')
|
|
621
|
+
if isinstance(value, int) or isinstance(value, float): self.collider.static_friction = value
|
|
622
|
+
else: raise TypeError(f'Node: Invalid static friction value type {type(value)}')
|
|
623
|
+
|
|
624
|
+
@kinetic_friction.setter
|
|
625
|
+
def kinetic_friction(self, value: int | float):
|
|
626
|
+
if not self.collider: raise RuntimeError('Node: Cannot set the kinetic friction of a node that has no physics body')
|
|
627
|
+
if isinstance(value, int) or isinstance(value, float): self.collider.kinetic_friction = value
|
|
628
|
+
else: raise TypeError(f'Node: Invalid kinetic friction value type {type(value)}')
|
|
629
|
+
|
|
630
|
+
@elasticity.setter
|
|
631
|
+
def elasticity(self, value: int | float):
|
|
632
|
+
if not self.collider: raise RuntimeError('Node: Cannot set the elasticity of a node that has no physics body')
|
|
633
|
+
if isinstance(value, int) or isinstance(value, float): self.collider.elasticity = value
|
|
634
|
+
else: raise TypeError(f'Node: Invalid elasticity value type {type(value)}')
|
|
635
|
+
|
|
636
|
+
@collision_group.setter
|
|
637
|
+
def collision_group(self, value: str):
|
|
638
|
+
if not self.collider: raise RuntimeError('Node: Cannot set the collision gruop of a node that has no physics body')
|
|
639
|
+
if isinstance(value, (str, type(None))): self.collider.collision_group = value
|
|
640
|
+
else: raise TypeError(f'Node: Invalid collision group value type {type(value)}')
|
|
641
|
+
|
|
642
|
+
@name.setter
|
|
643
|
+
def name(self, value: str):
|
|
644
|
+
if isinstance(value, str): self._name = value
|
|
645
|
+
else: raise TypeError(f'Node: Invalid name value type {type(value)}')
|
|
646
|
+
|
|
647
|
+
@tags.setter
|
|
648
|
+
def tags(self, value: list[str]):
|
|
649
|
+
if isinstance(value, list) or isinstance(value, tuple):
|
|
650
|
+
for tag in value:
|
|
651
|
+
if not isinstance(tag, str): raise TypeError(f'Node: Invalid tag value in tags list of type {type(tag)}')
|
|
652
|
+
self._tags = value
|
|
653
|
+
else: raise TypeError(f'Node: Invalid tags value type {type(value)}')
|
|
654
|
+
|
|
655
|
+
@static.setter
|
|
656
|
+
def static(self, value: bool):
|
|
657
|
+
self._static = value
|
|
658
|
+
|
|
659
|
+
@x.setter
|
|
660
|
+
def x(self, value: int | float):
|
|
661
|
+
if isinstance(value, int) or isinstance(value, float): self.internal_position.x = value
|
|
662
|
+
else: raise TypeError(f'Node: Invalid positional x value type {type(value)}')
|
|
663
|
+
|
|
664
|
+
@y.setter
|
|
665
|
+
def y(self, value: int | float):
|
|
666
|
+
if isinstance(value, int) or isinstance(value, float): self.internal_position.y = value
|
|
667
|
+
else: raise TypeError(f'Node: Invalid positional y value type {type(value)}')
|
|
668
|
+
|
|
669
|
+
@z.setter
|
|
670
|
+
def z(self, value: int | float):
|
|
671
|
+
if isinstance(value, int) or isinstance(value, float): self.internal_position.z = value
|
|
672
|
+
else: raise TypeError(f'Node: Invalid positional z value type {type(value)}')
|
|
673
|
+
|
|
674
|
+
@physics.setter
|
|
675
|
+
def physics(self, value: bool | PhysicsBody):
|
|
676
|
+
if not value and self.physics: # remove physics body from self and scene
|
|
677
|
+
if self.node_handler: self.node_handler.scene.physics_engine.remove(self.physics_body)
|
|
678
|
+
self.physics_body = None
|
|
679
|
+
elif isinstance(value, PhysicsBody): # deep copy physics body
|
|
680
|
+
if self.physics:
|
|
681
|
+
self.mass = value.mass
|
|
682
|
+
else:
|
|
683
|
+
self.physics_body = PhysicsBody(value.mass)
|
|
684
|
+
if self.node_handler: self.physics_body.physics_engine = self.node_handler.scene.physics_engine
|
|
685
|
+
elif not self.physics:
|
|
686
|
+
self.physics_body = PhysicsBody(mass = 1)
|
|
687
|
+
if self.node_handler: self.physics_body.physics_engine = self.node_handler.scene.physics_engine
|
|
688
|
+
|
|
689
|
+
|
|
690
|
+
@collision.setter
|
|
691
|
+
def collision(self, value: bool | PhysicsBody):
|
|
692
|
+
if not value and self.collision:
|
|
693
|
+
if self.node_handler: self.node_handler.scene.collider_handler.remove(self.collider)
|
|
694
|
+
self.collider = None
|
|
695
|
+
elif isinstance(value, Collider):
|
|
696
|
+
if self.collision:
|
|
697
|
+
self.kinetic_friction = value.kinetic_friction
|
|
698
|
+
self.elasticity = value.elasticity
|
|
699
|
+
self.static_friction = value.static_friction
|
|
700
|
+
else:
|
|
701
|
+
self.collider = Collider(self, value.mesh, value.static_friction, value.kinetic_friction, value.elasticity, value.collision_group)
|
|
702
|
+
if self.node_handler: self.collider.collider_handler = self.node_handler.scene.collider_handler
|
|
703
|
+
elif not self.collider:
|
|
704
|
+
self.collider = Collider(self)
|
|
696
705
|
if self.node_handler: self.collider.collider_handler = self.node_handler.scene.collider_handler
|