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:)