Unexpected behaviour of body.applyForce()

I’ve made my own vehicle physics with cannon-es.js and for some reason

body.applyForce(worldSpaceForce, localWheelOffset);

applies unexpected forces, making the vehicle jitter and even launch into the air when position.z gets a few units away from 0. I know the force I apply is correct because

body.applyLocalForce(body.vectorToLocalFrame(worldSpaceForce, new Vec3()), localWheelOffset);

works just as expected. I was wondering if anyone knows why the second way works and the first not.

This is just a guess, do not assume it is correct:

According to the documentation:

  • applyForce affects not only the force, but also the torque; and the force is applied to a point relative to the center of mass of the body
  • applyLocalForce affects only the force and it is applied to a point relative to the local coordinate system of the body

So, changing the vector of the force from world to local coordinates is not sufficient.

Then why does it work? Did I not understand you correctly? applyLocalForce() makes the body turn when steering the front wheels so it must affect torque too (at least it works like this in my case).

I checked the source code, and applyLocalForce actually uses applyForce, so it also affects the torque, as you have correctly observed.

Here is the source code (and it appears the second parameter if applyLocalForce is not the same as in applyForce, otherwise it would not need transformation):

applyLocalForce(localForce: Vec3, localPoint: Vec3 = new Vec3()): void {

    if (this.type !== Body.DYNAMIC) {
      return
    }

    const worldForce = Body_applyLocalForce_worldForce
    const relativePointWorld = Body_applyLocalForce_relativePointWorld

    // Transform the force vector to world space
    this.vectorToWorldFrame(localForce, worldForce)
    this.vectorToWorldFrame(localPoint, relativePointWorld)

    this.applyForce(worldForce, relativePointWorld)
  }
1 Like

Thank you for your time! I should have checked the source code myself but thought it would be to complicated :sweat_smile:. The problem was that localWheelOffset must be offseted in world space, not local space. So the working equivalent of the second way is:

body.applyForce(worldSpaceForce, worldSpaceWheelOffset);

In my code it is something like this:

vehicle.applyForce(force, vehicle.vectorToWorldFrame(localPoint || new Vec3()));

I really couldn’t understand it until now, so thanks again!

1 Like