Avoid sliding down slopes

moveWithCollisions causes meshes to slide down slopes when resting (i.e. zero displacement). This is due to gravity, and is expected - for steep slopes. But it would be nice to have a “friction” parameter that scales sliding, potentially to zero on gentle slopes.

It looks like the sliding displacement is calculated in Collider::getResponse. I tried scaling _slidePlaneNormal and _displacementVector, but it didn’t have any effect.

_getResponse(pos, vel) {
        pos.addToRef(vel, this._destinationPoint);
        vel.scaleInPlace(this._nearestDistance / vel.length());
        this._basePoint.addToRef(vel, pos);
        pos.subtractToRef(this.intersectionPoint, this._slidePlaneNormal);
        this._slidePlaneNormal.normalize();
        this._slidePlaneNormal.scaleToRef(this._epsilon, this._displacementVector);

        // scaling displacementVector has no noticeable effect (except when scaling to zero)

        pos.addInPlace(this._displacementVector);
        this.intersectionPoint.addInPlace(this._displacementVector);
        this._slidePlaneNormal.scaleInPlace(Plane.SignedDistanceToPlaneFromPositionAndNormal(this.intersectionPoint, this._slidePlaneNormal, this._destinationPoint));
        this._destinationPoint.subtractInPlace(this._slidePlaneNormal);
        this._destinationPoint.subtractToRef(this.intersectionPoint, vel);
    }

I expect it’s more involved than just scaling a vector. If I figure out a solution I’ll post a PG…

Alternatives:

  • Use a physics engine.
    No, it would break too many things. And it’s too slow on mobile.
  • Fudge gravity, e.g. scale gravity according to character speed.
    This does eliminate sliding, and also solves other issues, like allowing slow-moving characters to climb over curbs and up slopes. It has its own tradeoffs, and it’s a hacky solution anyway, but it has promise.

You may have a look how it is done in Character Controller - here and further down: BabylonJS-CharacterController/src/CharacterController.ts at 1d61d35164375a6d0ceb86f64cd679cd958c8b0f · ssatguru/BabylonJS-CharacterController · GitHub

How do you apply gravity? Do you add it to the displacement Vector when calling moveWithCollisions?

friction = 0.2

friction = 0.5

friction = 20 - full stop

Prototype.

2 Likes

Yes, I add it to the calcMovePOV call, then use the returned displacement with moveWithCollisions.

const GRAVITY = -9.807 / 60
const displacement = mesh.calcMovePOV(velocity.x, velocity.y + GRAVITY, velocity.z)
mesh.moveWithCollisions(displacement)

Possible solution above :arrow_double_up:

1 Like

That’s a pretty good solution. It’s essentially a “fudge gravity” approach, but only when in contact with the ground, rather than based on velocity. This is more correct, and solves the issue of slow-moving meshes being unable to overcome gravity on hills.

Edit: If direction is the character’s velocity, what is BASE_SPEED?

IMHO it solves the issue of sliding down slopes when frictionset to a high value

just the initial speed factor of the sphere which I chose randomly…

But why do we need a “speed factor” when we already have a velocity (direction)?

You may already know that velocity is the speed of the object moving in a direction so these terms are describing different properties of a moving object.

You could say gravity has a direction of (0, -1, 0) and initial velocity of 9.81 (on Earth).

I use BASE_SPEED as a multiplier in these very simplified examples of friction simulation, as a muliplier of the velocity to make the sphere fall slower so we can observe the friction behavior.

You should set it to 1/60 and multiply it with animationRatio every frame to get closer to the real world physics.