I am facing some unwanted collision behavior in some scenes. Such as being pulled in into a mesh and being stuck around a mesh.
Here is the PG link to an example scene Babylon.js Playground You can use WASD keys to move around.
If you go towards “Forward” ramp, you’ll see the sphere collides properly with the ramp. But if you go towards “Flip” ramp, which has flipped normals, it will sink in and get stuck there.
I’ll be very happy if you can help me devise a workaround for models with such normals.
The babylon collision system is constantly using the mesh’s (or to be more precise the submesh’s) normals to compute the collision. There is no flag to support flipped normals, but we can consider adding this if it is a case that is widely used. I’ll say this, however - this is (AFAIK) the first time someone asks about flipped-normals collisions, and the team is very occupied, so I am not sure when this can be implemented.
If you want the sphere to collide with both front and back normals meshes, the only way I can see is flip the normals right before computing the collisions, and returning them right after. It is an ugly hack, i know, and can be a bit more optimized if you save two normal arrays - flipped and not flipped. But this is really not an optimal solution for this.
Sorry, looking again at the code - it is using the positions array directly and not the normals. this might be a little trickier than I thought
Firstly, the gltf/glb has right handed coordinate system and BabylonJS coordinate system is left handed. So you need to set scene.useRightHandedSystem = true before importing. Else you have to consider negative z-scaling, which can cause unpredictable collision problems.
The main cause of the collision failure seems to be that the flipped mesh has inverted normals and also has a right handed coordinate system. Usually the triangles of gltf are counter-clockwise, while Babylons (left handed) are clockwise. So if you enable right handed conversion by scene, then the side orientation is and needs to be set clockwise and vice versa.
Accordingly the workaround that covers both cases would be:
Another thing is that you need to set measures of “player” collision body, that is defined by ellipsoid-property of mesh:
player.ellipsoid = new BABYLON.Vector3(1, 1, 1) // radius of 1
From my knowledge checkCollisions of meshA only takes effect if another meshB moveWithCollisions(). Therefore it would only make sense if another mesh moves with collision.
@Takemura I probably forgot saving after the movement direction fix, @RaananW thanks for doing it for me
It seems possible to solve the issue by using right hand system. However, it creates another issue. My application runs with user-uploaded models and it goes through all child meshes and processes them. If I apply material side orientation and flip normals, it breaks some of the meshes. If you compare this PG https://playground.babylonjs.com/#GFCVRL#2 with https://playground.babylonjs.com/#GFCVRL#1, you’ll see some meshes are inside out and collision system doesn’t work well.
Maybe if I could detect which meshes have flipped normals and which don’t, I’ll be able to use the solution for all possible meshes.
Have you found a solution to this? From the top of my head the approach I’d go is to check if the normals point towards the center of the model, (if the model is solid) in this case they’re flipped
I tried it but when the models are custom, terms center/inside/outside are sometimes being vague and inaccurate.
I’m trying to investigate _testTriangle method of Collider in my free time. I see there’s also a static value Collider.DoubleSidedCheck with default false. I set it to true after importing but didn’t work.
If I can pull off adapting the logic in _testTriangle to take the opposite normal into account I’ll create a PR. Any guidance on the method is welcome
This might also hurt performance. We could allow the dev to decide if they check against flipped normals, BUT the issue still remains - how do you know if the model’s normals are flipped
@carolhmj I tried your suggestion anyway, by a one-time recursion into the _testTriangle method by combining some tweaks (creating the triangle planes in different order of vectors; negating the normal’s sign or distance). No luck yet, must be missing something. But in any case, this will be an expensive solution in terms of performance as @RaananW says.