kripken / ammo.js

Direct port of the Bullet physics engine to JavaScript using Emscripten
Other
4.18k stars 559 forks source link

Please expose btTriangleIndexVertexArray #398

Open arcman7 opened 2 years ago

arcman7 commented 2 years ago

If I'm understanding everything correctly, this would allow us to pass in massive buffers that are filled with vertex data. This would unlock using massive open world maps with ammo js! As of now, I run out of memory well before all the the individual calls to btTriangleMesh.addTriangle(triPoints[0], triPoints[1], triPoints[2]); ever finishes for a model with 200k + vertices; and yet at the same time I'm allowed to load in a heightmap with 1480 x 1480 subdivisions passing in the data via Ammo._malloc? It seems to me ammo js would be perfectly capable of handling this if only it were exposed.

willeastcott commented 2 years ago

Yeah, PlayCanvas calls addTriangle here. For large environments, this can be very slow. It'd be great to have a faster mechanism for specifying the collision mesh geometry.

DennisSmolek commented 2 years ago

You don't want to do this...

A heightmap is essentially a Plane so much easier on the memory. See: https://rapier.rs/docs/user_guides/rust/colliders/#heightfields

You should try and use the smallest, most efficient method for the collision detection. There are a lot of ways to do this but realize when you test you'll have to run a collision test over EVERY triangle in the mesh vs EACH object you want to compare.

For many player objects, they use their own raycasters and dont rely on the physics engine for all sorts of reasons: https://gameworksdocs.nvidia.com/PhysX/4.1/documentation/physxguide/Manual/CharacterControllers.html

If you cant do this, use a subdivision method like quad trees or better yet use BVH.

This would let you do a smaller pass and maybe do a test against the specific triangles if you need to..

Something like VHCAD would work https://github.com/kmammou/v-hacd This Lib by Don McCurdy shows a method to create a shape for Cannon.js

BTW Rapier has a JS version and we're working on getting the VHCAD WASM wired up as well (not in rapier JS yet)

Will be over at https://github.com/pmndrs/react-three-rapier

The docs for Ammo and bullet really surprise me with how popular they are

arcman7 commented 2 years ago

Something like VHCAD would work https://github.com/kmammou/v-hacd This Lib by Don McCurdy shows a method to create a shape for Cannon.js

This is awesome. Thank you so much!

BTW Rapier has a JS version and we're working on getting the VHCAD WASM wired up as well (not in rapier JS yet) Will be over at https://github.com/pmndrs/react-three-rapier

This looks really exciting and I'd love to get a sense of performance benchmarks against ammo.js. Ultimately I would love to be able to use a babylon.js integration with rapier once the WASM api is up and running or if the performance gains against ammo.js are already there and it makes sense for me to start making the switch.

The docs for Ammo and bullet really surprise me with how popular they are

It's been a nightmare for me. But it's paid off more or less.

arcman7 commented 2 years ago

@DennisSmolek Can we revisit this

You don't want to do this...

Even if I don't want to do this for the world terrain mesh, exposing this interface would still speedup adding smaller but still detailed meshes into the ammo js physics world. Having to instantiate an instance of btPoint three times for each triangle still produces an incredible amount of overhead. In fact, I think it's this method of adding points to Ammo js that causes of a lot of the memory issues I've seen.

Correct me if I'm wrong, but adding large amounts of vertices in one function call momentarily raises the memory usage of ammo by a significant amount, but once the object has been fully passed in, the memory is released. If this is the case, then JS developers really could be getting more use out of Ammo js since it's the initial overhead that causes the OOM error in most cases, not the actual large count of vertices once it's been loaded.

MackeyK24 commented 2 years ago

you mean implementing the whole class btTriangleIndexVertexArray

I dunno about this one cause i dont know for sure how to implement all the constructor properties in ammo.idl

and more importantly how to pass them from javascript.

arcman7 commented 2 years ago

you mean implementing the whole class btTriangleIndexVertexArray

I dunno about this one cause i dont know for sure how to implement all the constructor properties in ammo.idl

and more importantly how to pass them from javascript.

So it's not a matter of just exposing it in the idl?

MackeyK24 commented 2 years ago

Mainly it is just exposing it the in ammo.idl but how you pass the pointers to the data is the thing.

I am going play with this for a bit... lets at least get the idl setup then we can fart around with how to wrap the pointers to the data for Ammo.js

arcman7 commented 2 years ago

Mainly it is just exposing it the in ammo.idl but how you pass the pointers to the data is the thing.

I am going play with this for a bit... lets at least get the idl setup then we can fart around with how to wrap the pointers to the data for Ammo.js

Sounds good - I'll reference to one your prs that made similar changes to the ammo.idl file

DennisSmolek commented 2 years ago

Even if I don't want to do this for the world terrain mesh, exposing this interface would still speedup adding smaller but still detailed meshes into the ammo js physics world.

So this makes sense and I’m honestly not sure regarding the function call itself, but I’ve made INSANE calls with things over the years so I’m not worried there.

my concern and warning was against your ultimate use case with using a mesh with that many faces as a collidable object..

(AFAIK) The standard way to run the test is at least one ray per face scanning the universe, and as this is JS it’s sequential, and if it’s a standard loop object and not a ground plane, it’s going to blow stuff up.

I’ll use rapiers docs because they explain an alternative a bit better: https://rapier.rs/docs/user_guides/rust/colliders/#compound-shapes

arcman7 commented 2 years ago

Mainly it is just exposing it the in ammo.idl but how you pass the pointers to the data is the thing.

I figured we'd just copy what's being done with the btHeightfieldTerrainShape:

  const ammoVertexData = Ammo._malloc(
    4 * numberOfRows * numberOfCols
  )

This might mean making slight modifications to the btTriangleIndexVertexArray class. I'll take a look in a few days.

arcman7 commented 2 years ago

@DennisSmolek

I’ll use rapiers docs because they explain an alternative a bit better: https://rapier.rs/docs/user_guides/rust/colliders/#compound-shapes

This will automatically create a compound shape composed of multiple convex meshes obtained from the approximate convex decomposition of the triangle mesh (or polyline in 2D) using the VHACD algorithm.

Okay that's awesome. I tried to use the VHACD algo as a plugin with blender and had no success. I gave up after reading that people were not getting any sort of stable results from the VHACD algo. At least with the implementation they were using.

Recently I went into blender just to split apart a model into a bunch of individual convex hulls, because creating a convexhull with the original monolith model would not result in the correct shape. Its a tree, and each branch and each twig had to be split into its own set of vertices. Does Rapiers ColliderBuilder::convex_decomposition(vertices, indices) solve this for me?

Would using this on a large terrain mesh produce an approximate shrink-wrapped mesh as well? I don't think I would use it this way, but I'm wondering what are the limits of it's usage?

arcman7 commented 1 year ago

If I'm understanding everything correctly, this would allow us to pass in massive buffers that are filled with vertex data. This would unlock using massive open world maps with ammo js! As of now, I run out of memory well before all the the individual calls to btTriangleMesh.addTriangle(triPoints[0], triPoints[1], triPoints[2]); ever finishes for a model with 200k + vertices; and yet at the same time I'm allowed to load in a heightmap with 1480 x 1480 subdivisions passing in the data via Ammo._malloc? It seems to me ammo js would be perfectly capable of handling this if only it were exposed.

Something has changed in the Ammo.js build that Babylon.js uses, for whatever reason now I can load in a triangle mesh shape with over 500k vertices no problem, just takes ~10~ 20 minutes to load lol.

suddenly4 commented 1 month ago

If I'm understanding everything correctly, this would allow us to pass in massive buffers that are filled with vertex data. This would unlock using massive open world maps with ammo js! As of now, I run out of memory well before all the the individual calls to btTriangleMesh.addTriangle(triPoints[0], triPoints[1], triPoints[2]); ever finishes for a model with 200k + vertices; and yet at the same time I'm allowed to load in a heightmap with 1480 x 1480 subdivisions passing in the data via Ammo._malloc? It seems to me ammo js would be perfectly capable of handling this if only it were exposed.

try may be anoter methode (Bvh include) for all mesh: new Ammo.btBvhTriangleMeshShape(). try may be btCompoundShape() and after add to world - .addChildShape() / .removeChildShapeByIndex()