Get Normal upon Collision

I’m making a 3d game using ‘moveWithCollision’ to move the player. This works as I would expect; the player moves and is prevented from clipping through walls. However, my player keeps on building speed even while colliding. Instead I would like the player to bounce against the wall. This is fine, I can use some old physics formulas to get the resulting velocity vector.

Problem is I need the normal of the wall I am colliding against to calculate this vector. I have tried using ‘getFacetNormal(0)’ inside ‘onCollideObservable’ to get the normal of the mesh, but this doesn’t always work as the facet being collided isn’t always the 0th index. It seems there isn’t a way to get the ‘faceId’ like in ‘PickingInfo’ either. What can I do? Is FacetData even the answer to my problems? I suppose I could shoot two raycasts on both sides of the player to get the normal, but that feels sloppy. Please help!

That’s what I would do but I’m not familiar with the collision system. Let’s see if others have some other solutions about this.

…and welcome aboard!

@RaananW will know

A mesh will has a reference to the collider that is used to calculate collisions for the current scene. The collider (mesh.collider) has quite a few pieces of information that you might find interesting, the most interesting for you would be the collision point ( collider.intersectionPoint) which will return the collided point in local coordinates.

There is no normal information, but you know your position, you know the collided position, you can use this information to calculate what you need :slight_smile:

BTW, you can play with the collision parameters to get the bounce out-of-the-box, maybe you can explain exactly how you expect the collider to work and we can try helping with that as well

Thank you Raanan. The mesh.collider object certainly did help.

Initially, I thought I could take the difference from intersectionPoint and the player’s origin to get the normal (since my player’s collider is a sphere, the point of collision should always be tangent). However, I encountered two problems:

  1. intersectionPoint is scaled differently than my players coordinates (I do not know how or why)
  2. I don’t have the player’s position at the moment it collided. Instead, all I have is the resulting position after moveWithCollision has already been resolved.

Luckily, I discovered a property called collider._displacementVector, which by normalizing gets me the normal of the wall. I assume this property is meant to be private, but it works for me so I can’t complain. :stuck_out_tongue:

The “secret” is in this function that is being executed after a collision was detected:

   public _getResponse(pos: Vector3, vel: Vector3): void {
        pos.addToRef(vel, this._destinationPoint);
        vel.scaleInPlace((this._nearestDistance / vel.length()));

        this._basePoint.addToRef(vel, pos);
        pos.subtractToRef(this.intersectionPoint, this._slidePlaneNormal);
        this._slidePlaneNormal.scaleToRef(this._epsilon, this._displacementVector);


        this._slidePlaneNormal.scaleInPlace(Plane.SignedDistanceToPlaneFromPositionAndNormal(this.intersectionPoint, this._slidePlaneNormal, this._destinationPoint));

        this._destinationPoint.subtractToRef(this.intersectionPoint, vel);

All of those internal values are calculated during a collision test with the mesh.

And as there is no real “private” direct members in javascript, you can technically use it :slight_smile: Just don’t tell typescript you are doing it. Another small thing is that private members are not guaranteed to stay backwards compatible. Having said that - the collision system hasn’t changed since version 2 or so, I believe it will stay the same in the near future.

1 Like