Browse Source

Add body rays

Miloslav Ciz 3 years ago
parent
commit
275a25a62b
1 changed files with 78 additions and 13 deletions
  1. 78 13
      tinyphysicsengine.h

+ 78 - 13
tinyphysicsengine.h

@@ -312,10 +312,10 @@ void TPE_bodyGetAABB(const TPE_Body *body, TPE_Vec3 *vMin, TPE_Vec3 *vMax);
 
 /** Gets a bounding sphere of a body which is not minimal but faster to compute
   than the minimal bounding sphere. */
-void TPE_bodyGetFastBBSphere(const TPE_Body *body, TPE_Vec3 *center,
+void TPE_bodyGetFastBSphere(const TPE_Body *body, TPE_Vec3 *center,
   TPE_Unit *radius);
 
-void TPE_bodyGetBBSphere(const TPE_Body *body, TPE_Vec3 *center,
+void TPE_bodyGetBSphere(const TPE_Body *body, TPE_Vec3 *center,
   TPE_Unit *radius);
 
 uint8_t TPE_checkOverlapAABB(TPE_Vec3 v1Min, TPE_Vec3 v1Max, TPE_Vec3 v2Min,
@@ -373,12 +373,13 @@ TPE_Vec3 TPE_castEnvironmentRay(TPE_Vec3 rayPos, TPE_Vec3 rayDir,
 
 /** Casts a ray against bodies in a world (ignoring the environment), returns
   the position of the closest hit as well as the hit body's index in bodyIndex
-  (unless the bodyIndex pointer is 0 in which case it is ignored). If no hit is
-  found a vector with all elements equal to TPE_INFINITY will be returned and
-  bodyIndex will be -1. A specific body can be excluded with excludeBody
-  (negative value will just make this parameter ignored). */
+  (unless the bodyIndex pointer is 0 in which case it is ignored). Similarly
+  with jointIndex. If no hit is found a vector with all elements equal to
+  TPE_INFINITY will be returned and bodyIndex will be -1. A specific body can be
+  excluded with excludeBody (negative value will just make this parameter
+  ignored). */
 TPE_Vec3 TPE_castBodyRay(TPE_Vec3 rayPos, TPE_Vec3 rayDir, int16_t excludeBody,
-  const TPE_World *world, int16_t *bodyIndex);
+  const TPE_World *world, uint16_t *bodyIndex, uint16_t *jointIndex);
 
 // environment building functions:
 
@@ -1552,7 +1553,7 @@ uint8_t TPE_bodyEnvironmentCollide(const TPE_Body *body,
  
 }
 
-void TPE_bodyGetFastBBSphere(const TPE_Body *body, TPE_Vec3 *center,
+void TPE_bodyGetFastBSphere(const TPE_Body *body, TPE_Vec3 *center,
   TPE_Unit *radius)
 {
   TPE_Vec3 b;
@@ -1566,7 +1567,7 @@ void TPE_bodyGetFastBBSphere(const TPE_Body *body, TPE_Vec3 *center,
   *radius = TPE_DISTANCE(*center,b);
 }
 
-void TPE_bodyGetBBSphere(const TPE_Body *body, TPE_Vec3 *center,
+void TPE_bodyGetBSphere(const TPE_Body *body, TPE_Vec3 *center,
   TPE_Unit *radius)
 {
   *radius = TPE_INFINITY;
@@ -1597,7 +1598,7 @@ void TPE_bodyGetBBSphere(const TPE_Body *body, TPE_Vec3 *center,
     TPE_Unit distSquared = 
       diff.x * diff.x + diff.y * diff.y + diff.z * diff.z;
 
-    if (distSquared < *radius);
+    if (distSquared < *radius)
       *radius = distSquared;
 
     j++;
@@ -1612,7 +1613,7 @@ uint8_t TPE_bodyEnvironmentResolveCollision(TPE_Body *body,
   TPE_Vec3 c;
   TPE_Unit d;
 
-  TPE_bodyGetFastBBSphere(body,&c,&d);
+  TPE_bodyGetFastBSphere(body,&c,&d);
 
   if (TPE_DISTANCE(c,env(c,d)) > d)
     return 0;
@@ -2324,19 +2325,83 @@ TPE_Vec3 TPE_castEnvironmentRay(TPE_Vec3 rayPos, TPE_Vec3 rayDir,
 }
 
 TPE_Vec3 TPE_castBodyRay(TPE_Vec3 rayPos, TPE_Vec3 rayDir, int16_t excludeBody,
-  const TPE_World *world, int16_t *bodyIndex)
+  const TPE_World *world, uint16_t *bodyIndex, uint16_t *jointIndex)
 {
   TPE_Vec3 bestP = TPE_vec3(TPE_INFINITY,TPE_INFINITY,TPE_INFINITY);
   TPE_Unit bestD = TPE_INFINITY;
 
-  if (*bodyIndex != 0)
+  if (bodyIndex != 0)
     *bodyIndex = -1;
 
+  if (jointIndex != 0)
+    *jointIndex = -1;
+
+  TPE_vec3Normalize(&rayDir);
+
   for (uint16_t i = 0; i < world->bodyCount; ++i)
   {
+    TPE_Vec3 c, p;
+    TPE_Unit r, d;
+
+    TPE_bodyGetFastBSphere(&world->bodies[i],&c,&r);
+
+    c = TPE_vec3Minus(c,rayPos);
+    p = TPE_vec3ProjectNormalized(c,rayDir);
+
+    if (TPE_vec3Dot(p,rayDir) >= 0) // point is in ray's forward dir?
+    {
+      d = TPE_DISTANCE(p,c);
+
+      if (d <= r)
+      {
+        // bounding sphere hit, now check all joints:
+
+        const TPE_Joint *joint = world->bodies[i].joints;
 
+        for (uint16_t j = 0; j < world->bodies[i].jointCount; ++j)
+        {
+          c = joint->position;
+          c = TPE_vec3Minus(c,rayPos);
+          p = TPE_vec3ProjectNormalized(c,rayDir);
 
+          if (TPE_vec3Dot(p,rayDir) >= 0)
+          {
+            d = TPE_DISTANCE(p,c);
+            TPE_Unit js = TPE_JOINT_SIZE(*joint);
+
+            if (d <= js)
+            {
+              // joint hit, compute exact coordinates:
+
+              c = TPE_vec3Times(rayDir,TPE_sqrt(js * js - d * d));
+              // ^ offset vector to two intersections
+              p = TPE_vec3Plus(p,rayPos);
+
+              TPE_Vec3
+                i1 = TPE_vec3Plus(p,c), // intersection points
+                i2 = TPE_vec3Minus(p,c);
+
+              d = TPE_DISTANCE(rayPos,i1);
+              TPE_Unit d2 = TPE_DISTANCE(rayPos,i2);
+
+              if (d2 < d) // take the closer one
+              {
+                d = d2;
+                i1 = i2;
+              }
+
+              if (d < bestD)
+              {
+                bestD = d;
+                bestP = i1;
+              }
+            }
+          }
 
+          joint++;
+        }
+      }
+    }
   }
 
   return bestP;