DanielChappuis / reactphysics3d

Open source C++ physics engine library in 3D
http://www.reactphysics3d.com
zlib License
1.54k stars 223 forks source link

Collisions in Dynamic World are strange. #96

Closed jooseyo closed 5 years ago

jooseyo commented 5 years ago

I sorry for asking one more question but I can't figure out why the collisions work this way. If you feel annoyed, I would never ask questions again. I am so sorry for annoying you.

I made simple simulation of collision of two spheres. Then, I print the coordinates of the two spheres as the simulation runs. The problem is that they don't collide but pass through each other. Then, they collide in weird position.

Here is the setup Two spheres are created First sphere has position (-2, 0, 0) with initial velocity (1, 0, 0), radius = 0.5, and mass = 10 Second sphere has position (0, 0, 0) with initial velocity (-1, 0, 0), radius = 0.5, and mass = 10

I thought they will collide at positions 0: (-1.5, 0.0, 0.0) and 1: (-0.5, 0.0, 0.0) but they pass through it and collide at 0: (-0.5, 0.0, 0.0) and 1: (-1.5, 0.0, 0.0)

Here is my code

int main (int argc, char **argv) {
    Vector3 gravity = Vector3(0.0, 0.0, 0.0);

    double mSimulationTime = 2.0;
    DynamicsWorld dynamicsWorld(gravity);

    // create a rigid body with the position
    Vector3 initPosition1(-2.0, 0.0, 0.0);
    Quaternion quaternion1 = Quaternion::identity();
    Transform transform1(initPosition1, quaternion1);
    RigidBody * body1 = dynamicsWorld.createRigidBody(transform1);

    // set the initial velocity, material, and the shape
    SphereShape sphere1(decimal(0.5));
    body1->addCollisionShape(&sphere1, transform1, decimal(10.0));
    Vector3 init_velocity1 = Vector3(1.0, 0.0, 0.0); 
    body1->setLinearVelocity(init_velocity1);
    body1->getMaterial().setBounciness(decimal(1.0));
    body1->getMaterial().setFrictionCoefficient(decimal(0.0));
    body1->setType(BodyType::DYNAMIC);

    // create a rigid body with the position
    Vector3 initPosition2(0.0, 0.0, 0.0);
    Quaternion quaternion2 = Quaternion::identity();
    Transform transform2(initPosition2, quaternion2);
    RigidBody * body2 = dynamicsWorld.createRigidBody(transform2);

    // set the initial velocity, material, and the shape
    SphereShape sphere2(decimal(0.5));
    body2->addCollisionShape(&sphere2, transform2, decimal(10.0));
    Vector3 init_velocity2 = Vector3(-1.0, 0.0, 0.0);
    body2->setLinearVelocity(init_velocity2);
    body2->getMaterial().setBounciness(decimal(1.0));
    body2->getMaterial().setFrictionCoefficient(decimal(0.0));
    body2->setType(BodyType::DYNAMIC);

    const float timeStep = 1.0 / 60.0;

    while (mSimulationTime >= timeStep) {
        mSimulationTime -= timeStep;
        dynamicsWorld.update(timeStep);
        double x, y, z;

        x = body1->getTransform().getPosition().x;
        y = body1->getTransform().getPosition().y;
        z = body1->getTransform().getPosition().z;
        printf("0: (%f, %f, %f)\n", x, y, z);

        x = body2->getTransform().getPosition().x;
        y = body2->getTransform().getPosition().y;
        z = body2->getTransform().getPosition().z;
        printf("1: (%f, %f, %f)\n", x, y, z);

        printf("collision = %s\n", dynamicsWorld.testOverlap(body1, body2) ? "TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue" : "false");
        printf("num = %d\n", dynamicsWorld.getNbRigidBodies());
        printf("----------------\n\n");
    }
}

To figure out, I tested with other initial data and found another strange result.

Here is the setup Two spheres are created First sphere has position (2, 0, 0) with initial velocity (1, 0, 0), radius = 0.5, and mass = 10 Second sphere has position (4, 0, 0) with initial velocity (0, 0, 0), radius = 0.5, and mass = 10

Here is the code for testing

int main (int argc, char **argv) {
    Vector3 gravity = Vector3(0.0, 0.0, 0.0);

    double mSimulationTime = 4.0;
    DynamicsWorld dynamicsWorld(gravity);

    // create a rigid body with the position
    Vector3 initPosition1(2.0, 0.0, 0.0);
    Quaternion quaternion1 = Quaternion::identity();
    Transform transform1(initPosition1, quaternion1);
    RigidBody * body1 = dynamicsWorld.createRigidBody(transform1);

    // set the initial velocity, material, and the shape
    SphereShape sphere1(decimal(0.5));
    body1->addCollisionShape(&sphere1, transform1, decimal(10.0));
    Vector3 init_velocity1 = Vector3(1.0, 0.0, 0.0); 
    body1->setLinearVelocity(init_velocity1);
    body1->getMaterial().setBounciness(decimal(1.0));
    body1->getMaterial().setFrictionCoefficient(decimal(0.0));
    body1->setType(BodyType::DYNAMIC);

    // create a rigid body with the position
    Vector3 initPosition2(4.0, 0.0, 0.0);
    Quaternion quaternion2 = Quaternion::identity();
    Transform transform2(initPosition2, quaternion2);
    RigidBody * body2 = dynamicsWorld.createRigidBody(transform2);

    // set the initial velocity, material, and the shape
    SphereShape sphere2(decimal(0.5));
    body2->addCollisionShape(&sphere2, transform2, decimal(10.0));
    Vector3 init_velocity2 = Vector3(0.0, 0.0, 0.0);
    body2->setLinearVelocity(init_velocity2);
    body2->getMaterial().setBounciness(decimal(1.0));
    body2->getMaterial().setFrictionCoefficient(decimal(0.0));
    body2->setType(BodyType::DYNAMIC);

    const float timeStep = 1.0 / 60.0;

    while (mSimulationTime >= timeStep) {
        mSimulationTime -= timeStep;
        dynamicsWorld.update(timeStep);
        double x, y, z;

        x = body1->getTransform().getPosition().x;
        y = body1->getTransform().getPosition().y;
        z = body1->getTransform().getPosition().z;
        printf("0: (%f, %f, %f)\n", x, y, z);

        x = body2->getTransform().getPosition().x;
        y = body2->getTransform().getPosition().y;
        z = body2->getTransform().getPosition().z;
        printf("1: (%f, %f, %f)\n", x, y, z);

        printf("collision = %s\n", dynamicsWorld.testOverlap(body1, body2) ? "TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue" : "false");
        printf("num = %d\n", dynamicsWorld.getNbRigidBodies());
        printf("----------------\n\n");
    }
}

The last part of the result is following.

collision = false
num = 2
----------------

0: (4.883372, 0.000000, 0.000000)
1: (4.000000, 0.000000, 0.000000)
collision = false
num = 2
----------------

0: (4.900039, 0.000000, 0.000000)
1: (4.000000, 0.000000, 0.000000)
collision = false
num = 2
----------------

0: (4.916706, 0.000000, 0.000000)
1: (4.000000, 0.000000, 0.000000)
collision = false
num = 2
----------------

0: (4.933372, 0.000000, 0.000000)
1: (4.000000, 0.000000, 0.000000)
collision = false
num = 2
----------------

0: (4.950039, 0.000000, 0.000000)
1: (4.000000, 0.000000, 0.000000)
collision = false
num = 2
----------------

0: (4.966706, 0.000000, 0.000000)
1: (4.000000, 0.000000, 0.000000)
collision = false
num = 2
----------------

0: (4.983373, 0.000000, 0.000000)
1: (4.000000, 0.000000, 0.000000)
collision = false
num = 2
----------------

0: (5.000040, 0.000000, 0.000000)
1: (4.000000, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.008373, 0.000000, 0.000000)
1: (4.008333, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.016706, 0.000000, 0.000000)
1: (4.016666, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.025040, 0.000000, 0.000000)
1: (4.025000, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.033373, 0.000000, 0.000000)
1: (4.033333, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.041706, 0.000000, 0.000000)
1: (4.041666, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.050039, 0.000000, 0.000000)
1: (4.049999, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.058372, 0.000000, 0.000000)
1: (4.058332, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.066706, 0.000000, 0.000000)
1: (4.066666, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.075039, 0.000000, 0.000000)
1: (4.074999, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.083372, 0.000000, 0.000000)
1: (4.083332, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.091705, 0.000000, 0.000000)
1: (4.091665, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.100039, 0.000000, 0.000000)
1: (4.099998, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.108372, 0.000000, 0.000000)
1: (4.108332, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.116705, 0.000000, 0.000000)
1: (4.116665, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.125038, 0.000000, 0.000000)
1: (4.124998, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.133371, 0.000000, 0.000000)
1: (4.133331, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.141705, 0.000000, 0.000000)
1: (4.141665, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.150038, 0.000000, 0.000000)
1: (4.149998, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.158371, 0.000000, 0.000000)
1: (4.158331, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.166704, 0.000000, 0.000000)
1: (4.166664, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.175037, 0.000000, 0.000000)
1: (4.174997, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.183371, 0.000000, 0.000000)
1: (4.183331, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.191704, 0.000000, 0.000000)
1: (4.191664, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.200037, 0.000000, 0.000000)
1: (4.199997, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.208370, 0.000000, 0.000000)
1: (4.208330, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.216703, 0.000000, 0.000000)
1: (4.216663, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.225037, 0.000000, 0.000000)
1: (4.224997, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.233370, 0.000000, 0.000000)
1: (4.233330, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.241703, 0.000000, 0.000000)
1: (4.241663, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.250036, 0.000000, 0.000000)
1: (4.249996, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.258369, 0.000000, 0.000000)
1: (4.258329, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.266703, 0.000000, 0.000000)
1: (4.266663, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.275036, 0.000000, 0.000000)
1: (4.274996, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.283369, 0.000000, 0.000000)
1: (4.283329, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.291702, 0.000000, 0.000000)
1: (4.291662, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.300035, 0.000000, 0.000000)
1: (4.299995, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.308369, 0.000000, 0.000000)
1: (4.308329, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.316702, 0.000000, 0.000000)
1: (4.316662, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.325035, 0.000000, 0.000000)
1: (4.324995, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.333368, 0.000000, 0.000000)
1: (4.333328, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.341702, 0.000000, 0.000000)
1: (4.341661, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.350035, 0.000000, 0.000000)
1: (4.349995, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.358368, 0.000000, 0.000000)
1: (4.358328, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.366701, 0.000000, 0.000000)
1: (4.366661, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.375034, 0.000000, 0.000000)
1: (4.374994, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.383368, 0.000000, 0.000000)
1: (4.383327, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.391701, 0.000000, 0.000000)
1: (4.391661, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.400034, 0.000000, 0.000000)
1: (4.399994, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.408367, 0.000000, 0.000000)
1: (4.408327, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.416700, 0.000000, 0.000000)
1: (4.416660, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.425034, 0.000000, 0.000000)
1: (4.424994, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.433367, 0.000000, 0.000000)
1: (4.433327, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.441700, 0.000000, 0.000000)
1: (4.441660, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.450033, 0.000000, 0.000000)
1: (4.449993, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.458366, 0.000000, 0.000000)
1: (4.458326, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.466700, 0.000000, 0.000000)
1: (4.466660, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.475033, 0.000000, 0.000000)
1: (4.474993, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.483366, 0.000000, 0.000000)
1: (4.483326, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

0: (5.491699, 0.000000, 0.000000)
1: (4.491659, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

They collide with each other at unexpected position. Then, they do not bounce off but merge into one thing to move together.

Again, I am so sorry for another question. Thank you

DanielChappuis commented 5 years ago

Hello,

When you call the following method to create a body:

RigidBody * body1 = dynamicsWorld.createRigidBody(transform1);

The transform1 here represents the position and orientation of the body in the physics world.

Then, when you add a collision shape for your body with the following code:

body1->addCollisionShape(&sphere1, transform1, decimal(10.0));

Here the transform1 parameter represents the position and orientation of the collision shape in the local-space of body1.

Therefore, I think your issue is that you are moving the body in the world using transform1 and then, you are moving again your collision shape inside the body using transform1. This is probably not what you want to do.

If you want the sphere collision shape to be at the center (origin) of the local-space of body1, you need to give an identity transform when you call the addCollisionShape() method. That's probably what you want to do.

jooseyo commented 5 years ago

Thank you for your response, The collision now occurs where it is expected. However, the second situation is still working in a strange way.

The collision occurs where it is expected but it works like a perfectly inelastic collision. Since I set bounciness as 1.0, I expected a perfectly elastic collision. How can I make the collision work as a perfect elastic collision? It happens when a sphere collides with a static box. When a sphere collides with a static box, it doesn't bounce back but just stops when collision occurs.

Here is the test I tried Two spheres are created First sphere has position (2.8, 0, 0) with initial velocity (1, 0, 0), radius = 0.5, and mass = 10 Second sphere has position (4, 0, 0) with initial velocity (0, 0, 0), radius = 0.5, and mass = 10

position 0: (2.816667, 0.000000, 0.000000)
velocity 0: (1.000000, 0.000000, 0.000000)
position 1: (4.000000, 0.000000, 0.000000)
velocity 1: (0.000000, 0.000000, 0.000000)
collision = false
num = 2
----------------

position 0: (2.833333, 0.000000, 0.000000)
velocity 0: (1.000000, 0.000000, 0.000000)
position 1: (4.000000, 0.000000, 0.000000)
velocity 1: (0.000000, 0.000000, 0.000000)
collision = false
num = 2
----------------

position 0: (2.850000, 0.000000, 0.000000)
velocity 0: (1.000000, 0.000000, 0.000000)
position 1: (4.000000, 0.000000, 0.000000)
velocity 1: (0.000000, 0.000000, 0.000000)
collision = false
num = 2
----------------

position 0: (2.866667, 0.000000, 0.000000)
velocity 0: (1.000000, 0.000000, 0.000000)
position 1: (4.000000, 0.000000, 0.000000)
velocity 1: (0.000000, 0.000000, 0.000000)
collision = false
num = 2
----------------

position 0: (2.883333, 0.000000, 0.000000)
velocity 0: (1.000000, 0.000000, 0.000000)
position 1: (4.000000, 0.000000, 0.000000)
velocity 1: (0.000000, 0.000000, 0.000000)
collision = false
num = 2
----------------

position 0: (2.900000, 0.000000, 0.000000)
velocity 0: (1.000000, 0.000000, 0.000000)
position 1: (4.000000, 0.000000, 0.000000)
velocity 1: (0.000000, 0.000000, 0.000000)
collision = false
num = 2
----------------

position 0: (2.916667, 0.000000, 0.000000)
velocity 0: (1.000000, 0.000000, 0.000000)
position 1: (4.000000, 0.000000, 0.000000)
velocity 1: (0.000000, 0.000000, 0.000000)
collision = false
num = 2
----------------

position 0: (2.933333, 0.000000, 0.000000)
velocity 0: (1.000000, 0.000000, 0.000000)
position 1: (4.000000, 0.000000, 0.000000)
velocity 1: (0.000000, 0.000000, 0.000000)
collision = false
num = 2
----------------

position 0: (2.950000, 0.000000, 0.000000)
velocity 0: (1.000000, 0.000000, 0.000000)
position 1: (4.000000, 0.000000, 0.000000)
velocity 1: (0.000000, 0.000000, 0.000000)
collision = false
num = 2
----------------

position 0: (2.966666, 0.000000, 0.000000)
velocity 0: (1.000000, 0.000000, 0.000000)
position 1: (4.000000, 0.000000, 0.000000)
velocity 1: (0.000000, 0.000000, 0.000000)
collision = false
num = 2
----------------

position 0: (2.983333, 0.000000, 0.000000)
velocity 0: (1.000000, 0.000000, 0.000000)
position 1: (4.000000, 0.000000, 0.000000)
velocity 1: (0.000000, 0.000000, 0.000000)
collision = false
num = 2
----------------

position 0: (3.000000, 0.000000, 0.000000)
velocity 0: (1.000000, 0.000000, 0.000000)
position 1: (4.000000, 0.000000, 0.000000)
velocity 1: (0.000000, 0.000000, 0.000000)
collision = false
num = 2
----------------

position 0: (3.016666, 0.000000, 0.000000)
velocity 0: (1.000000, 0.000000, 0.000000)
position 1: (4.000000, 0.000000, 0.000000)
velocity 1: (0.000000, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

position 0: (3.024333, 0.000000, 0.000000)
velocity 0: (0.500000, 0.000000, 0.000000)
position 1: (4.009000, 0.000000, 0.000000)
velocity 1: (0.500000, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

position 0: (3.032133, 0.000000, 0.000000)
velocity 0: (0.500000, 0.000000, 0.000000)
position 1: (4.017867, 0.000000, 0.000000)
velocity 1: (0.500000, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

position 0: (3.040040, 0.000000, 0.000000)
velocity 0: (0.500000, 0.000000, 0.000000)
position 1: (4.026627, 0.000000, 0.000000)
velocity 1: (0.500000, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

position 0: (3.048032, 0.000000, 0.000000)
velocity 0: (0.500000, 0.000000, 0.000000)
position 1: (4.035301, 0.000000, 0.000000)
velocity 1: (0.500000, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

position 0: (3.056092, 0.000000, 0.000000)
velocity 0: (0.500000, 0.000000, 0.000000)
position 1: (4.043908, 0.000000, 0.000000)
velocity 1: (0.500000, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

position 0: (3.064207, 0.000000, 0.000000)
velocity 0: (0.500000, 0.000000, 0.000000)
position 1: (4.052459, 0.000000, 0.000000)
velocity 1: (0.500000, 0.000000, 0.000000)
collision = TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue
num = 2
----------------

Here is the code

int main (int argc, char **argv) {
    Vector3 gravity = Vector3(0.0, 0.0, 0.0);

    double mSimulationTime = 1.0;
    DynamicsWorld dynamicsWorld(gravity);

    // create a rigid body with the position
    Vector3 initPosition1(2.8, 0.0, 0.0);
    Quaternion quaternion1 = Quaternion::identity();
    Transform transform1(initPosition1, quaternion1);
    RigidBody * body1 = dynamicsWorld.createRigidBody(transform1);

    // set the initial velocity, material, and the shape
    SphereShape sphere1(decimal(0.5));
    body1->addCollisionShape(&sphere1, Transform::identity(), decimal(10.0));
    Vector3 init_velocity1 = Vector3(1.0, 0.0, 0.0); 
    body1->setLinearVelocity(init_velocity1);
    body1->getMaterial().setBounciness(decimal(1.0));
    body1->getMaterial().setFrictionCoefficient(decimal(0.0));
    body1->setType(BodyType::DYNAMIC);

    // create a rigid body with the position
    Vector3 initPosition2(4.0, 0.0, 0.0);
    Quaternion quaternion2 = Quaternion::identity();
    Transform transform2(initPosition2, quaternion2);
    RigidBody * body2 = dynamicsWorld.createRigidBody(transform2);

    // set the initial velocity, material, and the shape
    SphereShape sphere2(decimal(0.5));
    body2->addCollisionShape(&sphere2, Transform::identity(), decimal(10.0));
    Vector3 init_velocity2 = Vector3(0.0, 0.0, 0.0);
    body2->setLinearVelocity(init_velocity2);
    body2->getMaterial().setBounciness(decimal(1.0));
    body2->getMaterial().setFrictionCoefficient(decimal(0.0));
    body2->setType(BodyType::DYNAMIC);

    const float timeStep = 1.0 / 60.0;

    while (mSimulationTime >= timeStep) {
        mSimulationTime -= timeStep;
        dynamicsWorld.update(timeStep);
        double x, y, z, vx, vy, vz;

        x = body1->getTransform().getPosition().x;
        y = body1->getTransform().getPosition().y;
        z = body1->getTransform().getPosition().z;
        vx = body1->getLinearVelocity().x;
        vy = body1->getLinearVelocity().y;
        vz = body1->getLinearVelocity().z;
        printf("position 0: (%f, %f, %f)\n", x, y, z);
        printf("velocity 0: (%f, %f, %f)\n", vx, vy, vz);

        x = body2->getTransform().getPosition().x;
        y = body2->getTransform().getPosition().y;
        z = body2->getTransform().getPosition().z;
        vx = body2->getLinearVelocity().x;
        vy = body2->getLinearVelocity().y;
        vz = body2->getLinearVelocity().z;
        printf("position 1: (%f, %f, %f)\n", x, y, z);
        printf("velocity 1: (%f, %f, %f)\n", vx, vy, vz);

        printf("collision = %s\n", dynamicsWorld.testOverlap(body1, body2) ? "TrueTrueTrueTrueTrueTrueTrueTrueTrueTrue" : "false");
        printf("num = %d\n", dynamicsWorld.getNbRigidBodies());
        printf("----------------\n\n");
    }
}
DanielChappuis commented 5 years ago

Hello.

If I correctly understand your scenario, you have two spheres of equal masses. One sphere (sphere1) is moving right with an initial velocity of (1, 0, 0) toward another sphere (sphere2) that is not moving at all at the beginning. With a perfectly elastic collision (bounciness = 1), it is expected that when sphere1 collides with sphere2, sphere1 will stop moving and sphere2 will start moving right with the same initial velocity of sphere1. Therefore, at the end, the sphere1 should stop, and sphere2 should start moving to the right. Do you not observe that in the simulation ?

You say that the sphere1 does not bounce back after the collision but that's how physics works. If the spheres have equal masses the first will not bounce back but it will transfer all its kinetic energy to the second one that will start moving right with the sphere1 not moving at all.

If you want the sphere1 to bounce back. The mass of the sphere2 should be larger than the mass of sphere1. If you want the sphere2 to not move at all after the collision (like a wall), you need to set this body as STATIC. A static body as infinite mass and therefore, will never move. If you set the sphere2 as a static body. The sphere1 will collide against the sphere2 and bounce back with the velocity (-1, 0, 0) (Exactly as if the sphere1 collides against a wall). But to do that, you need to set the sphere2 to be body of STATIC type (instead of DYNAMIC) with the followoing code:

body2->setType(BodyType::STATIC);

Also note that the code you gave me do not represent the scenario you described because in your code you set the velocity of sphere2 to be (-1, 0, 0) and not (0, 0, 0).

jooseyo commented 5 years ago

I am so sorry, I think I explained the situation so poorly. I gave you two different situations above. Let me explain the first situation. The first paragraph you wrote is the first situation that I got currently. Two spheres have the same mass. Sphere1 is moving toward sphere2 and sphere2 is not moving. After collision, I expected that the sphere1 stops and sphere2 moves to the same direction with the velocity that sphere1 originally had (perfect elastic collision). However, in my situation, two spheres stick together and move together in the direction with half of the velocity that sphere1 originally had. This is the first situation.

The second situation is that the dynamic sphere moves toward a static box. After the collision, sphere does not bounce off but stops when the collision occurs. Since the static box never moves, I thought the sphere will bounce off like the photon reflects against a mirror.

I am so sorry for the confusion. I also edited the code that I gave you above. I was so confused that fixed the code in a wrong way when I post it. I edited it so that it prints out the linear velocity to see how it changes.

DanielChappuis commented 5 years ago

About your first situation, are you sure you correctly set the bounciness factor of the two bodies to 1.0 ? If I test your situation in the testbed application, it works as expected. The sphere1 collides against sphere2 and stops moving while the sphere2 start moving with initial velocity of sphere1.

Concerning the second situation, you simply need to use a rigid body with STATIC type instead of DYNAMIC for your static box. This way, the box will have an infinite mass and will not move when the sphere collides against it.

box->setType(BodyType::STATIC);

jooseyo commented 5 years ago

Yes I set them correctly, I print the bouncinesses of two spheres at each time step and they are 1.0. Here is the code again. This is the code I run into the first situation (I literally copied and pasted).

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <execinfo.h>
#include <signal.h>
#include <unistd.h>

#include "reactphysics3d.h"

using namespace reactphysics3d;
using namespace std;

int main (int argc, char **argv) {
    /*
    Vector3 * gravity = new Vector3(0.0, 0.0, 0.0);
    ParticleSimulation ParticleSimulation(argv[1], stof(argv[2]), gravity);
    ParticleSimulation.get_positions_of_bodies();
    ParticleSimulation.simulate(stof(argv[3]));
    */
   Vector3 gravity = Vector3(0.0, 0.0, 0.0);

    double mSimulationTime = 0.5;
    DynamicsWorld dynamicsWorld(gravity);

    // create a rigid body with the position
    Vector3 initPosition1(2.9, 0.0, 0.0);
    Quaternion quaternion1 = Quaternion::identity();
    Transform transform1(initPosition1, quaternion1);
    RigidBody * body1 = dynamicsWorld.createRigidBody(transform1);

    // set the initial velocity, material, and the shape
    SphereShape sphere1(decimal(0.5));
    body1->addCollisionShape(&sphere1, Transform::identity(), decimal(10.0));
    Vector3 init_velocity1 = Vector3(1.0, 0.0, 0.0); 
    body1->setLinearVelocity(init_velocity1);
    body1->getMaterial().setBounciness(decimal(1.0));
    body1->getMaterial().setFrictionCoefficient(decimal(0.0));
    body1->setType(BodyType::DYNAMIC);

    // create a rigid body with the position
    Vector3 initPosition2(4.0, 0.0, 0.0);
    Quaternion quaternion2 = Quaternion::identity();
    Transform transform2(initPosition2, quaternion2);
    RigidBody * body2 = dynamicsWorld.createRigidBody(transform2);

    // set the initial velocity, material, and the shape
    SphereShape sphere2(decimal(0.5));
    body2->addCollisionShape(&sphere2, Transform::identity(), decimal(10.0));
    Vector3 init_velocity2 = Vector3(0.0, 0.0, 0.0);
    body2->setLinearVelocity(init_velocity2);
    body2->getMaterial().setBounciness(decimal(1.0));
    body2->getMaterial().setFrictionCoefficient(decimal(0.0));
    body2->setType(BodyType::DYNAMIC);

    const float timeStep = 1.0 / 60.0;

    while (mSimulationTime >= timeStep) {
        mSimulationTime -= timeStep;
        dynamicsWorld.update(timeStep);
        double x, y, z, vx, vy, vz;

        x = body1->getTransform().getPosition().x;
        y = body1->getTransform().getPosition().y;
        z = body1->getTransform().getPosition().z;
        vx = body1->getLinearVelocity().x;
        vy = body1->getLinearVelocity().y;
        vz = body1->getLinearVelocity().z;
        printf("position of sphere 1: (%f, %f, %f)\n", x, y, z);
        printf("velocity of sphere 1: (%f, %f, %f)\n", vx, vy, vz);
        printf("bounciness of sphere 1: %f\n\n", body1->getMaterial().getBounciness());

        x = body2->getTransform().getPosition().x;
        y = body2->getTransform().getPosition().y;
        z = body2->getTransform().getPosition().z;
        vx = body2->getLinearVelocity().x;
        vy = body2->getLinearVelocity().y;
        vz = body2->getLinearVelocity().z;
        printf("position of sphere 2: (%f, %f, %f)\n", x, y, z);
        printf("velocity of sphere 2: (%f, %f, %f)\n", vx, vy, vz);
        printf("bounciness of sphere 2: %f\n", body2->getMaterial().getBounciness());
        printf("----------------\n\n");
    }
}

Here is the output

position of sphere 1: (2.916667, 0.000000, 0.000000)
velocity of sphere 1: (1.000000, 0.000000, 0.000000)
bounciness of sphere 1: 1.000000

position of sphere 2: (4.000000, 0.000000, 0.000000)
velocity of sphere 2: (0.000000, 0.000000, 0.000000)
bounciness of sphere 2: 1.000000
----------------

position of sphere 1: (2.933333, 0.000000, 0.000000)
velocity of sphere 1: (1.000000, 0.000000, 0.000000)
bounciness of sphere 1: 1.000000

position of sphere 2: (4.000000, 0.000000, 0.000000)
velocity of sphere 2: (0.000000, 0.000000, 0.000000)
bounciness of sphere 2: 1.000000
----------------

position of sphere 1: (2.950000, 0.000000, 0.000000)
velocity of sphere 1: (1.000000, 0.000000, 0.000000)
bounciness of sphere 1: 1.000000

position of sphere 2: (4.000000, 0.000000, 0.000000)
velocity of sphere 2: (0.000000, 0.000000, 0.000000)
bounciness of sphere 2: 1.000000
----------------

position of sphere 1: (2.966667, 0.000000, 0.000000)
velocity of sphere 1: (1.000000, 0.000000, 0.000000)
bounciness of sphere 1: 1.000000

position of sphere 2: (4.000000, 0.000000, 0.000000)
velocity of sphere 2: (0.000000, 0.000000, 0.000000)
bounciness of sphere 2: 1.000000
----------------

position of sphere 1: (2.983333, 0.000000, 0.000000)
velocity of sphere 1: (1.000000, 0.000000, 0.000000)
bounciness of sphere 1: 1.000000

position of sphere 2: (4.000000, 0.000000, 0.000000)
velocity of sphere 2: (0.000000, 0.000000, 0.000000)
bounciness of sphere 2: 1.000000
----------------

position of sphere 1: (3.000000, 0.000000, 0.000000)
velocity of sphere 1: (1.000000, 0.000000, 0.000000)
bounciness of sphere 1: 1.000000

position of sphere 2: (4.000000, 0.000000, 0.000000)
velocity of sphere 2: (0.000000, 0.000000, 0.000000)
bounciness of sphere 2: 1.000000
----------------

position of sphere 1: (3.016667, 0.000000, 0.000000)
velocity of sphere 1: (1.000000, 0.000000, 0.000000)
bounciness of sphere 1: 1.000000

position of sphere 2: (4.000000, 0.000000, 0.000000)
velocity of sphere 2: (0.000000, 0.000000, 0.000000)
bounciness of sphere 2: 1.000000
----------------

position of sphere 1: (3.024333, 0.000000, 0.000000)
velocity of sphere 1: (0.500000, 0.000000, 0.000000)
bounciness of sphere 1: 1.000000

position of sphere 2: (4.009000, 0.000000, 0.000000)
velocity of sphere 2: (0.500000, 0.000000, 0.000000)
bounciness of sphere 2: 1.000000
----------------

position of sphere 1: (3.032133, 0.000000, 0.000000)
velocity of sphere 1: (0.500000, 0.000000, 0.000000)
bounciness of sphere 1: 1.000000

position of sphere 2: (4.017867, 0.000000, 0.000000)
velocity of sphere 2: (0.500000, 0.000000, 0.000000)
bounciness of sphere 2: 1.000000
----------------

If you see the output of the code, the sphere1 gets half of the original velocity of itself and the sphere2 gets half of the original velocity of sphere1, and move together like a perfect inelastic collision. If your testbed works correctly, maybe I am printing wrong data and I am misunderstanding right now. Here is how I check the position, velocity, and the bounciness of the spheres I check the position with

x = body2->getTransform().getPosition().x;
y = body2->getTransform().getPosition().y;
z = body2->getTransform().getPosition().z;

I check the velocity with

vx = body2->getLinearVelocity().x;
vy = body2->getLinearVelocity().y;
vz = body2->getLinearVelocity().z;

I check the bounciness with

body1->getMaterial().getBounciness()

I can't figure out what I am misunderstanding right now.

DanielChappuis commented 5 years ago

Ok I think I have understood the issue. Previously, I have tested with a linear velocity of 2.0 instead of 1.0 and it made a difference. Sorry for that.

When, you create a DynamicsWorld, you can specify, as a second parameter, the settings of the physics world. If you do not set this parameter, the world will use default settings (as in your example). In those settings, there is a restitutionVelocityThreshold parameter that has a default value of 1.0. This parameter says that if a collision occurs at a linear velocity smaller or equal to 1.0, the collision energy restitution is disabled (bounce is disabled). This is to avoid jitter in the simulation when velocity of bodies is small.

Therefore, in you case, because you set the linear velocity to 1.0, and restitutionVelocityThreshold=1.0, the bounce was disabled. If you try to set your linear velocity to 1.1 for instance, bounce will work as expected.

To solve this issue, you can change the default value of the restitutionVelocityThreshold parameter in the world settings with the following code when you create your DynamicsWorld. In the following example, I set the value to 0.1.

WorldSettings worldSettings;
worldSettings.restitutionVelocityThreshold = decimal(0.1);

DynamicsWorld dynamicsWorld(gravity, worldSettings);

With this change it should work as expected.

DanielChappuis commented 5 years ago

Can I close this issue ?

DanielChappuis commented 5 years ago

I am closing this issue !