Avoid triangle-testing when doing collision detection

I’m seeing expensive triangle-test collision checks even though 1) we have bounding boxes, and 2) the meshes aren’t even colliding yet.

Here’s a playground with two simple meshes. There’s not much to see, but if you open the Dev Tools, and run step(player()) in the console, the player box moves forward…

The interesting thing is what happens in abstractMesh._checkCollision. The stack looks like this:

collider._collide // per-triangle collision
abstractMesh._collideForSubMesh
abstractMesh._processCollisionsForSubMeshes
abstractMesh._checkCollision // we fail the bounding-box test

All meshes (player, npc, ground) have bounding volumes, so why are we doing per-triangle tests? How can we avoid it? Per-triangle tests are catastrophically slow with multiple complex meshes on mobile devices.

Actually, the fast collision check is done with the bounding spheres, and they do collide in your PG.

They collide with the ground, but even if you set checkCollisions = false on the ground they still collide as the meshes are close to each other. If you move them a bit apart, you will see that you don’t reach _processCollisionsForSubMeshes.

2 Likes

Sure, but in a real game, characters will get close. How do we stop them from bumping into each other, with just bounding volume checks?

I think games use mainly capsules for collision with characters(?), as it’s a better fit for an humanoid.

I know we also have capsules, at least for the camera (ellipsoid), but I don’t think we use them for other objects.

I guess we could also have some options to check with the bounding box and/or stop checking collisions at the bounding (box or sphere) level.

I don’t think this currently exists but @Cedric will know better than me.

[EDIT] I stand corrected, we already use ellipsoids for mesh collisions:

1 Like

I tried adding collision capsules as children of complex characters meshes… The idea is that those should be triangle-tested, instead of the complex ones. Doesn’t work well so far…

Adding them as parents solves some issues, but causes others. I’m out of ideas… going to sleep.

Maybe you can try using a physic plugin? I think they have their own collision primitives and should be optimized accordingly.

Also, let’s see if others have some ideas for you.

I think I found a good solution.

  1. When a character mesh is added to the scene, also add a collider mesh, at the same position.
    A cylinder works fine, and has fewer faces than a capsule. Anyway, the ellipsoid is what controls terrain negotiation, so the shape of the caps doesn’t matter. In fact, we can use tubes instead of cylinders to save even more faces!
  2. The collider doesn’t need to be part of the mesh hierarchy at all! It’s a separate mesh, named e.g. “collider:<mesh.id>”.
  3. To move the character, do:
const currentCollidedMesh = colliderMesh.collider.collidedMesh

// Move the collider, then update the character's position
colliderMesh.moveWithCollisions(...);
characterMesh.position = colliderMesh.position;

// Check if we bumped into anything
const newCollidedMesh = colliderMesh.collider.collidedMesh
if (newCollidedMesh && newCollidedMesh !== currentCollidedMesh) {
 // new collision
}

This may be helpful. Scroll down a little and you’ll see a table comparison of the different collision shapes each physics plugin uses. These are handled for you by using PhysicsImposter. I suggest ammo, as its 2-3x faster than cannon and has more features. Although, manually handling it has benefits too. Sometimes the abstractions just leave with a feeling of like, wtf am i even doing and just cause more mental overhead. Also, bjs supports collisions without an engine, which can be confusing because with physics enabled, there are 2 ways of doing it. Heres the table:

Also the process you described is similar to what happens with the physics plugins. The physics world object for ammo i think is called a ghost object, and you can even adjust the substep timing to run multiple physics ticks before you move your rendered objects

Thanks. I’ve been tempted to use physics on several occasions, but it seems like a big change at this stage in the project. I tried it early on, but ran into issues with things toppling over, which never got resolved properly. Also the performance on mobile was a concern. But who knows? Maybe I’ll give it another try.