# HG changeset patch # User Sam # Date 1685773898 -25200 # Node ID 519bc4861b3844f894a6d5655ef3f49fe42c9eb6 # Parent b58bb7381350b776be1e32dd89dce2ae829a052a did: restructure a bit, add hit-sphere diff -r b58bb7381350 -r 519bc4861b38 src/semicongine/collision.nim --- 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