Quellcode durchsuchen

Continue collision resolving

Miloslav Číž vor 4 Jahren
Ursprung
Commit
38d49af7d7
2 geänderte Dateien mit 74 neuen und 80 gelöschten Zeilen
  1. 5 3
      test_sdl.c
  2. 69 77
      tinyphysicsengine.h

+ 5 - 3
test_sdl.c

@@ -201,8 +201,10 @@ int main()
   sphere1.shapeParams[0] = 512; 
   sphere1.shapeParams[0] = 512; 
   sphere1.position.x = -700;
   sphere1.position.x = -700;
 
 
-sphere1.position.y = 200;
+sphere1.position.y = 400;
+/*
 sphere1.position.z = 300;
 sphere1.position.z = 300;
+*/
 
 
   sphere2.shape = TPE_SHAPE_SPHERE;
   sphere2.shape = TPE_SHAPE_SPHERE;
   sphere2.shapeParams[0] = 512; 
   sphere2.shapeParams[0] = 512; 
@@ -210,8 +212,8 @@ sphere1.position.z = 300;
 
 
   TPE_Unit frame = 0;
   TPE_Unit frame = 0;
 
 
-sphere1.velocity.x = 32;
-sphere2.velocity.x = -16;
+sphere1.velocity.x = 1;
+sphere2.velocity.x = 0;
 
 
   while (running)
   while (running)
   {
   {

+ 69 - 77
tinyphysicsengine.h

@@ -13,7 +13,8 @@
   particularly in the area of rotation: there is no moment of inertia for
   particularly in the area of rotation: there is no moment of inertia for
   objects, i.e. every object rotates as if it was a ball, and the object can be
   objects, i.e. every object rotates as if it was a ball, and the object can be
   rotating around at most one axis at a time, i.e. it is not possible to
   rotating around at most one axis at a time, i.e. it is not possible to
-  simulate e.g. the Dzhanibekov effect.
+  simulate e.g. the Dzhanibekov effect. Therefore the library is mostly intended
+  for entertainment software.
 
 
   CONVENTIONS:
   CONVENTIONS:
 
 
@@ -35,6 +36,8 @@
     TPE_FRACTIONS_PER_UNIT parts (instead of 2 * PI or degrees).
     TPE_FRACTIONS_PER_UNIT parts (instead of 2 * PI or degrees).
 
 
   - Quaternions are represented as vec4 where x ~ i, y ~ j, z ~ k, w ~ real.
   - Quaternions are represented as vec4 where x ~ i, y ~ j, z ~ k, w ~ real.
+
+  - There is no vec3 type, vec4 is usead for all vectors, for simplicity.
 */
 */
 
 
 #include <stdint.h>
 #include <stdint.h>
@@ -68,6 +71,7 @@ typedef int32_t TPE_Unit;
 
 
 TPE_Unit TPE_wrap(TPE_Unit value, TPE_Unit mod);
 TPE_Unit TPE_wrap(TPE_Unit value, TPE_Unit mod);
 TPE_Unit TPE_clamp(TPE_Unit v, TPE_Unit v1, TPE_Unit v2);
 TPE_Unit TPE_clamp(TPE_Unit v, TPE_Unit v1, TPE_Unit v2);
+static inline TPE_Unit TPE_abs(TPE_Unit x);
 static inline TPE_Unit TPE_nonZero(TPE_Unit x);
 static inline TPE_Unit TPE_nonZero(TPE_Unit x);
 
 
 /** Returns an integer square root of given value. */
 /** Returns an integer square root of given value. */
@@ -93,9 +97,6 @@ typedef struct
 
 
 /** Initializes vec4 to a zero vector. */
 /** Initializes vec4 to a zero vector. */
 void TPE_initVec4(TPE_Vec4 *v);
 void TPE_initVec4(TPE_Vec4 *v);
-
-TPE_Vec4 TPE_vec4(TPE_Unit x, TPE_Unit y, TPE_Unit z, TPE_Unit w);
-
 void TPE_vec4Set(TPE_Vec4 *v, TPE_Unit x, TPE_Unit y, TPE_Unit z, TPE_Unit w);
 void TPE_vec4Set(TPE_Vec4 *v, TPE_Unit x, TPE_Unit y, TPE_Unit z, TPE_Unit w);
 void TPE_vec3Add(TPE_Vec4 a, TPE_Vec4 b, TPE_Vec4 *result);
 void TPE_vec3Add(TPE_Vec4 a, TPE_Vec4 b, TPE_Vec4 *result);
 void TPE_vec4Add(TPE_Vec4 a, TPE_Vec4 b, TPE_Vec4 *result);
 void TPE_vec4Add(TPE_Vec4 a, TPE_Vec4 b, TPE_Vec4 *result);
@@ -104,14 +105,17 @@ void TPE_vec3Average(TPE_Vec4 a, TPE_Vec4 b, TPE_Vec4 *result);
 void TPE_vec4Substract(TPE_Vec4 a, TPE_Vec4 b, TPE_Vec4 *result);
 void TPE_vec4Substract(TPE_Vec4 a, TPE_Vec4 b, TPE_Vec4 *result);
 void TPE_vec3Multiply(TPE_Vec4 v, TPE_Unit f, TPE_Vec4 *result);
 void TPE_vec3Multiply(TPE_Vec4 v, TPE_Unit f, TPE_Vec4 *result);
 void TPE_vec4Multiply(TPE_Vec4 v, TPE_Unit f, TPE_Vec4 *result);
 void TPE_vec4Multiply(TPE_Vec4 v, TPE_Unit f, TPE_Vec4 *result);
-TPE_Unit TPE_vec3Len(TPE_Vec4 v);
-TPE_Unit TPE_vec4Len(TPE_Vec4 v);
-TPE_Unit TPE_vec3DotProduct(TPE_Vec4 v1, TPE_Vec4 v2);
 void TPE_vec3CrossProduct(TPE_Vec4 a, TPE_Vec4 b, TPE_Vec4 *result);
 void TPE_vec3CrossProduct(TPE_Vec4 a, TPE_Vec4 b, TPE_Vec4 *result);
 void TPE_vec3Normalize(TPE_Vec4 *v);
 void TPE_vec3Normalize(TPE_Vec4 *v);
 void TPE_vec4Normalize(TPE_Vec4 *v);
 void TPE_vec4Normalize(TPE_Vec4 *v);
 void TPE_vec3Project(TPE_Vec4 v, TPE_Vec4 base, TPE_Vec4 *result);
 void TPE_vec3Project(TPE_Vec4 v, TPE_Vec4 base, TPE_Vec4 *result);
 
 
+TPE_Unit TPE_vec3Len(TPE_Vec4 v);
+TPE_Unit TPE_vec3LenTaxicab(TPE_Vec4 v);
+TPE_Unit TPE_vec4Len(TPE_Vec4 v);
+TPE_Unit TPE_vec3DotProduct(TPE_Vec4 v1, TPE_Vec4 v2);
+
+TPE_Vec4 TPE_vec4(TPE_Unit x, TPE_Unit y, TPE_Unit z, TPE_Unit w);
 TPE_Vec4 TPE_vec3Plus(TPE_Vec4 a, TPE_Vec4 b);
 TPE_Vec4 TPE_vec3Plus(TPE_Vec4 a, TPE_Vec4 b);
 TPE_Vec4 TPE_vec3Minus(TPE_Vec4 a, TPE_Vec4 b);
 TPE_Vec4 TPE_vec3Minus(TPE_Vec4 a, TPE_Vec4 b);
 TPE_Vec4 TPE_vec3Times(TPE_Vec4 a, TPE_Unit f);
 TPE_Vec4 TPE_vec3Times(TPE_Vec4 a, TPE_Unit f);
@@ -122,13 +126,14 @@ TPE_Vec4 TPE_vec3Cross(TPE_Vec4 a, TPE_Vec4 b);
   the center of rotation. */
   the center of rotation. */
 TPE_Unit TPE_linearVelocityToAngular(TPE_Unit velocity, TPE_Unit distance);
 TPE_Unit TPE_linearVelocityToAngular(TPE_Unit velocity, TPE_Unit distance);
 
 
+/** Performs the opposite conversion of TPE_linearVelocityToAngular. */
 TPE_Unit TPE_angularVelocityToLinear(TPE_Unit velocity, TPE_Unit distance);
 TPE_Unit TPE_angularVelocityToLinear(TPE_Unit velocity, TPE_Unit distance);
 
 
 /** Holds a rotation state around a single axis, in a way that prevents rounding
 /** Holds a rotation state around a single axis, in a way that prevents rounding
   errors from distorting the rotation over time. In theory rotation of a body
   errors from distorting the rotation over time. In theory rotation of a body
   could be represented as 
   could be represented as 
 
 
-  [current orientation, axis of rotation,angular velocity]
+  [current orientation, axis of rotation, angular velocity]
 
 
   However applying the rotation and normalizing the orientation quaternion each
   However applying the rotation and normalizing the orientation quaternion each
   simulation step leads to error cumulation and the rotation gets aligned with
   simulation step leads to error cumulation and the rotation gets aligned with
@@ -177,20 +182,29 @@ typedef struct
                                  inferred */
                                  inferred */
 } TPE_Body;
 } TPE_Body;
 
 
-/** Initializes a physical body, this should be called on all TPE_Bodys that
-  are created.*/
+/** Initializes a physical body, this should be called on all TPE_Body objects
+  that are created.*/
 void TPE_bodyInit(TPE_Body *body);
 void TPE_bodyInit(TPE_Body *body);
 
 
 /** Computes a 4x4 transform matrix of given body. The matrix has the same
 /** Computes a 4x4 transform matrix of given body. The matrix has the same
   format as S3L_Mat4 from small3dlib. */
   format as S3L_Mat4 from small3dlib. */
 void TPE_bodyGetTransformMatrix(const TPE_Body *body, TPE_Unit matrix[4][4]);
 void TPE_bodyGetTransformMatrix(const TPE_Body *body, TPE_Unit matrix[4][4]);
 
 
+/** Gets the current orientation of a body as a quaternion. */
 void TPE_bodyGetOrientation(const TPE_Body *body, TPE_Vec4 *quaternion);
 void TPE_bodyGetOrientation(const TPE_Body *body, TPE_Vec4 *quaternion);
 
 
+/** Updates the body position and rotation according to its current velocity
+  and rotation state. */
 void TPE_bodyStep(TPE_Body *body);
 void TPE_bodyStep(TPE_Body *body);
 
 
+/** Sets the rotation state of a body as an axis of rotation and angular
+  velocity around this axis. */
 void TPE_bodySetRotation(TPE_Body *body, TPE_Vec4 axis, TPE_Unit velocity);
 void TPE_bodySetRotation(TPE_Body *body, TPE_Vec4 axis, TPE_Unit velocity);
 
 
+/** Adds a rotation to the current rotation of a body. This addition is perfomed
+  as a vector addition of the current and new rotation represented as vectors
+  whose direction is the rotation axis and magnitude is the angular velocity 
+  around that axis. */
 void TPE_bodyAddRotation(TPE_Body *body, TPE_Vec4 axis, TPE_Unit velocity);
 void TPE_bodyAddRotation(TPE_Body *body, TPE_Vec4 axis, TPE_Unit velocity);
 
 
 /** Applies a velocity change to a body at a specific point (relative to the
 /** Applies a velocity change to a body at a specific point (relative to the
@@ -497,14 +511,18 @@ TPE_Vec4 TPE_vec3Cross(TPE_Vec4 a, TPE_Vec4 b)
 void TPE_bodyApplyVelocity(TPE_Body *body, TPE_Vec4 point, TPE_Vec4 velocity)
 void TPE_bodyApplyVelocity(TPE_Body *body, TPE_Vec4 point, TPE_Vec4 velocity)
 {  
 {  
   TPE_Vec4 angularVelocity, rotationAxis;
   TPE_Vec4 angularVelocity, rotationAxis;
+
+TPE_PRINTF_VEC4(point);
+TPE_PRINTF_VEC4(velocity);
+printf("\n");
+TPE_PRINTF_VEC4(body->velocity);
   
   
   TPE_vec3Add(body->velocity,velocity,&(body->velocity));
   TPE_vec3Add(body->velocity,velocity,&(body->velocity));
 
 
   TPE_Unit pointDistance = TPE_vec3Len(point);
   TPE_Unit pointDistance = TPE_vec3Len(point);
 
 
-TPE_PRINTF_VEC4(point);
-TPE_PRINTF_VEC4(velocity);
-printf("\n");
+TPE_PRINTF_VEC4(body->velocity);
+printf("\n---\n");
 
 
   if (pointDistance != 0)  
   if (pointDistance != 0)  
   {
   {
@@ -626,6 +644,31 @@ void TPE_resolveCollision(TPE_Body *body1 ,TPE_Body *body2,
   if (!v1Sign && v2Sign)
   if (!v1Sign && v2Sign)
     return; // opposite going velocities => not a real collision
     return; // opposite going velocities => not a real collision
 
 
+  /* if the velocities are too small, weird behavior occurs, so we define a min
+    velocity for collisions and potentially modify the velocities: */
+
+  // TODO: something more elegant?
+
+  #define MIN_V 5
+
+  if (v1.x != 0 || v1.y != 0 || v1.z != 0)
+    while (TPE_vec3LenTaxicab(v1) < MIN_V)
+    {
+      v1.x *= 2;
+      v1.y *= 2;
+      v1.z *= 2;
+    } 
+
+  if (v2.x != 0 || v2.y != 0 || v2.z != 0)
+    while (TPE_vec3LenTaxicab(v1) < MIN_V)
+    {
+      v2.x *= 2;
+      v2.y *= 2;
+      v2.z *= 2;
+    } 
+
+  #undef MIN_V 
+  
   TPE_vec3Project(v1,collisionNormal,&v1);
   TPE_vec3Project(v1,collisionNormal,&v1);
   TPE_vec3Project(v2,collisionNormal,&v2);
   TPE_vec3Project(v2,collisionNormal,&v2);
 
 
@@ -653,6 +696,9 @@ void TPE_resolveCollision(TPE_Body *body1 ,TPE_Body *body2,
   
   
   TPE_bodyApplyVelocity(body2,p2,
   TPE_bodyApplyVelocity(body2,p2,
     TPE_vec3Times(collisionNormal,v2ScalarNew - v2Scalar));
     TPE_vec3Times(collisionNormal,v2ScalarNew - v2Scalar));
+
+printf("=====\n");
+
 }
 }
 
 
 TPE_Unit TPE_linearVelocityToAngular(TPE_Unit velocity, TPE_Unit distance)
 TPE_Unit TPE_linearVelocityToAngular(TPE_Unit velocity, TPE_Unit distance)
@@ -946,6 +992,11 @@ void TPE_vec4Multiply(const TPE_Vec4 v, TPE_Unit f, TPE_Vec4 *result)
   result->w = (v.w * f) / TPE_FRACTIONS_PER_UNIT;
   result->w = (v.w * f) / TPE_FRACTIONS_PER_UNIT;
 }
 }
 
 
+TPE_Unit TPE_abs(TPE_Unit x)
+{
+  return (x >= 0) ? x : (-1 * x);
+}
+
 TPE_Unit TPE_vec3Len(TPE_Vec4 v)
 TPE_Unit TPE_vec3Len(TPE_Vec4 v)
 {
 {
   return TPE_sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
   return TPE_sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
@@ -956,6 +1007,11 @@ TPE_Unit TPE_vec4Len(TPE_Vec4 v)
   return TPE_sqrt(v.x * v.x + v.y * v.y + v.z * v.z + v.w * v.w);
   return TPE_sqrt(v.x * v.x + v.y * v.y + v.z * v.z + v.w * v.w);
 }
 }
 
 
+TPE_Unit TPE_vec3LenTaxicab(TPE_Vec4 v)
+{
+  return TPE_abs(v.x) + TPE_abs(v.y) + TPE_abs(v.z);
+}
+
 TPE_Unit TPE_vec3DotProduct(const TPE_Vec4 v1, const TPE_Vec4 v2)
 TPE_Unit TPE_vec3DotProduct(const TPE_Vec4 v1, const TPE_Vec4 v2)
 {
 {
   return
   return
@@ -1048,70 +1104,6 @@ void TPE_getVelocitiesAfterCollision(
   #undef ANTI_OVERFLOW_SCALE
   #undef ANTI_OVERFLOW_SCALE
 }
 }
 
 
-void TPE_resolvePointCollision(
-  TPE_Vec4 collisionPoint,
-  TPE_Vec4 collisionNormal,
-  TPE_Unit elasticity,
-  TPE_Vec4 linVelocity1,
-  TPE_Vec4 rotVelocity1,
-  TPE_Unit m1,
-  TPE_Vec4 linVelocity2,
-  TPE_Vec4 rotVelocity2,
-  TPE_Unit m2)
-{
-  TPE_Vec4 v1, v2, v1New, v2New;
-
-  TPE_initVec4(&v1);
-  TPE_initVec4(&v2);
-  TPE_initVec4(&v1New);
-  TPE_initVec4(&v2New);
-
-  // add lin. and rot. velocities to get the overall vel. of both points:
-
-  TPE_vec4Add(linVelocity1,rotVelocity1,&v1);
-  TPE_vec4Add(linVelocity2,rotVelocity2,&v2);
-
-  /* project both of these velocities to the collision normal as we'll apply
-     the collision equation only in the direction of this normal: */
-
-  TPE_vec3Project(v1,collisionNormal,&v1New);
-  TPE_vec3Project(v2,collisionNormal,&v2New);
-
-  // get the velocities of the components
-
-  TPE_Unit
-    v1NewMag = TPE_vec3Len(v1New),
-    v2NewMag = TPE_vec3Len(v2New);
-
-  /* now also substract this component from the original velocity (so that it
-     will now be in the collision plane), we'll later add back the updated
-     velocity to it */
-
-  TPE_vec4Substract(v1,v1New,&v1); 
-  TPE_vec4Substract(v2,v2New,&v2); 
-
-  // apply the 1D collision equation to velocities along the normal:
-
-  TPE_getVelocitiesAfterCollision(
-    &v1NewMag,
-    &v2NewMag,
-    m1,
-    m2,
-    elasticity);
-
-  // add back the updated velocities to get the new overall velocities:
-
-  v1New.x += (collisionNormal.x * v1NewMag) / TPE_FRACTIONS_PER_UNIT;
-  v1New.y += (collisionNormal.y * v1NewMag) / TPE_FRACTIONS_PER_UNIT;
-  v1New.z += (collisionNormal.z * v1NewMag) / TPE_FRACTIONS_PER_UNIT;
- 
-  v2New.x += (collisionNormal.x * v2NewMag) / TPE_FRACTIONS_PER_UNIT;
-  v2New.y += (collisionNormal.y * v2NewMag) / TPE_FRACTIONS_PER_UNIT;
-  v2New.z += (collisionNormal.z * v2NewMag) / TPE_FRACTIONS_PER_UNIT;
-
-// TODO
-}
-
 void TPE_bodyGetTransformMatrix(const TPE_Body *body, TPE_Unit matrix[4][4])
 void TPE_bodyGetTransformMatrix(const TPE_Body *body, TPE_Unit matrix[4][4])
 {
 {
   TPE_Vec4 orientation;
   TPE_Vec4 orientation;