Hi all,
I’m currently working on a physics implementation for an icosahedron shape in a project I’m developing. The physics are applied when one of the vertices collides with the ground, and it works well if a single vertex is hitting the ground.
However, I’m encountering an issue when multiple vertices hit the ground at the same time. In this scenario, the physics stops applying any forces to the object. The first initial contact is fine, but when multiple vertices are on the floor, the system doesn’t seem to know what to do and the object sinks into the floor.
I’ve been trying to troubleshoot this issue but haven’t had much luck so far. I would greatly appreciate any insights or suggestions on how to handle this situation. Has anyone encountered a similar issue before, or does anyone have any ideas on how to prevent the object from sinking when multiple vertices are in contact with the ground?
vec3 Engine::DetectCollision(Surface& object, float height)
{
for(int i = 0; i < object.vertices.size(); i++)
{
vec3 vert = object.vertices[i];
vec4 vertex = vec4(vert.x, vert.y, vert.z, 1.0f);
Matrix4 rotateX = Matrix4::RotateX(angularVelocity.x);
Matrix4 rotateY = Matrix4::RotateY(angularVelocity.y);
Matrix4 rotateZ = Matrix4::RotateZ(angularVelocity.z);
Matrix4 rotation = Matrix4::RotateX(-90.0f) * rotateX * rotateY * rotateZ;
Matrix4 translate = Matrix4::Translate(object_translation);
vertex = translate * rotation * vertex;
if(vertex.z <= height)
{
isHittingFloor = true;
return vertex.Point();
}
}
}
bool Engine::isCollidingFloor()
{
return isHittingFloor;
}
void Engine::Physics()
{
velocity = velocity + gravity * frameTime;
object_translation = object_translation + velocity * frameTime;
float height = rollingLandModel.getHeight(object_translation.x, object_translation.y);
if(isStatic)
{
object_translation.z = height + collisionRadius;
} else
{
// Calculate the position of the center of mass after transformations
center_of_mass_update = vec4(center_of_mass.x, center_of_mass.y, center_of_mass.z, 1.0f);
Matrix4 translate = Matrix4::Translate(vec3(object_translation.x, object_translation.y, object_translation.z));
center_of_mass_update = translate * center_of_mass_update;
normal = rollingLandModel.getNormal(object_translation.x, object_translation.y);
normal = normal.unit();
vec3 point = DetectCollision(dodecahedronMesh, height); // find colliding vertex with ground
if(isCollidingFloor())
{
ApplyLinearImpulse(normal, point, height, 0);
isHittingFloor = false;
}
}
}
// Applying Linear impulse and angular velocity
void Engine:ApplyLinearImpulse(const vec3& normal, vec3&vert, float height, int c)
{
float relativeVelo = velocity.dot(normal);
float e = coefficient_of_restitution;
float invMass1 = 1 / mass;
float invMass2 = 1 / groundMass;
float invMassSum = invMass1 + invMass2;
// j is the magnitude of the impulse
// j is calculated per contact, we should divide j per contact
auto j = -(1 + e) * relativeVelo / (invMassSum);
// multiply the collision normal by the magnitude of the impulse and apply
// resulting vector to the velocity of the object. this is how we apply linear impulse
vec3 impulse = normal * j;
vec3 updateVelocity = velocity + impulse * invMass1;
if(updateVelocity.length() <= 0.1)
{
velocity = vec3(0,0,0);
isStatic = true;
return;
}
velocity = velocity + impulse * invMass1;
// After applying linear impulse, we must apply friction.
// to apply friction we find a vector tangent to the collision normal
float frictionCoefficient = 0.1;
vec3 tangent = velocity - normal * velocity.dot(normal);
tangent = tangent.unit();
vec3 frictionImpulse = -tangent * frictionCoefficient * j;
velocity = velocity + frictionImpulse / mass;
vec3 radius = vert - center_of_mass_update.Point();
vec3 torque = radius.cross(impulse);
Matrix3 inertialTensor = isocahedronMesh.InertialTensor();
vec3 angularImpulse = inertialTensor.Inverse() * torque;
angularVelocity = angularVelocity + angularImpulse;
}