changeset 276:dcfab05ed9ac

did: restructure a bit, add hit-sphere
author Sam <sam@basx.dev>
date Sat, 03 Jun 2023 13:31:38 +0700
parents 5d20689432bf
children 1fbef3a2d769
files src/semicongine/collision.nim
diffstat 1 files changed, 42 insertions(+), 44 deletions(-) [+]
line wrap: on
line diff
--- a/src/semicongine/collision.nim	Sat Jun 03 01:39:02 2023 +0700
+++ b/src/semicongine/collision.nim	Sat Jun 03 13:31:38 2023 +0700
@@ -1,24 +1,21 @@
+import std/random
+
 import ./core
 import ./scene
 
-type
-  Hitbox* = ref object of Component
-    transform*: Mat4
+const MAX_COLLISON_DETECTION_ITERATIONS = 20
 
-#[
-    dir1   
-    from core to point
-    dir_vec = point - cube3d_center
+type
+  HitBox* = ref object of Component
+    transform*: Mat4
+  HitSphere* = ref object of Component
+    radius*: float32
 
-    res1 = np.where( (np.absolute(np.dot(dir_vec, dir1)) * 2) > size1 )[0]
-    res2 = np.where( (np.absolute(np.dot(dir_vec, dir2)) * 2) > size2 )[0]
-    res3 = np.where( (np.absolute(np.dot(dir_vec, dir3)) * 2) > size3 )[0]
-]#
 
 func between(value, b1, b2: float32): bool =
   min(b1, b2) <= value and value <= max(b1, b2)
 
-func contains*(hitbox: Hitbox, x: Vec3f): bool =
+func contains*(hitbox: HitBox, x: Vec3f): bool =
   # from https://math.stackexchange.com/questions/1472049/check-if-a-point-is-inside-a-rectangular-shaped-area-3d
   let
     t = hitbox.entity.getModelTransform() * hitbox.transform
@@ -43,6 +40,9 @@
 
 # implementation of GJK, based on https://blog.winter.dev/2020/gjk-algorithm/
 
+# most generic implementation of findFurthestPoint
+# add other implementations of findFurthestPoint for other kind of geometry or optimization
+# (will be selected depening on type of the first parameter)
 func findFurthestPoint(points: openArray[Vec3f], direction: Vec3f): Vec3f =
   var maxDist = low(float32)
   for p in points:
@@ -51,7 +51,27 @@
       maxDist = dist
       result = p
 
-func supportPoint(a, b: openArray[Vec3f], direction: Vec3f): Vec3f =
+func findFurthestPoint(hitsphere: HitSphere, direction: Vec3f): Vec3f =
+  let directionNormalizedToSphere = ((direction / direction.length) * hitsphere.radius)
+  return (hitsphere.entity.getModelTransform() * directionNormalizedToSphere.toVec4(1'f32)).toVec3
+
+func findFurthestPoint(hitbox: HitBox, direction: Vec3f): Vec3f =
+  let transform = hitbox.entity.getModelTransform() * hitbox.transform
+  return findFurthestPoint(
+    [
+      (transform * newVec4f(0, 0, 0, 1)).toVec3,
+      (transform * X.toVec4(1'f32)).toVec3,
+      (transform * Y.toVec4(1'f32)).toVec3,
+      (transform * Z.toVec4(1'f32)).toVec3,
+      (transform * (X + Y).toVec4(1'f32)).toVec3,
+      (transform * (X + Z).toVec4(1'f32)).toVec3,
+      (transform * (Y + Z).toVec4(1'f32)).toVec3,
+      (transform * (X + Y + Z).toVec4(1'f32)).toVec3,
+    ],
+    direction
+  )
+
+func supportPoint[A, B](a: A, b: B, direction: Vec3f): Vec3f =
   a.findFurthestPoint(direction) - b.findFurthestPoint(-direction)
 
 func sameDirection(direction: Vec3f, ao: Vec3f): bool =
@@ -135,43 +155,21 @@
   of 4: simplex.tetrahedron(direction)
   else: raise newException(Exception, "Error in simplex")
 
-func overlaps*(a, b: openArray[Vec3f]): bool =
-  var support = supportPoint(a, b, X)
-  var simplex: seq[Vec3f]
+func overlaps*[A, B](a: A, b: B): bool =
+  var
+    support = supportPoint(a, b, newVec3f(0.8153, -0.4239, 0.5786)) # just random initial vector
+    simplex = newSeq[Vec3f]()
+    direction = -support
+    n = 0
   simplex.insert(support, 0)
-  var direction = -support;
-  while true:
+  while n < MAX_COLLISON_DETECTION_ITERATIONS:
     support = supportPoint(a, b, direction)
     if support.dot(direction) <= 0:
         return false
     simplex.insert(support, 0)
     if nextSimplex(simplex, direction):
       return true
-    # prevent a numeric instability
+    # prevent numeric instability
     if direction == newVec3f(0, 0, 0):
       direction[0] = 0.001
-
-func overlaps*(a, b: Hitbox): bool =
-  let ta = a.entity.getModelTransform() * a.transform
-  let tb = b.entity.getModelTransform() * b.transform
-  let points1 = [
-    (ta * newVec4f(0, 0, 0, 1)).toVec3,
-    (ta * X.toVec4(1'f32)).toVec3,
-    (ta * Y.toVec4(1'f32)).toVec3,
-    (ta * Z.toVec4(1'f32)).toVec3,
-    (ta * (X + Y).toVec4(1'f32)).toVec3,
-    (ta * (X + Z).toVec4(1'f32)).toVec3,
-    (ta * (Y + Z).toVec4(1'f32)).toVec3,
-    (ta * (X + Y + Z).toVec4(1'f32)).toVec3,
-  ]
-  let points2 = [
-    (tb * newVec4f(0, 0, 0, 1)).toVec3,
-    (tb * X.toVec4(1'f32)).toVec3,
-    (tb * Y.toVec4(1'f32)).toVec3,
-    (tb * Z.toVec4(1'f32)).toVec3,
-    (tb * (X + Y).toVec4(1'f32)).toVec3,
-    (tb * (X + Z).toVec4(1'f32)).toVec3,
-    (tb * (Y + Z).toVec4(1'f32)).toVec3,
-    (tb * (X + Y + Z).toVec4(1'f32)).toVec3,
-  ]
-  return overlaps(points1, points2)
+    inc n