I have developed a collision detector that return collision data, as collision normal, collision point, interpenetration, etc.
And now I am developing a collision solver. The collision solver compute correctly the linear motion after the collision but it is not able to compute the rotation after the collision.
This is an image ilustrating the problem
To compute the velocity after collision I apply a impulse
to each body, this impulse is able to compute correctly linear motion.
Now, to compute the rotation change I need to apply the following formula
ImpulsiveTorque = RelativePoint.cross(Impulse);
RotationChange = InverseInertiaTensorWorld.transform(ImpulsiveTorque);
The problem is ImpulsiveTorque
is very small to generate a visible rotation change.
The following correspond to my sphere-sphere collision detector
sphereAndSphere : function(one, two){
var oneToTwo = one.position.sub(two.position);
var oneToTwoLength = oneToTwo.length();
if (oneToTwoLength < 0 || oneToTwoLength > one.radius + two.radius){
return -1;
}
var normal = oneToTwo.divideByScalar(oneToTwoLength);
var data = new Collision();
data.normal = normal;
data.point = one.position.add(oneToTwo.multiplyByScalar(0.5));
data.depth = one.radius+two.radius - oneToTwoLength;
data.body = [];
data.body.push(one);
data.body.push(two);
data.restitution = Math.min(one.body.restitution, two.body.restitution);
return data;
},
RelativePoint
is the collision point relative to center of mass of each body in collision. It is computed as follow
this.relativePoint[0]=this.point.sub(this.body[0].position);
if (this.body[1] !== undefined){
this.relativePoint[1]=this.point.sub(this.body[1].position);
}
The impulse
should be applied in the normal direction.
If I am correct RelativePoint
vector has the same direction that normal collision vector. So, the impulse has the same direction that RelativePoint
so the cross product will return a very small result. As a result I can't get a visible rotation change.
I think calculations is ok, but it lead to no rotation between sphere-sphere collision and in the real world if sphere-sphere collide I can see a variation in rotation, so I think that I am forgetting something.
Can you give me some tip why I don't get a visible change in rotation?
P.D If you need more information please tell me.
Edit: This is the way how I compute the Impulse
vector.
First I need to know how change the velocity for each unit of impulse. At this point I compute this quantity in the collision normal (For collision solver I work in collision coordinates). For that reason I use the dot product between normal and ChangeVelPerUnit
var changeVelPerUnit = RelativePoint[0].cross(normal);
changeVelPerUnit = body1.inverseInertiaTensorWorld.transform(changeVelPerUnit);
changeVelPerUnit = changeVelPerUnit.cross(RelativePoint[0]);
changeVelPerUnit = changeVelPerUnit.dot(normal);
changeVelPerUnit += body1.inverseMass;
Then I need to know the current closing velocity (or separating velocity) with the formula v = v' + (rotation x RelativePoint)
var sepVelocity = body1.rotation.cross(RelativePoint[0]);
sepVelocity = sepVelocity.add(body1.velocity);
This velocity is computed in world coordinates so I need to change it to Collision coordinates
var collisionVelocity = transform.getTranspose().transform(sepVelocity);
With this, now I compute the change in velocity that should be given to the body, taking into account the restitution coefficient. I use the x coordinates because I use the normal as X axis for matrix to change from collision coordinates to world coordinates and viceversa.
var changeInVel = -collisionVelocity.x * (1 + this.restitution);
and finally I compute the impulse in collision coordinates and then pass it to world coordinates
var impulseCollision = new ALMath.Vector3(changeInVel/changeVelPerUnit,0,0)
var impulse = transform.transform(impulseCollision);
P.S the impulse computation is doing only for one body, it should be necessary to do calculations for second body, but for simplicity I omitted it.
Impulse
) passed to that cross product should be in the direction of the relative velocities of the objects. How do you calculateImpulse
? \$\endgroup\$impulse
vector \$\endgroup\$var changeVelPerUnit = RelativePoint[0].cross(normal);
would always result in 0. As you note in your original post, the relative point and the normal are parallel and therefore should give a cross product of 0. \$\endgroup\$