basilisk-engine 0.1.38__py3-none-any.whl → 0.1.40__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 (97) hide show
  1. basilisk/__init__.py +26 -26
  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 +226 -226
  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 +53 -53
  18. basilisk/draw/draw.py +100 -100
  19. basilisk/draw/draw_handler.py +178 -178
  20. basilisk/draw/font_renderer.py +28 -28
  21. basilisk/engine.py +165 -165
  22. basilisk/generic/abstract_bvh.py +15 -15
  23. basilisk/generic/abstract_custom.py +133 -133
  24. basilisk/generic/collisions.py +70 -70
  25. basilisk/generic/input_validation.py +82 -82
  26. basilisk/generic/math.py +18 -7
  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/__init__.py +0 -0
  34. basilisk/input/mouse.py +62 -0
  35. basilisk/input/path.py +14 -0
  36. basilisk/input_output/IO_handler.py +91 -91
  37. basilisk/input_output/clock.py +49 -49
  38. basilisk/input_output/keys.py +43 -43
  39. basilisk/input_output/mouse.py +90 -90
  40. basilisk/input_output/path.py +14 -14
  41. basilisk/mesh/cube.py +33 -33
  42. basilisk/mesh/mesh.py +233 -233
  43. basilisk/mesh/mesh_from_data.py +150 -150
  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 +709 -704
  50. basilisk/nodes/node_handler.py +97 -97
  51. basilisk/particles/particle_handler.py +64 -64
  52. basilisk/particles/particle_renderer.py +93 -93
  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 +103 -103
  57. basilisk/render/bloom.py +107 -107
  58. basilisk/render/camera.py +260 -260
  59. basilisk/render/chunk.py +108 -108
  60. basilisk/render/chunk_handler.py +167 -167
  61. basilisk/render/frame.py +110 -110
  62. basilisk/render/framebuffer.py +202 -202
  63. basilisk/render/image.py +120 -120
  64. basilisk/render/image_handler.py +120 -120
  65. basilisk/render/light.py +96 -96
  66. basilisk/render/light_handler.py +58 -58
  67. basilisk/render/material.py +232 -232
  68. basilisk/render/material_handler.py +133 -133
  69. basilisk/render/post_process.py +146 -146
  70. basilisk/render/shader.py +134 -134
  71. basilisk/render/shader_handler.py +85 -85
  72. basilisk/render/sky.py +120 -120
  73. basilisk/scene.py +290 -290
  74. basilisk/shaders/batch.frag +289 -289
  75. basilisk/shaders/batch.vert +117 -117
  76. basilisk/shaders/bloom_downsample.frag +42 -42
  77. basilisk/shaders/bloom_frame.frag +24 -24
  78. basilisk/shaders/bloom_upsample.frag +33 -33
  79. basilisk/shaders/crt.frag +31 -31
  80. basilisk/shaders/draw.frag +25 -25
  81. basilisk/shaders/draw.vert +25 -25
  82. basilisk/shaders/filter.frag +22 -22
  83. basilisk/shaders/frame.frag +12 -12
  84. basilisk/shaders/frame.vert +13 -13
  85. basilisk/shaders/geometry.frag +10 -10
  86. basilisk/shaders/geometry.vert +41 -41
  87. basilisk/shaders/normal.frag +62 -62
  88. basilisk/shaders/normal.vert +96 -96
  89. basilisk/shaders/particle.frag +76 -76
  90. basilisk/shaders/particle.vert +86 -86
  91. basilisk/shaders/sky.frag +23 -23
  92. basilisk/shaders/sky.vert +13 -13
  93. {basilisk_engine-0.1.38.dist-info → basilisk_engine-0.1.40.dist-info}/METADATA +89 -89
  94. basilisk_engine-0.1.40.dist-info/RECORD +114 -0
  95. {basilisk_engine-0.1.38.dist-info → basilisk_engine-0.1.40.dist-info}/WHEEL +1 -1
  96. basilisk_engine-0.1.38.dist-info/RECORD +0 -111
  97. {basilisk_engine-0.1.38.dist-info → basilisk_engine-0.1.40.dist-info}/top_level.txt +0 -0
@@ -1,71 +1,71 @@
1
- import glm
2
- from ..generic.vec3 import Vec3
3
- from ..generic.quat import Quat
4
-
5
-
6
- def collide_aabb_aabb(top_right1: glm.vec3, bottom_left1: glm.vec3, top_right2: glm.vec3, bottom_left2: glm.vec3, epsilon:float=1e-7) -> bool:
7
- """
8
- Determines if two aabbs are colliding
9
- """
10
- return all(bottom_left1[i] <= top_right2[i] + epsilon and epsilon + top_right1[i] >= bottom_left2[i] for i in range(3))
11
-
12
- def collide_aabb_line(top_right: glm.vec3, bottom_left: glm.vec3, position: glm.vec3, forward: glm.vec3) -> bool: # TODO check algorithm
13
- """
14
- Determines if an infinite line intersects with an AABB
15
- """
16
- # based on Smit's algorithm
17
- inv_dir = glm.vec3([1 / i if i != 0 else float('inf') for i in forward])
18
-
19
- t1 = (bottom_left - position) * inv_dir
20
- t2 = (top_right - position) * inv_dir
21
-
22
- t_min = glm.min(t1, t2) # entry point along each axis
23
- t_max = glm.max(t1, t2) # exit point along each axis
24
-
25
- t_entry = max(t_min.x, t_min.y, t_min.z) # furthest entry time
26
- t_exit = min(t_max.x, t_max.y, t_max.z) # earliest exit time
27
-
28
- return t_entry <= t_exit and t_exit >= 0
29
-
30
- def moller_trumbore(point:glm.vec3, vec:glm.vec3, triangle:list[glm.vec3], epsilon:float=1e-7) -> glm.vec3:
31
- """
32
- Determines where a line intersects with a triangle and where that intersection occurred
33
- """
34
- edge1, edge2 = triangle[1] - triangle[0], triangle[2] - triangle[0]
35
- ray_cross = glm.cross(vec, edge2)
36
- det = glm.dot(edge1, ray_cross)
37
-
38
- # if the ray is parallel to the triangle
39
- if abs(det) < epsilon: return None
40
-
41
- inv_det = 1 / det
42
- s = point - triangle[0]
43
- u = glm.dot(s, ray_cross) * inv_det
44
-
45
- if (u < 0 and abs(u) > epsilon) or (u > 1 and abs(u - 1) > epsilon): return None
46
-
47
- s_cross = glm.cross(s, edge1)
48
- v = glm.dot(vec, s_cross) * inv_det
49
-
50
- if (v < 0 and abs(v) > epsilon) or (u + v > 1 and abs(u + v - 1) > epsilon): return None
51
-
52
- t = glm.dot(edge2, s_cross) * inv_det
53
- if t > epsilon: return point + vec * t
54
- return None
55
-
56
- def get_sat_axes(rotation1: Quat, rotation2: Quat) -> list[glm.vec3]:
57
- """
58
- Gets the axes for SAT from obb rotation matrices
59
- """
60
- axes = []
61
- axes.extend(glm.transpose(glm.mat3_cast(rotation1.data)))
62
- axes.extend(glm.transpose(glm.mat3_cast(rotation2.data)))
63
-
64
- # crossed roots
65
- for i in range(0, 3):
66
- for j in range(3, 6):
67
- cross = glm.cross(axes[i], axes[j])
68
- if glm.length2(cross) < 1e-6: continue
69
- axes.append(glm.normalize(cross))
70
-
1
+ import glm
2
+ from ..generic.vec3 import Vec3
3
+ from ..generic.quat import Quat
4
+
5
+
6
+ def collide_aabb_aabb(top_right1: glm.vec3, bottom_left1: glm.vec3, top_right2: glm.vec3, bottom_left2: glm.vec3, epsilon:float=1e-7) -> bool:
7
+ """
8
+ Determines if two aabbs are colliding
9
+ """
10
+ return all(bottom_left1[i] <= top_right2[i] + epsilon and epsilon + top_right1[i] >= bottom_left2[i] for i in range(3))
11
+
12
+ def collide_aabb_line(top_right: glm.vec3, bottom_left: glm.vec3, position: glm.vec3, forward: glm.vec3) -> bool: # TODO check algorithm
13
+ """
14
+ Determines if an infinite line intersects with an AABB
15
+ """
16
+ # based on Smit's algorithm
17
+ inv_dir = glm.vec3([1 / i if i != 0 else float('inf') for i in forward])
18
+
19
+ t1 = (bottom_left - position) * inv_dir
20
+ t2 = (top_right - position) * inv_dir
21
+
22
+ t_min = glm.min(t1, t2) # entry point along each axis
23
+ t_max = glm.max(t1, t2) # exit point along each axis
24
+
25
+ t_entry = max(t_min.x, t_min.y, t_min.z) # furthest entry time
26
+ t_exit = min(t_max.x, t_max.y, t_max.z) # earliest exit time
27
+
28
+ return t_entry <= t_exit and t_exit >= 0
29
+
30
+ def moller_trumbore(point:glm.vec3, vec:glm.vec3, triangle:list[glm.vec3], epsilon:float=1e-7) -> glm.vec3:
31
+ """
32
+ Determines where a line intersects with a triangle and where that intersection occurred
33
+ """
34
+ edge1, edge2 = triangle[1] - triangle[0], triangle[2] - triangle[0]
35
+ ray_cross = glm.cross(vec, edge2)
36
+ det = glm.dot(edge1, ray_cross)
37
+
38
+ # if the ray is parallel to the triangle
39
+ if abs(det) < epsilon: return None
40
+
41
+ inv_det = 1 / det
42
+ s = point - triangle[0]
43
+ u = glm.dot(s, ray_cross) * inv_det
44
+
45
+ if (u < 0 and abs(u) > epsilon) or (u > 1 and abs(u - 1) > epsilon): return None
46
+
47
+ s_cross = glm.cross(s, edge1)
48
+ v = glm.dot(vec, s_cross) * inv_det
49
+
50
+ if (v < 0 and abs(v) > epsilon) or (u + v > 1 and abs(u + v - 1) > epsilon): return None
51
+
52
+ t = glm.dot(edge2, s_cross) * inv_det
53
+ if t > epsilon: return point + vec * t
54
+ return None
55
+
56
+ def get_sat_axes(rotation1: Quat, rotation2: Quat) -> list[glm.vec3]:
57
+ """
58
+ Gets the axes for SAT from obb rotation matrices
59
+ """
60
+ axes = []
61
+ axes.extend(glm.transpose(glm.mat3_cast(rotation1.data)))
62
+ axes.extend(glm.transpose(glm.mat3_cast(rotation2.data)))
63
+
64
+ # crossed roots
65
+ for i in range(0, 3):
66
+ for j in range(3, 6):
67
+ cross = glm.cross(axes[i], axes[j])
68
+ if glm.length2(cross) < 1e-6: continue
69
+ axes.append(glm.normalize(cross))
70
+
71
71
  return axes
@@ -1,83 +1,83 @@
1
- import numpy as np
2
- import glm
3
- from ..render.image import Image
4
-
5
-
6
- def validate_int(module: str, name: str, value: int | float | glm.int32) -> float:
7
- if isinstance(value, int) or isinstance(value, float):
8
- return int(round(value))
9
- elif isinstance(value, glm.int32):
10
- return int(value.value)
11
- else:
12
- raise TypeError(f"{module}: Invalid {name} value type {type(value)}. Expected float.")
13
-
14
- def validate_float(module: str, name: str, value: float | int | glm.float32) -> float:
15
- if isinstance(value, float) or isinstance(value, int):
16
- return float(value)
17
- elif isinstance(value, glm.float32):
18
- return float(value.value)
19
- else:
20
- raise TypeError(f"{module}: Invalid {name} value type {type(value)}. Expected float.")
21
-
22
- def validate_glm_float(module: str, name: str, value: float | int | glm.float32) -> glm.float32:
23
- if isinstance(value, float) or isinstance(value, int):
24
- return glm.float32(value)
25
- elif isinstance(value, glm.float32):
26
- return value
27
- else:
28
- raise TypeError(f"{module}: Invalid {name} value type {type(value)}. Expected glm.float32 or convertable value.")
29
-
30
- def validate_glm_vec3(module: str, name: str, value: tuple | list | glm.vec3 | np.ndarray) -> glm.vec3:
31
- if isinstance(value, tuple) or isinstance(value, list) or isinstance(value, np.ndarray):
32
- if len(value) != 3: raise ValueError(f"{module}: Invalid number of values for {name}. Expected 3 values, got {len(value)} values")
33
- return glm.vec3(value)
34
- elif isinstance(value, glm.vec3) or isinstance(value, int) or isinstance(value, float):
35
- return glm.vec3(value)
36
- else:
37
- raise TypeError(f"{module}: Invalid {name} value type {type(value)}. Expected glm.vec3")
38
-
39
- def validate_tuple3(module: str, name: str, value: tuple | list | glm.vec3 | np.ndarray) -> tuple:
40
- if isinstance(value, tuple) or isinstance(value, list) or isinstance(value, np.ndarray):
41
- if len(value) != 3: raise ValueError(f"{module}: Invalid number of values for {name}. Expected 3 values, got {len(value)} values")
42
- return tuple(value)
43
- elif isinstance(value, glm.vec3):
44
- return (value.x, value.y, value.z)
45
- if isinstance(value, int) or isinstance(value, float):
46
- return (value, value, value)
47
- else:
48
- raise TypeError(f"{module}: Invalid {name} value type {type(value)}. Expected tuple of size 3")
49
-
50
- def validate_image(module: str, name: str, value: Image | None) -> Image | None:
51
- """Accepts none as a value for no image"""
52
- if isinstance(value, Image) or isinstance(value, type(None)):
53
- return value
54
- else:
55
- raise TypeError(f"{module}: Invalid {name} value type {type(value)}. Expected bsk.Image or None")
56
-
57
- def validate_color(module: str, name: str, value: tuple | list | np.ndarray | int | float | None) -> tuple:
58
- if isinstance(value, tuple) or isinstance(value, list) or isinstance(value, np.ndarray):
59
- if len(value) == 4:
60
- return tuple(map(lambda x: x / 255, value))
61
- elif len(value) == 3:
62
- return (*tuple(map(lambda x: x / 255, value)), 1.0)
63
- else:
64
- raise TypeError(f"{module}: Invalid number of values for {name}. Expected 3 or 4 values, got {len(value)} values")
65
- elif isinstance(value, int) or isinstance(value, float):
66
- v = value / 255
67
- return (v, v, v, 1.0)
68
- else:
69
- raise TypeError(f"{module}: Invalid {name} value type {type(value)}. Expected tuple of size 3 or 4")
70
-
71
- def validate_rect(rect) -> tuple:
72
- if not (isinstance(rect, tuple) or isinstance(rect, list) or isinstance(rect, np.ndarray)):
73
- raise TypeError(f'Invalid rect type: {type(rect)}. Expected a tuple, list, or numpy array')
74
- if len(rect) != 4:
75
- raise TypeError(f'Invalid number of rect values. Expected 4 values, got {len(rect)}')
76
- return list(rect)
77
-
78
- def validate_point(point) -> tuple:
79
- if not (isinstance(point, tuple) or isinstance(point, list) or isinstance(point, np.ndarray)):
80
- raise TypeError(f'Invalid rect type: {type(point)}. Expected a tuple, list, or numpy array')
81
- if len(point) != 2:
82
- raise TypeError(f'Invalid number of rect values. Expected 2 values, got {len(point)}')
1
+ import numpy as np
2
+ import glm
3
+ from ..render.image import Image
4
+
5
+
6
+ def validate_int(module: str, name: str, value: int | float | glm.int32) -> float:
7
+ if isinstance(value, int) or isinstance(value, float):
8
+ return int(round(value))
9
+ elif isinstance(value, glm.int32):
10
+ return int(value.value)
11
+ else:
12
+ raise TypeError(f"{module}: Invalid {name} value type {type(value)}. Expected float.")
13
+
14
+ def validate_float(module: str, name: str, value: float | int | glm.float32) -> float:
15
+ if isinstance(value, float) or isinstance(value, int):
16
+ return float(value)
17
+ elif isinstance(value, glm.float32):
18
+ return float(value.value)
19
+ else:
20
+ raise TypeError(f"{module}: Invalid {name} value type {type(value)}. Expected float.")
21
+
22
+ def validate_glm_float(module: str, name: str, value: float | int | glm.float32) -> glm.float32:
23
+ if isinstance(value, float) or isinstance(value, int):
24
+ return glm.float32(value)
25
+ elif isinstance(value, glm.float32):
26
+ return value
27
+ else:
28
+ raise TypeError(f"{module}: Invalid {name} value type {type(value)}. Expected glm.float32 or convertable value.")
29
+
30
+ def validate_glm_vec3(module: str, name: str, value: tuple | list | glm.vec3 | np.ndarray) -> glm.vec3:
31
+ if isinstance(value, tuple) or isinstance(value, list) or isinstance(value, np.ndarray):
32
+ if len(value) != 3: raise ValueError(f"{module}: Invalid number of values for {name}. Expected 3 values, got {len(value)} values")
33
+ return glm.vec3(value)
34
+ elif isinstance(value, glm.vec3) or isinstance(value, int) or isinstance(value, float):
35
+ return glm.vec3(value)
36
+ else:
37
+ raise TypeError(f"{module}: Invalid {name} value type {type(value)}. Expected glm.vec3")
38
+
39
+ def validate_tuple3(module: str, name: str, value: tuple | list | glm.vec3 | np.ndarray) -> tuple:
40
+ if isinstance(value, tuple) or isinstance(value, list) or isinstance(value, np.ndarray):
41
+ if len(value) != 3: raise ValueError(f"{module}: Invalid number of values for {name}. Expected 3 values, got {len(value)} values")
42
+ return tuple(value)
43
+ elif isinstance(value, glm.vec3):
44
+ return (value.x, value.y, value.z)
45
+ if isinstance(value, int) or isinstance(value, float):
46
+ return (value, value, value)
47
+ else:
48
+ raise TypeError(f"{module}: Invalid {name} value type {type(value)}. Expected tuple of size 3")
49
+
50
+ def validate_image(module: str, name: str, value: Image | None) -> Image | None:
51
+ """Accepts none as a value for no image"""
52
+ if isinstance(value, Image) or isinstance(value, type(None)):
53
+ return value
54
+ else:
55
+ raise TypeError(f"{module}: Invalid {name} value type {type(value)}. Expected bsk.Image or None")
56
+
57
+ def validate_color(module: str, name: str, value: tuple | list | np.ndarray | int | float | None) -> tuple:
58
+ if isinstance(value, tuple) or isinstance(value, list) or isinstance(value, np.ndarray):
59
+ if len(value) == 4:
60
+ return tuple(map(lambda x: x / 255, value))
61
+ elif len(value) == 3:
62
+ return (*tuple(map(lambda x: x / 255, value)), 1.0)
63
+ else:
64
+ raise TypeError(f"{module}: Invalid number of values for {name}. Expected 3 or 4 values, got {len(value)} values")
65
+ elif isinstance(value, int) or isinstance(value, float):
66
+ v = value / 255
67
+ return (v, v, v, 1.0)
68
+ else:
69
+ raise TypeError(f"{module}: Invalid {name} value type {type(value)}. Expected tuple of size 3 or 4")
70
+
71
+ def validate_rect(rect) -> tuple:
72
+ if not (isinstance(rect, tuple) or isinstance(rect, list) or isinstance(rect, np.ndarray)):
73
+ raise TypeError(f'Invalid rect type: {type(rect)}. Expected a tuple, list, or numpy array')
74
+ if len(rect) != 4:
75
+ raise TypeError(f'Invalid number of rect values. Expected 4 values, got {len(rect)}')
76
+ return list(rect)
77
+
78
+ def validate_point(point) -> tuple:
79
+ if not (isinstance(point, tuple) or isinstance(point, list) or isinstance(point, np.ndarray)):
80
+ raise TypeError(f'Invalid rect type: {type(point)}. Expected a tuple, list, or numpy array')
81
+ if len(point) != 2:
82
+ raise TypeError(f'Invalid number of rect values. Expected 2 values, got {len(point)}')
83
83
  return list(point)
basilisk/generic/math.py CHANGED
@@ -1,7 +1,18 @@
1
- import glm
2
-
3
- def triple_product(vector1, vector2, vector3) -> glm.vec3:
4
- """
5
- Computes (1 x 2) x 3
6
- """
7
- return glm.cross(glm.cross(vector1, vector2), vector3)
1
+ import glm
2
+
3
+ def triple_product(vector1, vector2, vector3) -> glm.vec3:
4
+ """
5
+ Computes (1 x 2) x 3
6
+ """
7
+ return glm.cross(glm.cross(vector1, vector2), vector3)
8
+
9
+ def relative_transforms(parent, child) -> tuple[glm.vec3, glm.vec3, glm.quat]:
10
+ """
11
+ Calculates the relative transforms for position, scale, and rotation for the parent and child. parent and child are Nodes
12
+ """
13
+ relative = glm.inverse(parent.model_matrix) * child.model_matrix
14
+ position = glm.vec3(relative[3])
15
+ scale = glm.vec3([glm.length(relative[i]) for i in range(3)])
16
+ rotation = child.rotation.data * glm.inverse(parent.rotation.data)
17
+
18
+ return position, scale, rotation
@@ -1,36 +1,36 @@
1
- import glm
2
- from ..generic.vec3 import Vec3
3
- from ..generic.quat import Quat
4
-
5
-
6
- # transform matrices
7
- def get_model_matrix(position: Vec3, scale: Vec3, rotation: Quat) -> glm.mat4x4:
8
- """
9
- Gets projection matrix from object data
10
- """
11
- translation_matrix = glm.translate(glm.mat4(1.0), position.data)
12
- rotation_matrix = glm.mat4_cast(rotation.data)
13
- scale_matrix = glm.scale(glm.mat4(1.0), scale.data)
14
- model_matrix = translation_matrix * glm.transpose(rotation_matrix) * scale_matrix
15
- return model_matrix
16
-
17
- def get_scale_matrix(scale: glm.vec3) -> glm.mat3x3:
18
- """
19
- Gets the scaling matrix from a scale vector
20
- """
21
- return glm.mat3x3(
22
- scale.x, 0, 0,
23
- 0, scale.y, 0,
24
- 0, 0, scale.z
25
- )
26
-
27
- # inertia tensors
28
- def compute_inertia_moment(t:list[glm.vec3], i:int) -> float:
29
- return t[0][i] ** 2 + t[1][i] * t[2][i] + \
30
- t[1][i] ** 2 + t[0][i] * t[2][i] + \
31
- t[2][i] ** 2 + t[0][i] * t[1][i]
32
-
33
- def compute_inertia_product(t:list[glm.vec3], i:int, j:int) -> float:
34
- return 2 * t[0][i] * t[0][j] + t[1][i] * t[2][j] + t[2][i] * t[1][j] + \
35
- 2 * t[1][i] * t[1][j] + t[0][i] * t[2][j] + t[2][i] * t[0][j] + \
1
+ import glm
2
+ from ..generic.vec3 import Vec3
3
+ from ..generic.quat import Quat
4
+
5
+
6
+ # transform matrices
7
+ def get_model_matrix(position: Vec3, scale: Vec3, rotation: Quat) -> glm.mat4x4:
8
+ """
9
+ Gets projection matrix from object data
10
+ """
11
+ translation_matrix = glm.translate(glm.mat4(1.0), position.data)
12
+ rotation_matrix = glm.mat4_cast(rotation.data)
13
+ scale_matrix = glm.scale(glm.mat4(1.0), scale.data)
14
+ model_matrix = translation_matrix * glm.transpose(rotation_matrix) * scale_matrix
15
+ return model_matrix
16
+
17
+ def get_scale_matrix(scale: glm.vec3) -> glm.mat3x3:
18
+ """
19
+ Gets the scaling matrix from a scale vector
20
+ """
21
+ return glm.mat3x3(
22
+ scale.x, 0, 0,
23
+ 0, scale.y, 0,
24
+ 0, 0, scale.z
25
+ )
26
+
27
+ # inertia tensors
28
+ def compute_inertia_moment(t:list[glm.vec3], i:int) -> float:
29
+ return t[0][i] ** 2 + t[1][i] * t[2][i] + \
30
+ t[1][i] ** 2 + t[0][i] * t[2][i] + \
31
+ t[2][i] ** 2 + t[0][i] * t[1][i]
32
+
33
+ def compute_inertia_product(t:list[glm.vec3], i:int, j:int) -> float:
34
+ return 2 * t[0][i] * t[0][j] + t[1][i] * t[2][j] + t[2][i] * t[1][j] + \
35
+ 2 * t[1][i] * t[1][j] + t[0][i] * t[2][j] + t[2][i] * t[0][j] + \
36
36
  2 * t[2][i] * t[2][j] + t[0][i] * t[1][j] + t[1][i] * t[0][j]
@@ -1,73 +1,73 @@
1
- import glm
2
- import numpy as np
3
-
4
-
5
- # transformations
6
- def transform_points(points: np.ndarray, model_matrix: glm.mat4x4) -> list[glm.vec3]:
7
- """
8
- Transforms the mesh points to world space
9
- """
10
- return [model_matrix * pt for pt in points]
11
-
12
- # bvh
13
- def get_aabb_surface_area(top_right: glm.vec3, bottom_left: glm.vec3) -> float:
14
- """
15
- Returns the surface area of the AABB
16
- """
17
- diagonal = top_right - bottom_left
18
- return 2 * (diagonal.x * diagonal.y + diagonal.y * diagonal.z + diagonal.x * diagonal.z)
19
-
20
- def get_extreme_points_np(points: np.ndarray) -> tuple[glm.vec3, glm.vec3]:
21
- """
22
- Returns the top right and bottom left points of the aabb encapsulating the points
23
- """
24
- top_right = glm.vec3(-1e10)
25
- bottom_left = glm.vec3(1e10)
26
- for pt in points:
27
- for i in range(3):
28
- if top_right[i] < pt[i]: top_right[i] = pt[i]
29
- if bottom_left[i] > pt[i]: bottom_left[i] = pt[i]
30
- return top_right, bottom_left
31
-
32
- def get_aabb_line_collision(top_right:glm.vec3, bottom_left:glm.vec3, point:glm.vec3, vec:glm.vec3) -> bool:
33
- """
34
- Determines if a line has collided with an aabb
35
- """
36
- tmin, tmax = -1e10, 1e10
37
- for i in range(3):
38
- if vec[i] != 0:
39
- inv_dir = 1.0 / vec[i]
40
- t1 = (bottom_left[i] - point[i]) * inv_dir
41
- t2 = (top_right[i] - point[i]) * inv_dir
42
- t1, t2 = min(t1, t2), max(t1, t2)
43
- tmin = max(tmin, t1)
44
- tmax = min(tmax, t2)
45
- if tmin > tmax: return False
46
- elif point[i] < bottom_left[i] or point[i] > top_right[i]: return False
47
- return tmax >= 0 and tmin <= 1
48
-
49
- def moller_trumbore(point:glm.vec3, vec:glm.vec3, triangle:list[glm.vec3], epsilon:float=1e-7) -> glm.vec3 | None:
50
- """
51
- Determines where a line intersects with a triangle and where that intersection occurred
52
- """
53
- edge1, edge2 = triangle[1] - triangle[0], triangle[2] - triangle[0]
54
- ray_cross = glm.cross(vec, edge2)
55
- det = glm.dot(edge1, ray_cross)
56
-
57
- # if the ray is parallel to the triangle
58
- if abs(det) < epsilon: return None
59
-
60
- inv_det = 1 / det
61
- s = point - triangle[0]
62
- u = glm.dot(s, ray_cross) * inv_det
63
-
64
- if (u < 0 and abs(u) > epsilon) or (u > 1 and abs(u - 1) > epsilon): return None
65
-
66
- s_cross = glm.cross(s, edge1)
67
- v = glm.dot(vec, s_cross) * inv_det
68
-
69
- if (v < 0 and abs(v) > epsilon) or (u + v > 1 and abs(u + v - 1) > epsilon): return None
70
-
71
- t = glm.dot(edge2, s_cross) * inv_det
72
- if t > epsilon: return point + vec * t
1
+ import glm
2
+ import numpy as np
3
+
4
+
5
+ # transformations
6
+ def transform_points(points: np.ndarray, model_matrix: glm.mat4x4) -> list[glm.vec3]:
7
+ """
8
+ Transforms the mesh points to world space
9
+ """
10
+ return [model_matrix * pt for pt in points]
11
+
12
+ # bvh
13
+ def get_aabb_surface_area(top_right: glm.vec3, bottom_left: glm.vec3) -> float:
14
+ """
15
+ Returns the surface area of the AABB
16
+ """
17
+ diagonal = top_right - bottom_left
18
+ return 2 * (diagonal.x * diagonal.y + diagonal.y * diagonal.z + diagonal.x * diagonal.z)
19
+
20
+ def get_extreme_points_np(points: np.ndarray) -> tuple[glm.vec3, glm.vec3]:
21
+ """
22
+ Returns the top right and bottom left points of the aabb encapsulating the points
23
+ """
24
+ top_right = glm.vec3(-1e10)
25
+ bottom_left = glm.vec3(1e10)
26
+ for pt in points:
27
+ for i in range(3):
28
+ if top_right[i] < pt[i]: top_right[i] = pt[i]
29
+ if bottom_left[i] > pt[i]: bottom_left[i] = pt[i]
30
+ return top_right, bottom_left
31
+
32
+ def get_aabb_line_collision(top_right:glm.vec3, bottom_left:glm.vec3, point:glm.vec3, vec:glm.vec3) -> bool:
33
+ """
34
+ Determines if a line has collided with an aabb
35
+ """
36
+ tmin, tmax = -1e10, 1e10
37
+ for i in range(3):
38
+ if vec[i] != 0:
39
+ inv_dir = 1.0 / vec[i]
40
+ t1 = (bottom_left[i] - point[i]) * inv_dir
41
+ t2 = (top_right[i] - point[i]) * inv_dir
42
+ t1, t2 = min(t1, t2), max(t1, t2)
43
+ tmin = max(tmin, t1)
44
+ tmax = min(tmax, t2)
45
+ if tmin > tmax: return False
46
+ elif point[i] < bottom_left[i] or point[i] > top_right[i]: return False
47
+ return tmax >= 0 and tmin <= 1
48
+
49
+ def moller_trumbore(point:glm.vec3, vec:glm.vec3, triangle:list[glm.vec3], epsilon:float=1e-7) -> glm.vec3 | None:
50
+ """
51
+ Determines where a line intersects with a triangle and where that intersection occurred
52
+ """
53
+ edge1, edge2 = triangle[1] - triangle[0], triangle[2] - triangle[0]
54
+ ray_cross = glm.cross(vec, edge2)
55
+ det = glm.dot(edge1, ray_cross)
56
+
57
+ # if the ray is parallel to the triangle
58
+ if abs(det) < epsilon: return None
59
+
60
+ inv_det = 1 / det
61
+ s = point - triangle[0]
62
+ u = glm.dot(s, ray_cross) * inv_det
63
+
64
+ if (u < 0 and abs(u) > epsilon) or (u > 1 and abs(u - 1) > epsilon): return None
65
+
66
+ s_cross = glm.cross(s, edge1)
67
+ v = glm.dot(vec, s_cross) * inv_det
68
+
69
+ if (v < 0 and abs(v) > epsilon) or (u + v > 1 and abs(u + v - 1) > epsilon): return None
70
+
71
+ t = glm.dot(edge2, s_cross) * inv_det
72
+ if t > epsilon: return point + vec * t
73
73
  return None