0
\$\begingroup\$

I've implemented a collision resolution system based on Ian Mellington's System Cyclone and afterwards based on the Game Physics Cookbook. Currently the last one is implemented.

For some reason the system behaves oddly. If I set up a test, where the cube drops from a bit up the Y-axis and with 45 degree rotation over the x axis it just stays on that edge, then it starts moving around weirdly. That last part is due to friction.

A video sample here

You should be able to see the contact points and their normal (up the Y axis)

If I move the object and slam it into a wall, it will end up rotating forever.

It's not the dampening, since that works fine - apply a force without gravity for instance and everything stops eventually.

It's not the inertia tensor.

The contact normal is pointing towards "B", meaning that it has to be negative for the object to be treated as "A"

The code is as follows:

while (currentiteration < 8) {
    for (int cidx = 0; cidx < contactDataFrame.size(); cidx++) {
        //apply impulse, frictionless
        {
            GVECTOR relativeContactPoint = Math::VectorSubtract(contactDataFrame[cidx].contactpoint, mPhysicsOBJData[0].position);
            GVECTOR closingVelocity = Math::VectorNegate(Math::VectorAdd(mPhysicsOBJData[0].velocity, Math::Vector3Cross(mPhysicsOBJData[0].rotation, relativeContactPoint)));

            float dp = Math::Vector3Dot(closingVelocity, Math::VectorNegate(contactDataFrame[cidx].contactnormal)).m128_f32[0];

            if (dp > 0.0f) {
                continue;
            }

            float numerator = (-(1.0f + restitution)) * dp;
            
            GMATRIX tensor = transformedTensors[0];; 
            GVECTOR torque = Math::Vector3Cross(Math::Vec3MultiplyMatrixRHS(Math::Vector3Cross(relativeContactPoint, Math::VectorNegate(contactDataFrame[cidx].contactnormal)), tensor), relativeContactPoint);

            float denominator = mPhysicsOBJData[0].inverseMass + Math::Vector3Dot(Math::VectorNegate(contactDataFrame[cidx].contactnormal), torque).m128_f32[0];
            if (denominator == 0.0f) {
                PRINT_N("ERROR - denominator J == 0");
                continue;
            }

            float j = numerator / denominator;
            j /= contactDataFrame[cidx].contactcount;

            GVECTOR impulse = Math::VecMultiplyScalar(Math::VectorNegate(contactDataFrame[cidx].contactnormal), j);
    
            mPhysicsOBJData[0].velocity = Math::VectorSubtract(mPhysicsOBJData[0].velocity, Math::VecMultiplyScalar(impulse, mPhysicsOBJData[0].inverseMass));
            mPhysicsOBJData[0].rotation = Math::VectorSubtract(mPhysicsOBJData[0].rotation, Math::Vec3MultiplyMatrixRHS(Math::Vector3Cross(relativeContactPoint, impulse), tensor));

            GVECTOR tangentNormal = Math::VectorSubtract(closingVelocity, Math::VecMultiplyScalar(Math::VectorNegate(contactDataFrame[cidx].contactnormal), Math::Vector3Dot(closingVelocity, Math::VectorNegate(contactDataFrame[cidx].contactnormal)).m128_f32[0]));

            if (sqrt(Math::Vector3Dot(tangentNormal, tangentNormal).m128_f32[0]) == 0.0f) {
                PRINT_N("ERROR - NO TAGENT VECTOR");
                continue;
            }
            tangentNormal = Math::Vec3Normalize(tangentNormal);

            numerator = -Math::Vector3Dot(closingVelocity, tangentNormal).m128_f32[0];
            denominator = mPhysicsOBJData[0].inverseMass + Math::Vector3Dot(tangentNormal, Math::Vector3Cross(Math::Vec3MultiplyMatrixRHS(Math::Vector3Cross(relativeContactPoint, tangentNormal), tensor), relativeContactPoint)).m128_f32[0];
            if (denominator == 0.0f) {
                PRINT_N("ERROR - DENOMINATOR TANGET == 0");
                continue;
            }
            float jt = numerator / denominator;
            jt /= contactDataFrame[cidx].contactcount;

            if (jt == 0.0f) {
                PRINT_N("ERROR - NO JT IMPULSE");
                continue;
            }

            float friction = 3.75f;
            if (jt > j * friction) {
                jt = j * friction;

            }
            else if (jt < -j * friction) {
                jt = -j * friction;
            }

            GVECTOR tagentImpulse = Math::VecMultiplyScalar(tangentNormal, jt);
            mPhysicsOBJData[0].velocity = Math::VectorSubtract(mPhysicsOBJData[0].velocity, tagentImpulse);
            mPhysicsOBJData[0].rotation = Math::VectorSubtract(mPhysicsOBJData[0].rotation, Math::Vec3MultiplyMatrixRHS(Math::Vector3Cross(relativeContactPoint, tagentImpulse), tensor));
        }
    }
    currentiteration++;
}
\$\endgroup\$
2
  • \$\begingroup\$ For the weird endless rotation see here: youtube.com/… - By the way, if I disable the friction it will still rotate endlessly \$\endgroup\$
    – Martin
    Commented Nov 26, 2023 at 20:29
  • \$\begingroup\$ Things haven't been solved yet, but I've achieved more stability by changing the check of the dot product of the closing velocity and the contact normal to if (dp > -0.01) youtu.be/GSCVSbUHCZ0 \$\endgroup\$
    – Martin
    Commented Dec 3, 2023 at 9:05

1 Answer 1

0
\$\begingroup\$

The problem was related to the orientation quaternion. Nothing related to the physics code.

I figured it out by applying forces to specific axes. I realized that nothing worked when the force was a rotational force (torque) around the Z-axis.

I then debugged the way the rotational velocity was translated into the orientation quaternion during the integration step, I compared it to online calculators. Especially the quaternion multiplication function (implemented besides the code) stood out as wrong. After fixing that i got rid of the weird rotational problems.

\$\endgroup\$
1
  • \$\begingroup\$ This answer would be even better if you showed the flawed code and how you fixed it. \$\endgroup\$
    – DMGregory
    Commented Dec 3, 2023 at 20:47

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .