playcanvas / engine

JavaScript game engine built on WebGL, WebGPU, WebXR and glTF
https://playcanvas.com
MIT License
9.69k stars 1.36k forks source link

Multiple Mesh Colliders of Different Scales don't behave properly #3062

Open CaseyHofland opened 3 years ago

CaseyHofland commented 3 years ago

When using differently scaled mesh colliders of the same mesh, only 1 instance of the collider will be used on all entities.

As LeXXik put it (forum username): "Placing a mesh into the physics world is a computationally expensive operation - the engine generates an Ammo compound shape from a number of bvh triangle meshes, one for each mesh instance. Once generated the trimeshes then get cached for future re-use. As a result, when you use the same mesh for another collider, the trimeshes are taken from the cache, instead of generating new ones."

Provide as much information as possible. Include (where applicable): The forum discussion

Example:

Steps to Reproduce

  1. Add a mesh and ammo to your project.
  2. Create 2 or more entities of different scales.
  3. Give them both the same mesh collider.

Result: all colliders have the same scale. Desired: all colliders have their own scale.

yaustar commented 3 years ago

Martin had a quick look and it seems like it will need dedicated time to fix rather than be included in a bug blitz

mvaligursky commented 3 years ago

We could consider to upgrade the Ammo version, and use btScaledBvhTriangleMeshShape API which allows to use btBvhTriangleMeshShape with different scale without having to have separate btBvhTriangleMeshShape instance. This was added in Sept 2008 it seems .. not sure why its not in our Ammo version yet. https://github.com/kripken/ammo.js/pull/240

Otherwise we can implement the system using the duplication.

yaustar commented 3 years ago

Does it still need to be uniformly scaled?

yaustar commented 1 year ago

Random thought, I wonder if instead of using the mesh.id, we can construct a string of the mesh.id and scale here (eg '' + mesh.id + sx + sy + sz: https://github.com/playcanvas/engine/blob/a596c8b7881acbb318bca3f8b1b727aad62c3ecc/src/framework/components/collision/system.js#L318

That would allow different sized meshes to be built and cached using the same model data. It would mean an extra cost of calling _getNodeScaling to get the final scale on each look up though 🤔

leonidaspir commented 1 year ago

That's what we did in Solar Tools by patching the engine. And in addition we provided an option to round the scale to the nearest value set by the user. So for example he could group various rock objects to 0.75, 1.0, 1.25 scale variants and produce just 3 cached mesh shapes.

willeastcott commented 1 year ago

@yaustar Yeah, something like that. Or create a hash from the scale.

jbromberg commented 1 year ago

I've implemented something similar.

export const getScaleUniqueMeshId = (meshId: number, scale: Vec3): number => {
  // Removes scale values from meshId if present
  const rawMeshId = Math.floor(meshId);

  const { x, y, z } = scale.clone().abs().round();

  return Number(`${rawMeshId}.${x}${y}${z}`);
};