Havok Precision

Hello,

I have a question regarding the Havok physics engine. I am trying to create a rope which is hanging on a movable object. You can think of a crane. But I have the problem that the rope doesnt stop straight down from the object above. There is alway someking of angle. I tried changing frictions, etc. and using different constraints (6DoF, BallAndSocket, Distant). Is there someway to tune the precision or something like that?

I can reproduce the problem with this example playground: https://playground.babylonjs.com/#NAMYYQ#2

If you wait till all spheres stop moving, every sphere stops in a different ā€˜positionā€™. Like in the picture below.

I would be really thankful for any tips and tricks. :slight_smile:

cc @eoin

Havok has an optimization to put bodies to sleep when they stop or are moving very slowly.

You can try to disable this on the constrained bodies like in:

https://playground.babylonjs.com/#NAMYYQ#15

4 Likes

Thanks for the quick answer. Unfortunately it seems that it still behaves the same way. I tested your adjusted playground. Down below is the result after waiting till nothing moves. Are there maybe other options that could be tweaked?

1 Like

I think I got it to work.

More detailed comments in the updated playground.

I used two methods of bypassing object sleep, but also had to apply gravity with applyForce().

Two methods from the forums are: 1) ActivationControl and 2) apply zero force.

You may want to play around to see which method(s) are really necessary. When I did so, only applyForce() gravity seemed necessary.

My biggest find is that these methods donā€™t seem to apply to the physics engineā€™s gravity (is this a bug in the engine?). So I set the engine gravity to 0.01 (didnā€™t want to use zero in case that was interpreted as special) and then apply the equivalent force of gravity to the objects and had to do so each physics frame.

Lastly, I applied a linear damping factor so I could test more quickly. You should be able to remove the damping to more closely match your original, but it takes a really long time to settle (5-10 minutes, but it doesnā€™t REALLY settle completely).

Itā€™s hard to tell if ActivationControl actually makes a difference since it doesnā€™t appear to work for gravity which means we then applyForce() gravity, which happens to be the other method that the forums suggest will bypass sleep.

5 Likes

Thanks for the detailed reply. This looks promising. I am going to implement it into my project and give you a feedback.

Animation Snake Sticker by VJ Suave

1 Like

I tried implementing the logic into the project. It did not really work out. I created a small version of the part where I tried to make it work in this playground: https://playground.babylonjs.com/#IG2RTD#2

It seems that the applyForce has no effect here. It only uses the engines gravity which is set to -0.01. When I set the engines gravity to -9.81 the box hanging on the ā€˜ropeā€™ sometimes jumps. Where does this come from?

Could you please have a look on it?
Maybe you can figger out what I am missing.

You can apply an impluse to the box moving along the long box with ā€˜aā€™ and ā€˜dā€™ on the keyboard.

At a glance, I see the rod/cylinder here has a physics aggregate, whereas the rods in the pendulum example do not. I think that involving the rod in the physics system might be contributing to the unexpected results.

Also, why not use a DistanceConstraint between the box and the box on top of the rod?

I adjusted the playground. Now there is a DistanceConstraint between the two boxes and no aggregate on the rod: https://playground.babylonjs.com/#IG2RTD#3

I still canā€™t make the applied force work like in the pendulum example. It seems that only the engines gravity gets applied. What am I missing? :thinking:

1 Like

It appears to be something with the PrismaticConstraint. Comment that out and things seem to move as expected, but obviously without the constraint. Are there other constraints you can substitute, just to see?

1 Like

I think I found the problem. The mass of the box seems to have a big influence. I broke down the playground to one fixed box with mass 0 and one swinging box, like the pendulum example. https://playground.babylonjs.com/#IG2RTD#8
At the moment the swinging box has a mass of 200 and it behaves like the -0.01 engines gravity. If you change the mass of the box to 1, it behaves like the pendulum example. I am not sure how to use this information. Might it be a solution to multiply the gravity with the mass? :thinking:

1 Like

This is strange. A pendulumā€™s period should be independent of mass, yet your PG shows clearly that in Havok, it is. I canā€™t figure out how your model of a pendulum differs from a real pendulum. I wrote up a whole thing about you should switch to shape and body instead of aggregates, but the result is the same.

Multiplying the applied force by the objectā€™s mass does indeed make the period independent of mass. It would be interesting to calculate the factor necessary to make the model act like a real pendulum: for angles less than 15 degrees, a ā€œseconds pendulumā€ is about 1 meter long.

Edit: period = 2 * PI * sqrt (length/g), where g = 9.81 and length is in meters.

I think I misinterpreted the apply force function. I thought it applies gravity/acceleration and not a force (Newton) to the object. To implement our own gravity, we have to apply the same force that the gravity applies to the object. And thats gravity multiplied by the mass(F = m*a). N = kg * m / s^2. That should be 9,81 N per kg. So I think it makes sense that it works out. But I am not sure if the manually force gets applied the same way as from the gravity.

Iā€™m learning too. Itā€™s starting to make sense. Hereā€™s a discussion of gravity vs. force that corroborates your view.

It also appears that setLinearVelocity may not be an equivalent alternative because it canā€™t apply to a specific point such as center of mass. So to your point, perhaps a generalized applied acceleration equivalent to gravity would be:

// can numInstances be zero?
// either way, handle it with low runtime cost
// It may be prudent to extract mass and CoM into an array of arrays to avoid repeated getMassProperties
// use remainder of gravity not handled by the engine.
// here, engine would be -0.01 so the remainder is -9.8
const num = mesh.physicsBody.numInstances;
if (num == 0) {
    var mp = mesh.physicsBody.getMassProperties();
    mesh.physicsBody.applyForce( -9.8*mp.mass, mp.centerOfMass)
} else for(var i = 0; i < num; i+=1) {
    var mp = mesh.physicsBody.getMassProperties(i);
    mesh.physicsBody.applyForce(-9.8*mp.mass, mp.centerOfMass,i)
}

Edit: if CoM is local space and force is world space, will need to convert CoM from local to world coordinates.
Edit2: updated code per first edit and use supplied instance iterate function:

mesh.physicsBody.iterateOverAllInstances((body,i) => {
    const mp = body.getMassProperties(i);
    body.applyForce(-9.8*mp.mass, body.getObjectCenterWorld(i),i)
});

Or shorten to:

mesh.physicsBody.iterateOverAllInstances((body,i) => 
    body.applyForce(-9.8*body.getMassProperties(i).mass, body.getObjectCenterWorld(i),i));

For an array of meshes:

meshArray.forEach((mesh)=>
    mesh.physicsBody.iterateOverAllInstances((body,i) => 
        body.applyForce(-9.8*body.getMassProperties(i).mass, body.getObjectCenterWorld(i),i)
    )
)

For good measure, here is my attempt to use setLinearVelocity() instead of applyForce(). However, I donā€™t know if setting velocity directly will override constraints, or if the natural physics (versus using a force) is identical. Currently untested.

scene.onBeforePhysicsObservable.add( (eventData, eventState) => {
    const vel = BABYLON.Vector3.Zero();
    meshArray.forEach( (mesh) => 
        mesh.physicsBody.iterateOverAllInstances( (body, i) =>
            body.getLinearVelocityToRef(vel, i)
            vel.y += -9.8*eventData.deltaTime;
            // generically: vel.addInPlace(gvector.scale(eventData.deltaTime))
            body.setLinearVelocity(vel, i)        
        )
    )
})

Thank you for all your effort. I am testing the approach of setting the gravity manually with applyForce() at the moment. For me it behaves pretty naturally in different use cases.

The approach with the setLinearVelocity() also deserves some testing. I will try to implement and compare it and see if I can spot some differences.

1 Like

Iā€™m very interested in what you find out.

Note the applyFoce code calls getMassProperties() every frame, while the setLinearVelocity code creates a (temporary) Vector3 on every frame. It might be better to create a permanent Vector3 for this so itā€™s not repeatedly creating and garbage collecting that temporary Vector3. Doing that and I think the velocity code is much more efficient, which only matters if it works!

Iā€™m not sure if getMassProperties() returns a new object every call or if it returns the same object each time. Hopefully the same object.

Iā€™ve implemented a ā€œdvyā€ function and used it in physics observable. It seems to work very well.

However, Iā€™ve set all damping and material friction to zero but the pendulums still slow down. Some constraints have friction options (e.g. 6dof), but distance constraint doesnā€™t.

Where is the friction coming from?

I tried both variants. The applyForce() variant works best for me. I have set ā€˜_useDeltaForWorldStepā€™ in the HavokPlugin constructor to false. If I set it to true my rope starts to jump/shiver up and down a bit, mostly if it is nearly not moving. Approximately what happend here Havok Precision - #8 by birnie.

When I use setLinearVelocity() I have the jump/shiver problem with and without ā€˜_useDeltaForWorldStepā€™, but in a smaller scale.

My rope consists of 3 distance constraints with small spheres in between functioning as connectors. Maybe it has something to do with that.

Regarding the friction I have the same result as you. I tried playing with the friction and damping but was also not able to find out where the friciton is coming from :thinking: