Example #1
0
void PhysicsWorld::solvePositions(Contact & contact)
{
    if (!contact.intersect())
    {
        return;
    }

    contact.update();

    auto & bodyA = contact.bodyA();
    auto & bodyB = contact.bodyB();

    auto & transformA = bodyA.transform();
    auto & transformB = bodyB.transform();

    auto mA = bodyA.inverseMass();
    auto mB = bodyB.inverseMass();

    auto & iA = bodyA.worldInverseInertia();
    auto & iB = bodyB.worldInverseInertia();

    auto & cA = transformA.position();
    auto & cB = transformB.position();

    for (uint p = 0; p < contact.numPoints(); p++)
    {
        auto & point = contact.point(p);

        auto & n = point.normal;

        auto position = point.position;
        auto separation = -point.depth;

        auto rA = position - cA;
        auto rB = position - cB;

        // Track max constraint error.
        //  auto minSeparation = std::min(minSeparation, separation);

        // Prevent large corrections and allow slop.
        auto C = std::min(std::max(0.5f * (separation + LINEAR_SLOP), -MAX_LINEAR_CORRECTION), 0.0f);

        // Compute the effective mass.
        auto normalMass = point.normalMass;

        // Compute normal impulse
        auto impulse = normalMass > 0.0f ? -C / normalMass : 0.0f;

        auto P = impulse * n;

        std::cout << P << " " << separation << " " << (-mA * P) << " " << (mB * P) << std::endl;

        transformA.setPosition(transformA.position() - mA * P);
        transformA.setOrientation(QuaternionAxisRotation(transformA.orientation(), iA * glm::cross(rA, -P)));

        transformB.setPosition(transformB.position() + mB * P);
        transformB.setOrientation(QuaternionAxisRotation(transformB.orientation(), iB * glm::cross(rB, P)));
    }
}
Example #2
0
void PhysicsWorld::warmStart(Contact & contact) const
{
    if (!contact.intersect())
    {
        return;
    }

    auto & bodyA = contact.bodyA();
    auto & bodyB = contact.bodyB();

    auto mA = bodyA.inverseMass();
    auto & iA = bodyA.worldInverseInertia();
    auto & vA = bodyA.linearVelocity();
    auto & wA = bodyA.angularVelocity();
    auto & cA = bodyA.transform().position();

    auto mB = bodyB.inverseMass();
    auto & iB = bodyB.worldInverseInertia();
    auto & vB = bodyB.linearVelocity();
    auto & wB = bodyB.angularVelocity();
    auto & cB = bodyB.transform().position();

    for (uint p = 0; p < contact.numPoints(); p++)
    {
        auto & point = contact.point(p);

        auto & n = point.normal;

        auto rA = point.position - cA;
        auto rB = point.position - cB;

        auto lambda = point.normalImpulseAccumulator;

        auto J = lambda * n;

        bodyA.setLinearVelocity(vA - mA * J);
        bodyA.setAngularVelocity(wA - iA * glm::cross(rA, J));

        bodyB.setLinearVelocity(vB + mB * J);
        bodyB.setAngularVelocity(wB + iB * glm::cross(rB, J));
    }
}
Example #3
0
void PhysicsWorld::solveContactVelocities(Contact & contact)
{
    if (!contact.intersect())
    {
        return;
    }

    auto & bodyA = contact.bodyA();
    auto & bodyB = contact.bodyB();

    auto mA = bodyA.inverseMass();
    auto & iA = bodyA.worldInverseInertia();
    auto & vA = bodyA.linearVelocity();
    auto & wA = bodyA.angularVelocity();
    auto & cA = bodyA.transform().position();

    auto mB = bodyB.inverseMass();
    auto & iB = bodyB.worldInverseInertia();
    auto & vB = bodyB.linearVelocity();
    auto & wB = bodyB.angularVelocity();
    auto & cB = bodyB.transform().position();

    // Coefficient of restitution
    auto e = contact.restitution();

    /**
     * Solve tangent velocities
     */
    for (uint p = 0; p < contact.numPoints(); p++)
    {
        auto & point = contact.point(p);

        auto rA = point.position - cA;
        auto rB = point.position - cB;

        // Relative velocity along normal
        auto vra = bodyA.localVelocity(rA);
        auto vrb = bodyB.localVelocity(rB);
        auto vRel = vrb - vra;
        auto vRelNormal = glm::dot(point.normal, vRel);

        // Relative velocity along tangent
        auto vRelTangent = vRel - (vRelNormal * point.normal);

        if (vRelTangent == glm::vec3(0.0f)) {
            continue;
        }

        auto tangent = glm::normalize(vRelTangent);

        auto tangentMass = glm::dot(glm::cross(iA * glm::cross(rA, tangent), rA) +
                                    glm::cross(iB * glm::cross(rB, tangent), rB), tangent) + mA + mB;

        if (tangentMass == 0.0f) {
            continue;
        }

        auto lambda = -glm::length(vRelTangent) / tangentMass;

        auto maxFriction = contact.friction() * point.normalImpulseAccumulator;
        auto newImpulse = std::max(-maxFriction, std::min<float>(maxFriction, point.tangentImpulseAccumulator + lambda));
        lambda = newImpulse - point.tangentImpulseAccumulator;

        auto P = lambda * tangent;

        bodyA.setLinearVelocity(vA - mA * P);
        bodyA.setAngularVelocity(wA - iA * glm::cross(rA, P));

        bodyB.setLinearVelocity(vB + mB * P);
        bodyB.setAngularVelocity(wB + iB * glm::cross(rB, P));
    }

    /**
     * Solve normal velocities
     */
    for (uint p = 0; p < contact.numPoints(); p++)
    {
        auto & point = contact.point(p);

        auto rA = point.position - cA;
        auto rB = point.position - cB;

        auto & n = point.normal;
        auto normalMass = point.normalMass;
        auto velocityBias = point.velocityBias;

        // Relative velocity along normal
        auto vra = bodyA.localVelocity(rA);
        auto vrb = bodyB.localVelocity(rB);
        auto vRel = glm::dot(n, vrb - vra);

        //
        auto vDelta = velocityBias - vRel;

        auto lambda = vDelta / normalMass;

        auto newNormalImpulseAccumulator = std::max(lambda + point.normalImpulseAccumulator, 0.0f);
        lambda = newNormalImpulseAccumulator - point.normalImpulseAccumulator;
        point.normalImpulseAccumulator += lambda;

        // Bias lambda
        auto bias = (BAUMGARTE * std::max(point.depth - LINEAR_SLOP, 0.0f)) / m_timestep;

        // J - impulse magnitude
        auto J = (lambda + bias) * n;

        bodyA.setLinearVelocity(vA - mA * J);
        bodyA.setAngularVelocity(wA - iA * glm::cross(rA, J));

        bodyB.setLinearVelocity(vB + mB * J);
        bodyB.setAngularVelocity(wB + iB * glm::cross(rB, J));
    }
}