• Advertisement
Sign in to follow this  

Shouldn't the spheres rotate?

This topic is 2682 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I've got a 3D sphere-sphere collision physics setup. One sphere, coming from the left hits the other; it then bounces off and imparts some momentum to the other sphere. This is all as expected.

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.

Share this post


Link to post
Share on other sites
Advertisement
You need some friction in order to get rotations for spheres.


Probably unrelated, but this:

if (inverseMass <= 0.0000001F)
inverseMass = 1.0F;

looks suspicious.

Share this post


Link to post
Share on other sites
Quote:
Original post by SriLumpa
You need some friction in order to get rotations for spheres.


Probably unrelated, but this:

if (inverseMass <= 0.0000001F)
inverseMass = 1.0F;

looks suspicious.

Thanks.


It's only used for calculating the base j-value.

float bounce = 1.0F;
float j = -(1.0F + bounce) * impactVelocityDotNormal / inverseMass;

The actual collision vector is multiplied by the respective inverse mass of the objects.

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));

It is double-take worthy.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement