Except - The collision produces no rotation. The point of collision looks like this:
So...One apparent problem. With an offset like that, I'd think they'd start rotating. However, with the normal calculation I keep seeing on the internet ("Vector3 collisionNormal = Vector3.Normalize(collisionPoint - collisionPositionA);"), they don't rotate. I've tried the following fix, but I'm not sure how correct it is: "Vector3 collisionNormal = Vector3.Normalize(relativeVelocity + (collisionPoint - collisionPositionA))". This is because, when the force offset of "collisionPoint - collisionPositionA" is crossed with that collisionNormal, it naturally results in a (0, 0, 0) vector.
So - Shouldn't they rotate? And, if so, what am I doing wrong? Or am I missing something?
Sphere-Sphere intersection:
internal static bool Intersection( float radiusA, Vector3 previousPositionA, Vector3 currentPositionA, float radiusB, Vector3 previousPositionB, Vector3 currentPositionB, out CollisionData collisionData, float maxTime ) { Vector3 velocityA = currentPositionA - previousPositionA; Vector3 velocityB = currentPositionB - previousPositionB; Vector3 lastToLast = previousPositionB - previousPositionA; // Vector3 lastToLast = currentPositionB - currentPositionA; Vector3 relativeVelocity = velocityB - velocityA; float totalRadius = radiusA + radiusB; float a = Vector3.Dot(relativeVelocity, relativeVelocity); float b = 2 * Vector3.Dot(relativeVelocity, lastToLast); float ca = Vector3.Dot(lastToLast, lastToLast); float cb = totalRadius * totalRadius; if (ca <= cb) { float t1 = 0, t2 = 0; collisionData = GenerateCollisonData( radiusA, ref previousPositionA, radiusB, ref previousPositionB, ref velocityA, ref velocityB, ref relativeVelocity, t1, t2 ); return true; } { float c = ca - cb; float t1, t2; if (SGLMath.Quadratic(a, b, c, out t1, out t2)) { if (t1 > t2) Main.Swap<float>(ref t1, ref t2); if (t1 > maxTime || t1 < 0) { collisionData = new CollisionData(false); return false; } collisionData = GenerateCollisonData( radiusA, ref previousPositionA, radiusB, ref previousPositionB, ref velocityA, ref velocityB, ref relativeVelocity, t1, t2 ); return true; } } collisionData = new CollisionData(false); return false; }
Collision data generation:
private static CollisionData GenerateCollisonData( float radiusA, ref Vector3 previousPositionA, float radiusB, ref Vector3 previousPositionB, ref Vector3 velocityA, ref Vector3 velocityB, ref Vector3 relativeVelocity, float t1, float t2 ) { CollisionData collisionData; Vector3 collisionPositionA = previousPositionA + (velocityA * t1); Vector3 collisionPositionB = previousPositionB + (velocityB * t1); Vector3 collisionPoint = Vector3.Lerp(collisionPositionA, collisionPositionB, radiusA / (radiusA + radiusB)); Vector3 collisionNormal = Vector3.Normalize(collisionPoint - collisionPositionA); // Vector3 collisionNormal = Vector3.Normalize(Vector3.Lerp(relativeVelocity, collisionPoint - collisionPositionA, 0.5F)); // Vector3 collisionNormal = Vector3.Normalize(relativeVelocity + (collisionPoint - collisionPositionA)); // Vector3 collisionNormal = Vector3.Normalize(collisionPositionB - collisionPoint); collisionData = new CollisionData( true, t1, t2, collisionPositionA, collisionPositionB, collisionPoint, collisionNormal ); return collisionData; }
Collision handling:
internal static void HandleCollision(RigidBody rigidBodyOne, RigidBody rigidBodyTwo, CollisionData collisionData) { float inverseMass = rigidBodyOne.physic.InverseMass + rigidBodyTwo.physic.InverseMass; if (inverseMass <= 0.0000001F) inverseMass = 1.0F; Vector3 impactVelocity = rigidBodyOne.physic.Velocity - rigidBodyTwo.physic.Velocity; float impactVelocityDotNormal = Vector3.Dot(impactVelocity, collisionData.Normal); if (impactVelocityDotNormal < 0F) return; float bounce = 1.0F; float j = -(1.0F + bounce) * impactVelocityDotNormal / inverseMass; rigidBodyOne.physic.ApplyForce( new Force(collisionData.Normal * (j * rigidBodyOne.physic.InverseMass), collisionData.Point - collisionData.PositionA)); rigidBodyTwo.physic.ApplyForce( new Force(-collisionData.Normal * (j * rigidBodyOne.physic.InverseMass), collisionData.Point - collisionData.PositionB)); }
ApplyForce function:
public void ApplyForce(Force force) { velocity += force.Vector * InverseMass; Vector3 crossVector = Vector3.Cross(force.Vector, force.Offset); crossVector = new Vector3(crossVector.X * InverseInertia.X, crossVector.Y * InverseInertia.Y, crossVector.Z * InverseInertia.Z); angularVelocity += crossVector; }
Thanks.