basilisk-engine 0.1.2__py3-none-any.whl → 0.1.3__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 (82) hide show
  1. basilisk/__init__.py +11 -11
  2. basilisk/bsk_assets/cube.obj +48 -48
  3. basilisk/collisions/broad/broad_aabb.py +102 -102
  4. basilisk/collisions/broad/broad_bvh.py +137 -137
  5. basilisk/collisions/collider.py +95 -83
  6. basilisk/collisions/collider_handler.py +225 -228
  7. basilisk/collisions/narrow/contact_manifold.py +90 -90
  8. basilisk/collisions/narrow/dataclasses.py +33 -27
  9. basilisk/collisions/narrow/deprecated.py +46 -46
  10. basilisk/collisions/narrow/epa.py +91 -91
  11. basilisk/collisions/narrow/gjk.py +66 -66
  12. basilisk/collisions/narrow/graham_scan.py +24 -24
  13. basilisk/collisions/narrow/helper.py +29 -29
  14. basilisk/collisions/narrow/line_intersections.py +106 -106
  15. basilisk/collisions/narrow/sutherland_hodgman.py +75 -75
  16. basilisk/config.py +2 -2
  17. basilisk/draw/draw.py +100 -100
  18. basilisk/draw/draw_handler.py +180 -210
  19. basilisk/draw/font_renderer.py +28 -28
  20. basilisk/engine.py +195 -195
  21. basilisk/generic/abstract_bvh.py +15 -15
  22. basilisk/generic/abstract_custom.py +133 -133
  23. basilisk/generic/collisions.py +70 -70
  24. basilisk/generic/input_validation.py +67 -28
  25. basilisk/generic/math.py +6 -6
  26. basilisk/generic/matrices.py +33 -33
  27. basilisk/generic/meshes.py +72 -72
  28. basilisk/generic/quat.py +137 -137
  29. basilisk/generic/quat_methods.py +7 -7
  30. basilisk/generic/raycast_result.py +24 -0
  31. basilisk/generic/vec3.py +143 -143
  32. basilisk/input/mouse.py +61 -59
  33. basilisk/mesh/cube.py +33 -33
  34. basilisk/mesh/mesh.py +230 -230
  35. basilisk/mesh/mesh_from_data.py +132 -132
  36. basilisk/mesh/model.py +271 -271
  37. basilisk/mesh/narrow_aabb.py +89 -89
  38. basilisk/mesh/narrow_bvh.py +91 -91
  39. basilisk/mesh/narrow_primative.py +23 -23
  40. basilisk/nodes/helper.py +29 -0
  41. basilisk/nodes/node.py +681 -617
  42. basilisk/nodes/node_handler.py +95 -118
  43. basilisk/particles/particle_handler.py +63 -54
  44. basilisk/particles/particle_renderer.py +87 -87
  45. basilisk/physics/impulse.py +112 -112
  46. basilisk/physics/physics_body.py +43 -43
  47. basilisk/physics/physics_engine.py +35 -35
  48. basilisk/render/batch.py +86 -86
  49. basilisk/render/camera.py +204 -199
  50. basilisk/render/chunk.py +99 -99
  51. basilisk/render/chunk_handler.py +154 -154
  52. basilisk/render/frame.py +181 -181
  53. basilisk/render/image.py +75 -75
  54. basilisk/render/image_handler.py +122 -122
  55. basilisk/render/light.py +96 -96
  56. basilisk/render/light_handler.py +58 -58
  57. basilisk/render/material.py +219 -219
  58. basilisk/render/material_handler.py +135 -135
  59. basilisk/render/shader.py +109 -109
  60. basilisk/render/shader_handler.py +79 -79
  61. basilisk/render/sky.py +120 -120
  62. basilisk/scene.py +250 -210
  63. basilisk/shaders/batch.frag +276 -276
  64. basilisk/shaders/batch.vert +115 -115
  65. basilisk/shaders/draw.frag +21 -21
  66. basilisk/shaders/draw.vert +21 -21
  67. basilisk/shaders/filter.frag +22 -22
  68. basilisk/shaders/frame.frag +12 -12
  69. basilisk/shaders/frame.vert +13 -13
  70. basilisk/shaders/geometry.frag +8 -8
  71. basilisk/shaders/geometry.vert +41 -41
  72. basilisk/shaders/normal.frag +59 -59
  73. basilisk/shaders/normal.vert +96 -96
  74. basilisk/shaders/particle.frag +71 -71
  75. basilisk/shaders/particle.vert +84 -84
  76. basilisk/shaders/sky.frag +9 -9
  77. basilisk/shaders/sky.vert +13 -13
  78. {basilisk_engine-0.1.2.dist-info → basilisk_engine-0.1.3.dist-info}/METADATA +45 -38
  79. basilisk_engine-0.1.3.dist-info/RECORD +97 -0
  80. {basilisk_engine-0.1.2.dist-info → basilisk_engine-0.1.3.dist-info}/WHEEL +1 -1
  81. basilisk_engine-0.1.2.dist-info/RECORD +0 -95
  82. {basilisk_engine-0.1.2.dist-info → basilisk_engine-0.1.3.dist-info}/top_level.txt +0 -0
@@ -1,229 +1,226 @@
1
- import glm
2
-
3
- from .collider import Collider
4
- from .broad.broad_bvh import BroadBVH
5
- from .narrow.gjk import collide_gjk
6
- from .narrow.epa import get_epa_from_gjk
7
- from .narrow.contact_manifold import get_contact_manifold, separate_polytope
8
- from .narrow.dataclasses import SupportPoint, ContactPoint, ContactManifold
9
- from ..nodes.node import Node
10
- from ..generic.collisions import get_sat_axes
11
- from ..physics.impulse import calculate_collisions
12
-
13
- class ColliderHandler():
14
- scene: ...
15
- """Back reference to scene"""
16
- colliders: list[Collider]
17
- """Main list of collders contained in the scene"""
18
- bvh: BroadBVH
19
- """Broad bottom up BVH containing all colliders in the scene"""
20
-
21
- def __init__(self, scene) -> None:
22
- self.scene = scene
23
- self.cube = self.scene.engine.cube
24
- self.colliders = []
25
- self.polytope_data = {}
26
- self.contact_manifolds: dict[tuple[Collider, Collider] : ContactManifold] = {}
27
- self.bvh = BroadBVH(self)
28
-
29
- def add(self, collider: Collider) -> Collider:
30
- """
31
- Creates a collider and adds it to the collider list
32
- """
33
- self.colliders.append(collider)
34
- self.bvh.add(collider)
35
- return collider
36
-
37
- def remove(self, collider: Collider) -> None:
38
- """
39
- Removes a collider from the main branch and BVH
40
- """
41
- if collider in self.colliders: self.colliders.remove(collider)
42
- self.bvh.remove(collider)
43
- collider.collider_handler = None
44
-
45
- def resolve_collisions(self) -> None:
46
- """
47
- Resets collider collision values and resolves all collisions in the scene
48
- """
49
- # reset collision data
50
- for collider in self.colliders: collider.collisions = {}
51
-
52
-
53
- # update BVH
54
- for collider in self.colliders:
55
- if collider.needs_bvh:
56
- self.bvh.remove(collider)
57
- self.bvh.add(collider)
58
- collider.needs_bvh = False
59
-
60
- # resolve collisions
61
- broad_collisions = self.resolve_broad_collisions()
62
- self.resolve_narrow_collisions(broad_collisions)
63
-
64
- def collide_obb_obb(self, collider1: Collider, collider2: Collider) -> tuple[glm.vec3, float] | None:
65
- """
66
- Finds the minimal penetrating vector for an obb obb collision, return None if not colliding. Uses SAT.
67
- """
68
- axes = get_sat_axes(collider1.node.rotation, collider2.node.rotation) # axes are normaized
69
- points1 = collider1.obb_points # TODO remove once oobb points are lazy updated, switch to just using property
70
- points2 = collider2.obb_points
71
-
72
- # test axes
73
- small_axis = None
74
- small_overlap = 1e10
75
- small_index = 0
76
- for i, axis in enumerate(axes): # TODO add optimization for points on cardinal axis of cuboid
77
- # "project" points
78
- proj1 = [glm.dot(p, axis) for p in points1]
79
- proj2 = [glm.dot(p, axis) for p in points2]
80
- max1, min1 = max(proj1), min(proj1)
81
- max2, min2 = max(proj2), min(proj2)
82
- if max1 < min2 or max2 < min1: return None
83
-
84
- # if lines are not intersecting
85
- if max1 > max2 and min1 < min2: overlap = min(max1 - min2, max2 - min1)
86
- elif max2 > max1 and min2 < min1: overlap = min(max2 - min1, max1 - min2)
87
- else: overlap = min(max1, max2) - max(min1, min2) # TODO check if works with containment
88
-
89
- if abs(overlap) > abs(small_overlap): continue
90
- small_overlap = overlap
91
- small_axis = axis
92
- small_index = i
93
-
94
- return small_axis, small_overlap, small_index
95
-
96
- def collide_obb_obb_decision(self, collider1: Collider, collider2: Collider) -> bool:
97
- """
98
- Determines if two obbs are colliding Uses SAT.
99
- """
100
- axes = get_sat_axes(collider1.node.rotation, collider2.node.rotation)
101
- points1 = collider1.obb_points # TODO remove once oobb points are lazy updated, switch to just using property
102
- points2 = collider2.obb_points
103
-
104
- # test axes
105
- for axis in axes: # TODO add optimization for points on cardinal axis of cuboid
106
- # "project" points
107
- proj1 = [glm.dot(p, axis) for p in points1]
108
- proj2 = [glm.dot(p, axis) for p in points2]
109
- max1, min1 = max(proj1), min(proj1)
110
- max2, min2 = max(proj2), min(proj2)
111
- if max1 < min2 or max2 < min1: return False
112
-
113
- return True
114
-
115
- def resolve_broad_collisions(self) -> set[tuple[Collider, Collider]]:
116
- """
117
- Determines which colliders collide with each other from the BVH
118
- """
119
- collisions = set()
120
- for collider1 in self.colliders:
121
- if collider1.node.static: continue
122
- # traverse bvh to find aabb aabb collisions
123
- colliding = self.bvh.get_collided(collider1)
124
- for collider2 in colliding:
125
- if collider1 is collider2: continue
126
- if ((collider1, collider2) if id(collider1) < id(collider2) else (collider2, collider1)) in collisions: continue
127
-
128
- # run broad collision for specified mesh types
129
- if max(len(collider1.mesh.points), len(collider2.mesh.points)) > 250 and not self.collide_obb_obb_decision(collider1, collider2): continue # contains at least one "large" mesh TODO write heuristic algorithm for determining large meshes
130
- collisions.add((collider1, collider2) if id(collider1) < id(collider2) else (collider2, collider1))
131
-
132
- return collisions
133
-
134
- def merge_contact_points(self, vec: glm.vec3, collider1: Collider, collider2: Collider, points1: list[ContactPoint], points2: list[ContactPoint]) -> None:
135
- """
136
-
137
- """
138
- def merge_points(node: Node, existing: dict[int, glm.vec3], incoming: list[ContactPoint]) -> dict[int, glm.vec3]:
139
- incoming_indices = set()
140
-
141
- # add incoming points
142
- for point in incoming:
143
- incoming_indices.add(point.index)
144
- if point.index not in existing or glm.length2(point.vertex - existing[point.index]) > 1e-5: existing[point.index] = glm.vec3(point.vertex)
145
- # if glm.length2(point.vertex - existing[point.index]) != 0: print(point.vertex - existing[point.index])
146
-
147
- # remove changed stored points
148
- remove_indices = []
149
- for index, vertex in existing.items():
150
- if index in incoming_indices: continue
151
- if glm.length2(node.get_vertex(index) - vertex) > 1e-5: remove_indices.append(index) # check to see if point has moved
152
-
153
- # remove unused and moved points
154
- for index in remove_indices: del existing[index]
155
- return existing
156
-
157
- # check if collision is logged, if not create a new one
158
- collider_tuple = (collider1, collider2)
159
- if collider_tuple not in self.contact_manifolds or glm.length2(self.contact_manifolds[collider_tuple].normal - vec) > 1e-7: self.contact_manifolds[collider_tuple] = ContactManifold(vec, dict(), dict())
160
-
161
- # add contact point from current collision and check overlap
162
- self.contact_manifolds[collider_tuple].contact_points1 = merge_points(collider1.node, self.contact_manifolds[collider_tuple].contact_points1, points1)
163
- self.contact_manifolds[collider_tuple].contact_points2 = merge_points(collider2.node, self.contact_manifolds[collider_tuple].contact_points2, points2)
164
-
165
- def resolve_narrow_collisions(self, broad_collisions: list[tuple[Collider, Collider]]) -> None:
166
- """
167
- Determines if two colliders are colliding, if so resolves their penetration and applies impulse
168
- """
169
- for collision in broad_collisions: # assumes that broad collisions are unique
170
- collider1 = collision[0]
171
- collider2 = collision[1]
172
- node1: Node = collider1.node
173
- node2: Node = collider2.node
174
-
175
- # get peneration data or quit early if no collision is found
176
- if collider1.mesh == self.cube and collider2.mesh == self.cube: # obb-obb collision
177
-
178
- # run SAT for obb-obb (includes peneration)
179
- data = self.collide_obb_obb(collider1, collider2)
180
- if not data: continue
181
-
182
- vec, distance, index = data
183
-
184
- # TODO replace with own contact algorithm
185
- points1 = [ContactPoint(index, vertex) for index, vertex in enumerate(collider1.obb_points)]
186
- points2 = [ContactPoint(index, vertex) for index, vertex in enumerate(collider2.obb_points)]
187
-
188
- else: # use gjk to determine collisions between non-cuboid meshes
189
- has_collided, simplex = collide_gjk(node1, node2)
190
- if not has_collided: continue
191
-
192
- face, polytope = get_epa_from_gjk(node1, node2, simplex)
193
- vec, distance = face[1], face[0]
194
-
195
- # TODO replace with own contact algorithm
196
- points1 = [ContactPoint(p.index1, p.vertex1) for p in polytope]
197
- points2 = [ContactPoint(p.index2, p.vertex2) for p in polytope]
198
-
199
- if glm.dot(vec, node2.position - node1.position) > 0: vec *= -1
200
-
201
- # apply impulse if a collider has a physic body
202
- if node1.physics_body or node2.physics_body:
203
-
204
- # determine the contact points from the collision
205
- points1, points2 = separate_polytope(points1, points2, vec)
206
- self.merge_contact_points(vec, collider1, collider2, points1, points2)
207
-
208
- # for manifold in self.contact_manifolds.values(): print(list(manifold.contact_points1.values()) + list(manifold.contact_points2.values()))
209
-
210
- collider_tuple = (collider1, collider2)
211
- # print(self.contact_manifolds[collider_tuple])
212
- manifold = get_contact_manifold(
213
- node1.position - vec,
214
- vec,
215
- self.contact_manifolds[collider_tuple].contact_points1.values(),
216
- self.contact_manifolds[collider_tuple].contact_points2.values()
217
- )
218
-
219
- collision_normal = node1.velocity - node2.velocity
220
- collision_normal = vec if glm.length2(collision_normal) < 1e-12 else glm.normalize(collision_normal)
221
- calculate_collisions(collision_normal, node1, node2, manifold, node1.get_inverse_inertia(), node2.get_inverse_inertia(), node1.center_of_mass, node2.center_of_mass)
222
-
223
- # for i, point in enumerate(manifold):
224
- # self.scene.add(Node(position = point, scale = (0.1, 0.1, 0.1)))
225
-
226
- # resolve collision penetration
227
- multiplier = 0.5 if not (node1.static or node2.static) else 1
228
- if not node1.static: node1.position += multiplier * vec * distance
1
+ import glm
2
+
3
+ from .collider import Collider
4
+ from .broad.broad_bvh import BroadBVH
5
+ from .narrow.gjk import collide_gjk
6
+ from .narrow.epa import get_epa_from_gjk
7
+ from .narrow.contact_manifold import get_contact_manifold, separate_polytope
8
+ from .narrow.dataclasses import ContactPoint, ContactManifold, Collision
9
+ from ..nodes.node import Node
10
+ from ..generic.collisions import get_sat_axes
11
+ from ..physics.impulse import calculate_collisions
12
+
13
+ class ColliderHandler():
14
+ scene: ...
15
+ """Back reference to scene"""
16
+ colliders: list[Collider]
17
+ """Main list of collders contained in the scene"""
18
+ bvh: BroadBVH
19
+ """Broad bottom up BVH containing all colliders in the scene"""
20
+
21
+ def __init__(self, scene) -> None:
22
+ self.scene = scene
23
+ self.cube = self.scene.engine.cube
24
+ self.colliders = []
25
+ self.polytope_data = {}
26
+ self.contact_manifolds: dict[tuple[Collider, Collider] : ContactManifold] = {}
27
+ self.bvh = BroadBVH(self)
28
+
29
+ def add(self, collider: Collider) -> Collider:
30
+ """
31
+ Creates a collider and adds it to the collider list
32
+ """
33
+ self.colliders.append(collider)
34
+ self.bvh.add(collider)
35
+ return collider
36
+
37
+ def remove(self, collider: Collider) -> None:
38
+ """
39
+ Removes a collider from the main branch and BVH
40
+ """
41
+ if collider in self.colliders: self.colliders.remove(collider)
42
+ self.bvh.remove(collider)
43
+ collider.collider_handler = None
44
+
45
+ def resolve_collisions(self) -> None:
46
+ """
47
+ Resets collider collision values and resolves all collisions in the scene
48
+ """
49
+ # reset collision data
50
+ for collider in self.colliders: collider.collisions = []
51
+
52
+ # update BVH
53
+ for collider in self.colliders:
54
+ if collider.needs_bvh:
55
+ self.bvh.remove(collider)
56
+ self.bvh.add(collider)
57
+ collider.needs_bvh = False
58
+
59
+ # resolve collisions
60
+ broad_collisions = self.resolve_broad_collisions()
61
+ self.resolve_narrow_collisions(broad_collisions)
62
+
63
+ def collide_obb_obb(self, collider1: Collider, collider2: Collider) -> tuple[glm.vec3, float] | None:
64
+ """
65
+ Finds the minimal penetrating vector for an obb obb collision, return None if not colliding. Uses SAT.
66
+ """
67
+ axes = get_sat_axes(collider1.node.rotation, collider2.node.rotation) # axes are normaized
68
+ points1 = collider1.obb_points # TODO remove once oobb points are lazy updated, switch to just using property
69
+ points2 = collider2.obb_points
70
+
71
+ # test axes
72
+ small_axis = None
73
+ small_overlap = 1e10
74
+ small_index = 0
75
+ for i, axis in enumerate(axes): # TODO add optimization for points on cardinal axis of cuboid
76
+ # "project" points
77
+ proj1 = [glm.dot(p, axis) for p in points1]
78
+ proj2 = [glm.dot(p, axis) for p in points2]
79
+ max1, min1 = max(proj1), min(proj1)
80
+ max2, min2 = max(proj2), min(proj2)
81
+ if max1 < min2 or max2 < min1: return None
82
+
83
+ # if lines are not intersecting
84
+ if max1 > max2 and min1 < min2: overlap = min(max1 - min2, max2 - min1)
85
+ elif max2 > max1 and min2 < min1: overlap = min(max2 - min1, max1 - min2)
86
+ else: overlap = min(max1, max2) - max(min1, min2) # TODO check if works with containment
87
+
88
+ if abs(overlap) > abs(small_overlap): continue
89
+ small_overlap = overlap
90
+ small_axis = axis
91
+ small_index = i
92
+
93
+ return small_axis, small_overlap, small_index
94
+
95
+ def collide_obb_obb_decision(self, collider1: Collider, collider2: Collider) -> bool:
96
+ """
97
+ Determines if two obbs are colliding Uses SAT.
98
+ """
99
+ axes = get_sat_axes(collider1.node.rotation, collider2.node.rotation)
100
+ points1 = collider1.obb_points # TODO remove once oobb points are lazy updated, switch to just using property
101
+ points2 = collider2.obb_points
102
+
103
+ # test axes
104
+ for axis in axes: # TODO add optimization for points on cardinal axis of cuboid
105
+ # "project" points
106
+ proj1 = [glm.dot(p, axis) for p in points1]
107
+ proj2 = [glm.dot(p, axis) for p in points2]
108
+ max1, min1 = max(proj1), min(proj1)
109
+ max2, min2 = max(proj2), min(proj2)
110
+ if max1 < min2 or max2 < min1: return False
111
+
112
+ return True
113
+
114
+ def resolve_broad_collisions(self) -> set[tuple[Collider, Collider]]:
115
+ """
116
+ Determines which colliders collide with each other from the BVH
117
+ """
118
+ collisions = set()
119
+ for collider1 in self.colliders:
120
+ if collider1.node.static: continue
121
+ # traverse bvh to find aabb aabb collisions
122
+ colliding = self.bvh.get_collided(collider1)
123
+ for collider2 in colliding:
124
+ if collider1 is collider2: continue
125
+ if ((collider1, collider2) if id(collider1) < id(collider2) else (collider2, collider1)) in collisions: continue
126
+
127
+ # run broad collision for specified mesh types
128
+ if max(len(collider1.mesh.points), len(collider2.mesh.points)) > 250 and not self.collide_obb_obb_decision(collider1, collider2): continue # contains at least one "large" mesh TODO write heuristic algorithm for determining large meshes
129
+ collisions.add((collider1, collider2) if id(collider1) < id(collider2) else (collider2, collider1))
130
+
131
+ return collisions
132
+
133
+ def merge_contact_points(self, vec: glm.vec3, collider1: Collider, collider2: Collider, points1: list[ContactPoint], points2: list[ContactPoint]) -> None:
134
+ """
135
+
136
+ """
137
+ def merge_points(node: Node, existing: dict[int, glm.vec3], incoming: list[ContactPoint]) -> dict[int, glm.vec3]:
138
+ incoming_indices = set()
139
+
140
+ # add incoming points
141
+ for point in incoming:
142
+ incoming_indices.add(point.index)
143
+ if point.index not in existing or glm.length2(point.vertex - existing[point.index]) > 1e-5: existing[point.index] = glm.vec3(point.vertex)
144
+ # if glm.length2(point.vertex - existing[point.index]) != 0: print(point.vertex - existing[point.index])
145
+
146
+ # remove changed stored points
147
+ remove_indices = []
148
+ for index, vertex in existing.items():
149
+ if index in incoming_indices: continue
150
+ if glm.length2(node.collider.get_vertex(index) - vertex) > 1e-5: remove_indices.append(index) # check to see if point has moved
151
+
152
+ # remove unused and moved points
153
+ for index in remove_indices: del existing[index]
154
+ return existing
155
+
156
+ # check if collision is logged, if not create a new one
157
+ collider_tuple = (collider1, collider2)
158
+ if collider_tuple not in self.contact_manifolds or glm.length2(self.contact_manifolds[collider_tuple].normal - vec) > 1e-7: self.contact_manifolds[collider_tuple] = ContactManifold(vec, dict(), dict())
159
+
160
+ # add contact point from current collision and check overlap
161
+ self.contact_manifolds[collider_tuple].contact_points1 = merge_points(collider1.node, self.contact_manifolds[collider_tuple].contact_points1, points1)
162
+ self.contact_manifolds[collider_tuple].contact_points2 = merge_points(collider2.node, self.contact_manifolds[collider_tuple].contact_points2, points2)
163
+
164
+ def resolve_narrow_collisions(self, broad_collisions: list[tuple[Collider, Collider]]) -> None:
165
+ """
166
+ Determines if two colliders are colliding, if so resolves their penetration and applies impulse
167
+ """
168
+ for collision in broad_collisions: # assumes that broad collisions are unique
169
+ collider1 = collision[0]
170
+ collider2 = collision[1]
171
+ node1: Node = collider1.node
172
+ node2: Node = collider2.node
173
+
174
+ # get peneration data or quit early if no collision is found
175
+ if collider1.mesh == self.cube and collider2.mesh == self.cube: # obb-obb collision
176
+
177
+ # run SAT for obb-obb (includes peneration)
178
+ data = self.collide_obb_obb(collider1, collider2)
179
+ if not data: continue
180
+
181
+ vec, distance, index = data
182
+
183
+ # TODO replace with own contact algorithm
184
+ points1 = [ContactPoint(index, vertex) for index, vertex in enumerate(collider1.obb_points)]
185
+ points2 = [ContactPoint(index, vertex) for index, vertex in enumerate(collider2.obb_points)]
186
+
187
+ else: # use gjk to determine collisions between non-cuboid meshes
188
+ has_collided, simplex = collide_gjk(node1, node2)
189
+ if not has_collided: continue
190
+
191
+ face, polytope = get_epa_from_gjk(node1, node2, simplex)
192
+ vec, distance = face[1], face[0]
193
+
194
+ # TODO replace with own contact algorithm
195
+ points1 = [ContactPoint(p.index1, p.vertex1) for p in polytope]
196
+ points2 = [ContactPoint(p.index2, p.vertex2) for p in polytope]
197
+
198
+ if glm.dot(vec, node2.position - node1.position) > 0: vec *= -1
199
+
200
+ # add collision data to colliders
201
+ collider1.collisions.append(Collision(node2, vec))
202
+ collider2.collisions.append(Collision(node1, -vec))
203
+
204
+ # apply impulse if a collider has a physic body
205
+ if node1.physics_body or node2.physics_body:
206
+
207
+ # determine the contact points from the collision
208
+ points1, points2 = separate_polytope(points1, points2, vec)
209
+ self.merge_contact_points(vec, collider1, collider2, points1, points2)
210
+
211
+ collider_tuple = (collider1, collider2)
212
+ manifold = get_contact_manifold(
213
+ node1.position - vec,
214
+ vec,
215
+ self.contact_manifolds[collider_tuple].contact_points1.values(),
216
+ self.contact_manifolds[collider_tuple].contact_points2.values()
217
+ )
218
+
219
+ collision_normal = node1.velocity - node2.velocity
220
+ collision_normal = vec if glm.length2(collision_normal) < 1e-12 else glm.normalize(collision_normal)
221
+ calculate_collisions(collision_normal, node1, node2, manifold, node1.get_inverse_inertia(), node2.get_inverse_inertia(), node1.center_of_mass, node2.center_of_mass)
222
+
223
+ # resolve collision penetration
224
+ multiplier = 0.5 if not (node1.static or node2.static) else 1
225
+ if not node1.static: node1.position += multiplier * vec * distance
229
226
  if not node2.static: node2.position -= multiplier * vec * distance