Sunday, February 23, 2025
spot_img

c++ – Collision response with exterior forces & small relative velocities


How do I take care of collisions which have small relative velocities, however exterior forces reminiscent of gravity?

Think about a situation with a field in 2D, rotated 30 levels, and positioned on the bottom.

enter image description here

Gravity acts on the field, transferring it down into the bottom, and inflicting a collision.
The collision is resolved utilizing an impulse based mostly collision decision mannequin, however as a result of the relative velocity of the field on the level of collision is near 0, the impulse could be very small.

This appears to trigger the field to take a seat on its edge for an unnaturally lengthy interval, till it lastly builds up sufficient angular velocity to fall again onto its aspect.

It appears like my collision decision mannequin is lacking a part that may account for the impact of exterior forces like gravity on a collision that takes place with low relative velocity. Is there an accurate solution to account for this?

Sharing some code beneath in case there’s a bug:

float Simulator::calculateCollisionImpulse(const CollisionDetails &collision, const glm::vec2 &regular,
                                     const glm::vec2 &relative_velocity,
                                     const glm::vec2 &relative_a, const glm::vec2 &relative_b,
                                     float total_mass) {
    BodyId id_a = collision.bodyA();
    BodyId id_b = collision.bodyB();
    RigidBody& body_a = m_bodies[id_a];
    RigidBody& body_b = m_bodies[id_b];


    float impulse_force = glm::dot(relative_velocity, regular);


    float inertia_magnitude_a = body_a.invert_moment * Vec2Utilities::cross2(relative_a, regular);
    float inertia_magnitude_b = body_b.invert_moment * Vec2Utilities::cross2(relative_b, regular);


    // Compute cross product: inertia x relative_position
    glm::vec2 inertia_a = {-inertia_magnitude_a * relative_a.y,inertia_magnitude_a * relative_a.x};
    glm::vec2 inertia_b = {-inertia_magnitude_b * relative_b.y,inertia_magnitude_b * relative_b.x};

    // Whole angular momentum within the path of collision
    float angular_effect = glm::dot(inertia_a + inertia_b, regular);

    // Calculate whole impulse
    const float restitution = body_a.restitution * body_b.restitution;
    return (-(1.0f + restitution) * impulse_force) / (total_mass + angular_effect);
}


void Simulator::applyCollisionImpulse(const CollisionDetails &collision, const glm::vec2 &regular,
                                      const glm::vec2 &relative_a, const glm::vec2 &relative_b,
                                      float impulse) {

    BodyId id_a = collision.bodyA();
    BodyId id_b = collision.bodyB();

    glm::vec2 full_impulse = regular * impulse;

    addImpulse(id_a, full_impulse);
    addImpulse(id_b, -full_impulse);


    addAngularImpulse(id_a, Vec2Utilities::cross2(relative_a, full_impulse));
    addAngularImpulse(id_b, Vec2Utilities::cross2(relative_b, -full_impulse));
}

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

- Advertisement -spot_img

Latest Articles