Possibly a collision detection bug (BabylonJS built-in collisions)

Hi everyone!

I have noticed an inaccuracy in the collision detection system in a scenario when meshes bounding boxes are overlapping (although meshes itself are not).

So I have such a hexagonal grid composed of instanced hexagon meshes with enabled collision detection.

One can throw a ball onto the grid and when it collides with a grid tile it should destroy the tile. The ball is moving with the help of ballMesh.moveWithCollisions(vector) method. In general, everything is working as expected, except a few cases when the ball collides with a tile not at its center, but closer to a neighbour hexagon tile.

Here is a gif which illustrates the issue Iā€™ve just described:
collision-inaccuracy

My guess this is happening because of overlapping bounding boxes:

I was looking into collision detection code and it looks like bounding boxes are only used to limit meshes and actual collision detection is happening against actual mesh shape. Thatā€™s why Iā€™m confused with this behaviour and it seems to be like a bug. Although, might be Iā€™m just not getting correctly the code behind collision detection system.

Any help/insight on this topic is highly appreciated.

The final and most important bit of this topic - link to the playground repro - https://www.babylonjs-playground.com/#KJRQM7#14 (press ā€˜Spaceā€™ to throw a ball, green cube acts as gunsight)

1 Like

Hi Jsdream. What a wonderfully thorough post you have written! Fantastic!

What if I saidā€¦ the ā€œcollidersā€ for this type of collision systemā€¦ is not the mesh shape, nor the boundingbox-extends? What ifā€¦ it were an ellipse/sphereā€¦ whose (half-)size is stored in anymesh.ellipsoid? That would be a surprise for you, huh? :slight_smile:

https://www.babylonjs-playground.com/#KJRQM7#15

And there they are, the green ellipsoid collidersā€¦ sized and displayed via two badly-coded-by-wingnut functions in lines 2-52 (called overloads). Those green ellipsoids are temporary ā€œvisualizersā€ stored in a meshā€™s .ellipsoidMesh propertyā€¦ which is a property I just add myself. Tools in the playground ā€œInspectorā€ may be able to display these collider ellipsoids, too. I havenā€™t checked real well. I have always used these two junky funcs I made. :slight_smile:

I also added freecam mousewheeling in lines 72-103. Someday weā€™ll code a core freeCameraWithWheelControlā€¦ for use in camera.inputs.

Lines 146-148 is where I call the two ā€œellipsoid viewer helper funcsā€ā€¦ on each blockMesh. Line 147 - blockMesh.setEllipsoidPerBoundingBox(scene); might not be needed. BJS often sets .ellipsoid size == mesh boundingbox-extendsā€¦ automatically (as best it can).

(Thereā€™s also anymesh.ellipsoidOffset = anyvector3ā€¦ for offset-positioning the ellipsoid collider on any mesh, if ever needed. It is sometimes used to raise/lower cam-viewā€¦ for gravity-active ground-skidding freecams.)

Andā€¦ one other important thingā€¦ which you may not ever need. engine.collisionsEpsillon ā€¦ a float value that determines what collide-angle is a ā€œdead-stopā€ and what collide-angle is a ā€œglance-offā€.

But the main thing hereā€¦ is showing you the shape of genuine colliders (for this type of non-physics-engine colliding). I think you now understand WHY some of your ā€œedgeā€ shots are missing the intended targets, and instead, colliding with the wrong targets. Itā€™s all about the collider shapes, eh? The more above-the-board that the shot is fired-from, the less chance of missed collisions.

There IS bounding-box type of colliding (intersecting) available, though.

Look at THIS classic playground - carefully: https://playground.babylonjs.com/#KQV9SA#0 IntersectsMesh (precise or loose) and intersectsPoint. Pretty good collision detect. Perhaps precise would work perfectly for you.

The colliding system you are trying to useā€¦ was originally designed for simple FPS gamesā€¦ freeCameras colliding with mesh obstacles. MoveWithCollisions is a little bit of a cheater. It allows mesh to collide with other mesh (ellipsoids-only, not boundingBoxes/intersectsMesh). But, like all cool tools in BJS, try anything with everythingā€¦ its part of the fun. :slight_smile:

If you DO change to an intersectsMesh systemā€¦ you will no longer have .moveWithCollisions() availableā€¦ at least i donā€™t think so. All .checkCollisions = true/false will no long be used, either.

Intersecting is not the same as collidingā€¦ butā€¦ intersecting works fine for SOME stuff, as you can see by that last playground. It might work for you. Iā€™d sayā€¦ stay with ā€œpreciseā€. Butā€¦ even thenā€¦ the shape, and the close-proximity of your meshesā€¦ might cause trouble for intersectsMesh().

There is one other possibility. For all your hexagonsā€¦ add a ā€œtop capā€ to each oneā€¦ a real THIN hexagon atop the thicker ones. Then put a .checkCollisions on THAT. (a few more meshes, but what the heck?) :slight_smile: That top-cap collider will be REALLY flat and near-full-coverage circularā€¦ and it MIGHT prevent the missed edge collisions. Remember that you are allowed to fully adjust the vector3 value of mesh.ellipsoidā€¦ like mesh.ellipsoid.multiplyInPlace(new BABYLON.Vector3(1.1, 1.0, 1.1)); (expand the x and z size of mesh.ellipsoidā€¦ 10 percent diameter.) ANY adjustment to mesh.ellipsoid size is allowed, and donā€™t forget the .ellipsoidOffset to raise/lower the colliderā€™s height. Possibilities. :slight_smile:

As a possible alternative to top-capping, I wonder what would happen if you raised all the blockMesh collidersā€¦ (mesh.ellipsoidOffset.y += somefloat)ā€¦ 1/2 height of each blockMesh. hmm. They might protrude too much, and disallow near-edge shots on far-away tiles. But thenā€¦ set mesh.ellipsoid.y = .1 (real flat). hmm. Essentially, move the collider up to the top of the tile, and then smash it flat-as-a-pancake. :slight_smile: Thatā€™s something to try. Probably, no colliding will happen when shooting-at the SIDES of tiles after that (thru a hole left by a removed tile). (likely a good thing)

If you want green mesh.ellipsoidMesh to dispose when tiles dispose, add mesh.ellipsoidMesh.dispose(); just before line 169.

Ok, thatā€™s all I know. Stay tuned for more ideas/options. I hope I have been helpful. :slight_smile: Perhaps we could/should move this thread/topicā€¦ to the Questions & Answers sub-forum? shrug

Hi Wingnut! Thank you for as always a detailed response.

Youā€™re saying that ellipsoid colliders are being used on both colliding meshes, right? Although your explanation sounds to be reasonable, are you sure thatā€™s really how native BabylonJS collision system works?

The reason why Iā€™m asking is that when I was learning about the collisions system Iā€™ve stumbled upon this post by @Deltakosh which states that ellipsoid is used only on the mesh being moved and vertices are used on a mesh the moving mesh is about to collide with.


Here is the topic: moveWithCollisions issue - Bugs - HTML5 Game Devs Forum

1 Like

Yeah, you/thatā€¦ could be correct. Iā€™ve never studied moveWithCollisions to see how it does collide-testing for the moved item.

But, I did some moveWithCollisions ā€œbarrel testsā€ in a series of playgroundsā€¦ here: https://www.babylonjs-playground.com/#WWCK0#54 - wasdqe keys active on left barrel, shifted WASDQE keys active on right barrelā€¦ and I think mouse-dragging is active, too. (SOME basic rotation testing is also in that series of PGā€™s, but just some simple dragā€™nā€™drop on a tri-grid, so still mostly just position testing.)

It appears that both colliders are using ellipsoid, but it might be wise to find an onCollide event to monitorā€¦ while playing with the barrels or with your playground.

The testing started well-before #54 in the WWCK0 series, and likely continues beyond #61, so feel free to tour ALL of that WWCK0 series of playgrounds. Myself and another userā€¦ maybe @Arteā€¦ were deep into ellipsoid learning back then, and studied it hard, but then forgot anything we learned there. :smiley:

Good topic-find, JSD. I need to read it.

I THINK I am seeing glance-off when I drive these barrels into each otherā€¦ and I think glance-off (climb-over, dive-under, slide-around) requires that both colliders be ellipsoids. Letā€™s listen for more wisdom/comments about that, and/or do some deeper research.

Iā€™ll get a cup of coffee and then start sniffinā€™ around in source code and old forum searchā€¦ see if I can find some more info and get a little more educated on this subject.

@jsdream: You are correct. The collision engine will use an ellipsoid for the moving entity (camera or mesh) and will use geometry (vertices) on the colliding meshes.

I was not able to repro the issue on your playground. Can you position the camera on a place where just hitting space will cause the issue?

The collision system is fast but a bit painful to debug :smiley:

Hi @Deltakosh! Thank you for bringing your attention to this topic. :blush:

Here it goes the playground with the positioned camera. Now you should be able to reproduce by simply hitting ā€˜Spaceā€™.

https://www.babylonjs-playground.com/#KJRQM7#17

Bug found!

will be fixed in next nightly :smiley:

2 Likes

Great to hear that, Master! :muscle:

Iā€™ll mark this topic as resolved after I test the fix on my side :wink:

Thanks!

Should be live in a hour or so

Just tested the fix in my project and meshes colliding as expected now.

Thank you very much for such a quick fix, David!

Also, thank you again, @Wingnut, for spending your time trying to help me out :wink:

2 Likes

Nice job, guys! Congrats on the bug find/report/fix! (and I was able to learn things, too - excellent)

JsDream gets his ā€œI contributed to BJS Coreā€ certificate and shoulder patchā€¦ ALRIGHT! (hi-5)
(he might have already gotten one or two in the past, though) :slight_smile:

It comes with a year membership at The Bug Wranglerā€™s Spa, too! Rockinā€™!

Soā€¦ waitā€¦ something isnā€™t right with that claim. If that is true, there is never a need to set .ellipsoid or offsets on ANY ā€œobstacleā€? ONLY needed on freecams and moveWithCollision mesh?

Why does that sound so strange to me? :confused: (if anyone feels like commenting - please do) Thereā€™s tons of things I donā€™t know about collisions, yet. (Like WHEN does something get a .collider?)

I need to studyā€¦ thatā€™s all there is to it. :slight_smile: Sorry about sending you on a ā€œgoose chaseā€, JsD. I said wrong thingsā€¦ accidentally lead you astray. hmphā€¦ Wingnut incompetency rises again. :confused:

1 Like

Hey @Wingnut!

Just want to comment on this:

Soā€¦ waitā€¦ something isnā€™t right with that claim. If that is true, there is never a need to set .ellipsoid or offsets on ANY ā€œobstacleā€? ONLY needed on freecams and moveWithCollision mesh?

Thatā€™s right and the ellipsoid is only needed either for a camera and meshes being moved with moveWithCollisions method.

All other meshes which are supposed to take part in the collision detection should only be marked with mesh.checkCollisions = true and setting an ellipsoid for them wonā€™t have any effect until you start moving those meshes with moveWithCollision method.

As for .collider it is being created for a mesh when you call moveWithCollisions on it.

public moveWithCollisions(displacement: Vector3): AbstractMesh {
        var globalPosition = this.getAbsolutePosition();

        globalPosition.addToRef(this.ellipsoidOffset, this._meshCollisionData._oldPositionForCollisions);
        let coordinator = this.getScene().collisionCoordinator;

        if (!this._meshCollisionData._collider) {
            this._meshCollisionData._collider = coordinator.createCollider();
        }

        this._meshCollisionData._collider._radius = this.ellipsoid;

        coordinator.getNewPosition(this._meshCollisionData._oldPositionForCollisions, displacement, this._meshCollisionData._collider, 3, this, this._onCollisionPositionChange, this.uniqueId);
        return this;
    }

Then it is used for collision detection with other meshes.

As far as I understood the main magic of collision detection system happens in _testTriangle method of the Collider object.

Cheers!

1 Like

Excellent report, thanks for legwork on that. I had some serious misconceptions about how that system works.

Hi there

I got the following problem:

in short: My meshes are colliding on boundingBoxes (using mesh.intersectsMesh(otherMesh) rather than the actual meshes.
I saw that in @jsdream 's example the collision doesnā€™t depend on the boundingBox,( but rather on the edges?), but I canā€™t figure out why exactly? Does this only work with moveWithCollisions()?

As answered by DK on the linked thread: Move With Collisions will impersonate the mesh with an ellipsoid and use to collisions with other meshes so it will be more precise:)