DanielChappuis / reactphysics3d

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

Discovering ReactPhysics3d : simple dynamic body does not even move #124

Closed esppat closed 4 years ago

esppat commented 4 years ago

Hi All,

Being new to ReactPhysics3d (but not to dev, C++ since 1992), I tried to create a simple dynamic body with two collision shapes (to simple rectangles). Then I apply every 1/100 sec two forces (not opposed), and while checking for body position or velocity, nothing is alive: I get zeroes everywhere...

I did not found any full (simple) example, where could I find them?

Please find the part of code I use to try to move a rigid dynamic body with some forces.

Thanks a lot for this very nice lib!!!

Patrice

PS: Here is the code I use:


    void SimulationController::create3dBody()
    {
        m_gravity = new rp3d::Vector3(0.0, 0.0, -9.81); // yes, X and Y are horizontal
        m_world = new rp3d::DynamicsWorld(*m_gravity);

        // Change the number of iterations of the velocity solver
        m_world->setNbIterationsVelocitySolver(15);

        // Change the number of iterations of the position solver
        m_world->setNbIterationsPositionSolver(8);

        // Initial position and orientation of the rigid body
        rp3d::Vector3 initPosition(0.0, 0.0, 0.0);
        rp3d::Quaternion initOrientation = rp3d::Quaternion::identity();
        rp3d::Transform transform(initPosition, initOrientation);

        // Create a rigid body in the world
        m_body = m_world->createRigidBody(transform);

        m_body->setType(BodyType::DYNAMIC); // I found this error
        m_body->enableGravity(false); // to simplify problem for now

        rp3d::Vector3 hullHalfExtents(0.75, 0.15, 0.2);
        m_hullCollisionShape = new rp3d::BoxShape(hullHalfExtents);

        m_hullMass = rp3d::decimal(5.0); // kg

        initPosition = rp3d::Vector3(0.0, -0.5, 0.0);
        transform = rp3d::Transform(initPosition, initOrientation);
        m_leftHull = m_body->addCollisionShape(m_hullCollisionShape, transform, m_hullMass);

        initPosition = rp3d::Vector3(0.0, +0.5, 0.0);
        transform = rp3d::Transform(initPosition, initOrientation);
        m_rightHull = m_body->addCollisionShape(m_hullCollisionShape, transform, m_hullMass);
    }

    void SimulationController::update3dBody(const second_t tickDuration)
    {
        // TODO
        m_world->update(double(tickDuration)); // around 1/100 sec, a little bit more in fact
    }

...

    void SimulationController::applyForcesOn3dBody()
    {
        const Transform & bodyTransform = m_body->getTransform();

        for (auto element : m_simuElements)
        {
            newton_t xElementThrust;
            newton_t yElementThrust;
            meter_t x;
            meter_t y;

            ... // update thrust and thrust position

            Vector3 force(double(xElementThrust), double(yElementThrust), 0.0);

            Vector3 point(double(x), double(y), 0.0);
            point = bodyTransform * point;

            m_body->applyForce(force, point);
        }
    }
esppat commented 4 years ago

Setting gravity on Z axle, without any other force, and the body is falling (really too fast) on X axle ... What is wrong? Not very easy to dig in...

DanielChappuis commented 4 years ago

Hello.

Welcome to ReactPhysics3D. You can find the documentation for the current release here. I suggest to take a look at the user manual.

About your code, I see two main things that you need to change.

First, you need to use a constant time step for the physics simulation when you call the DynamicsWorld::update() method. You should never use the elapsed time of the previous frame. This is true for almost all physics engines. Take a look at the section "Updating the Dynamics World" so that you can understand how to update the simulation.

Secondly, in your code, it's not very clear when you call the applyForcesOn3dBody() method. Take a look at the user manual in the chapter "Applying Force or Torque to a Rigid Body" and here you will see that you need to call the RigidBody::applyForce() method not only once but during multiple frames.

I hope this helps.

esppat commented 4 years ago

Thanks for your detailed reply!

I obviously saw the explanation about update and constant time between updates. In my case, the duration I used is precise at about 10^-5 sec. I tried to set the duration as a constant (ie, 0.1 instead of the real 0.10005), and this did not changed anything. But OK, let keep a real constant duration.

Concerning forces, I do apply them constantly (at each 'frame'). This is also obvious to me. I keep trying to have something correct, I will update this issue post whenever I find something interesting (on a starter point of view ... ).

Once again, thanks for this superb product!

Patrice

esppat commented 4 years ago

OK, here is a very simple example I wrote, following instructions given in docs. The results are ... disappointing!

Here is the code (program output follows):

        rp3d::Vector3 gravity(0.0, -9.81, 0.0);
        rp3d::DynamicsWorld world(gravity);

        rp3d::Vector3 position(0.0, 0.0, 0.0);
        rp3d::Quaternion orientation = rp3d::Quaternion::identity();
        rp3d::Transform transform(position, orientation);

        rp3d::RigidBody * body = world.createRigidBody(transform);
        body->setType(rp3d::BodyType::DYNAMIC);

        rp3d::Vector3 halfExtents(0.05, 0.05, 0.05); // cube 10x10x10 cm?
        rp3d::BoxShape * collisionShape = new rp3d::BoxShape(halfExtents);

        rp3d::decimal mass = rp3d::decimal(5.0); // kg?

        position = rp3d::Vector3(0.0, 0.0, 0.0);
        transform = rp3d::Transform(position, orientation);
        body->addCollisionShape(collisionShape, transform, mass);

        body->recomputeMassInformation(); // useful?

        body->setLinearVelocity(rp3d::Vector3(0, 0, 0));
        body->setAngularVelocity(rp3d::Vector3(0, 0, 0));

        second_t frameDuration = 1.0_s;
        while (true)
        {
            world.update(double(frameDuration));

            LOG_THAT(body->getLinearVelocity().to_string());
            LOG_THAT(body->getAngularVelocity().to_string());
            LOG_THAT(body->getTransform().to_string());

            sleepFor(frameDuration);
        }

According to this simple code, the cube should 'fall down', because of gravity. For now, I do not apply any force nor couple.

Here is the beginning of the output:

body->getLinearVelocity().to_string() = Vector3(-9.810000,0.000000,0.000000)
body->getAngularVelocity().to_string() = Vector3(-9.810000,0.000000,0.000000)
body->getTransform().to_string() = Transform(Vector3(0.000000,0.000000,0.000000),Quaternion(-9.810000,0.000000,0.000000,0.000000))

body->getLinearVelocity().to_string() = Vector3(-58.860001,0.000000,0.000000)
body->getAngularVelocity().to_string() = Vector3(-29.430000,0.000000,0.000000)
body->getTransform().to_string() = Transform(Vector3(0.000000,0.000000,0.000000),Quaternion(-58.860001,0.000000,0.000000,0.000000))

If I understand this output, the cube is going forward along X axis. The velocity is at first frame equal to -9.81. At second frame, speed should be something like 2*-9.81 but it is far away from that (-58.86). Even stranger, angular velocity is not null ...

Any clue about what is happening?

Thanks a lot Patrice

DanielChappuis commented 4 years ago

Are you sure that the last code you posted is running alone and that there is no other code that interferes with it ? I have copied and pasted your code and made the following changes so that it compiles on my side:

//second_t frameDuration = 1.0_s;
float frameDuration = 1.0f;
while (true)
{
    testWorld.update(double(frameDuration));

     //LOG_THAT(body->getLinearVelocity().to_string());
     //LOG_THAT(body->getAngularVelocity().to_string());
     //LOG_THAT(body->getTransform().to_string());

     std::cout << "Linear Velocity: " << body->getLinearVelocity().to_string() << std::endl;
     std::cout << "Angular Velocity: " << body->getAngularVelocity().to_string() << std::endl;
     std::cout << "Transform: " << body->getTransform().to_string() << std::endl;

      //sleepFor(frameDuration);
    }

Then, if I run it, I have the following results which is exactly what I expect.

`Linear Velocity: Vector3(0.000000,-9.810000,0.000000) Angular Velocity: Vector3(0.000000,0.000000,0.000000) Transform: Transform(Vector3(0.000000,-9.810000,0.000000),Quaternion(0.000000,0.000000,0.000000,1.000000))

Linear Velocity: Vector3(0.000000,-19.620001,0.000000) Angular Velocity: Vector3(0.000000,0.000000,0.000000) Transform: Transform(Vector3(0.000000,-29.430000,0.000000),Quaternion(0.000000,0.000000,0.000000,1.000000))`

esppat commented 4 years ago

OK, I found the problem: I first tried to compile using floats, then I switched to double, mis-cleaning the whole stuff, then .... well, what a mess! I finished using headers configured as decimal == double, linking (without error!) to float compiled lib (or maybe the opposite, I am not sure). Blah! This is not professional at all, but I did this kind of error, and I am sorry to have been forced to open some ticket here. This is my bad, and I apologize.

Now, everything is back to some coherent results, and I will be able to continue my ReactPhysics3d exploration.

Thanks, and sorry for the noise!

DanielChappuis commented 4 years ago

No need to apologize. I am glad that you figured out what was going on. Best regards