kripken / ammo.js

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

WebAssembly? #117

Open josephrocca opened 8 years ago

josephrocca commented 8 years ago

Sorry, this is very hypothetical, but I'm just wondering whether the "next generation" of Ammo.js could use WebAssembly to compile Bullet (almost) directly to a usable JavaScript module? I'm not exactly sure how WebAssembly works, so I am just naive and curious.

Apparently WebAssembly will hit browsers some time next year if all goes well. Here are some articles for those who haven't heard of it yet:

https://medium.com/javascript-scene/what-is-webassembly-the-dawn-of-a-new-era-61256ec5a8f6 https://medium.com/javascript-scene/why-we-need-webassembly-an-interview-with-brendan-eich-7fb2a60b0723

kripken commented 8 years ago

WebAssembly is basically a drop-in replacement for asm.js, so it will provide nothing new except for much faster parsing/startup. In the farther future, WebAssembly hopes to add some features like GC support, which might help with binding languages like Java and C#, but probably not for C++ and Bullet.

I'm curious in what way is current ammo.js not a "usable JavaScript module", in your opinion? If there are usability issues, we should fix those. ammo.js should basically provide an interface that looks just like a standalone module.

josephrocca commented 8 years ago

I didn't mean to emphasise the JS module part, sorry. My question was mainly based around potential performance improvements that WebAssembly could bring to Ammo.

I don't understand what the problem is with compiling Bullet to WebAssembly? It seems like this sort of application is exactly what asm, and now WebAssembly, is made for.

It will be used for performance critical code and to compile languages other than JavaScript (especially C/C++) to the web platform.

(from http://www.2ality.com/2015/06/web-assembly.html)

I think I may misunderstand something fundamental about asm/WebAssembly.

Thanks

kripken commented 8 years ago

WebAssembly will provide a big speedup in parse time/startup. But there isn't much room left for speedups in throughput after asm.js - it's already very close to full native speed, and much of the remaining disparity is sandboxing, which WebAssembly won't change.

However, WebAssembly will have less hacks in it, so it should be more consistently fast across browsers. And the startup improvement will be very large. So it is a big improvement, in those specific areas.

josephrocca commented 8 years ago

Oh! I didn't realise Ammo was already using asm.js! Sorry once again.

So why do people say libraries like Cannon.js, written in pure JS, are faster than Ammo.js? If Ammo is running asm.js, shouldn't it almost have the power of Bullet running natively?

kripken commented 8 years ago

I've never heard that cannon.js or anything else is faster than ammo.js. That sounds silly, since yes, ammo.js runs within a small factor of difference of native bullet, and there is no way that cannon.js beats bullet. Unless cannon.js is running on some very specific benchmark that bullet happens to not be optimized on.

Where did you see people saying cannon.js was faster?

josephrocca commented 8 years ago

I don't want to start a war here, but maybe this was referring to a pre-asm version of ammo (if there was one)? It's from an article back in 2012:

Performance: Ammo.js is a large library, and being an Emscripten port means there are no Javascript optimizations. There is a definite tradeoff between power and performance, but most games shouldn’t have an issue staying about 50 frames per second.

and in the conclusion section:

While a lot has improved for the world of Javascript physics there is still quite a bit to be wanted. box2dweb doesn’t support 3D worlds, Ammo.js can suffer from performance issues, and JigLibJS is affected by its API design and lack of functionality. Challengers such as Cannon.js and others which are 100% written in Javascript are beginning to appear, but none are yet ready to be widely used.

http://buildnewgames.com/physics-engines-comparison/

I'm sure I've read it other places too. Is this just a huge myth? Has anyone done benchmarks to compare Ammo against pure JS libs?

kripken commented 8 years ago

"no javascript optimizations"? perhaps they meant in older JS engines, where the size of the code limited optimization. But even in 2012, most engines should have been capable. Certainly today they are. Or maybe they meant something else - very strange comment.

Someone should do those benchmarks - should be easy to do. I might if no one else does. I would be shocked if ammo.js is not at least 2x faster than the closest regular-JS engine.

josephrocca commented 8 years ago

Maybe Chandler was talking about cross-browser performance (i.e. without asm)? I'd certainly love to see some benchmarks! I should have some spare time in a couple of weeks if you need a hand and haven't done it by then.

chandlerprall commented 8 years ago

I haven't benchmarked Ammo in a while, certainly was before asm was supported in more than experimental Firefox builds. I'm still turned off by Ammo's 1.41mb filesize, memory requirements, and necessity of another emscripten library to pass callbacks to Ammo functions.

@kripken I've wanted to do a cross-browser cross-engine performance benchmark for about a year now, let me know if you start one and I'd love to help out.

kripken commented 8 years ago

Regarding the file size, it's possible to make custom builds of ammo, defining just the parts of bullet that are needed, in the ammo.idl file. The full 1.41MB is just for the entire engine containing everything. Still, though, a handwritten JS engine will likely be smaller, although slower.

What do you mean by "another emscripten library to pass callbacks"?

Definitely lets collaborate on a benchmark! One thought I had was that at least for a cannon.js / ammo.js comparison, I would look if it is possible to take some cannon demo and just replace it with ammo. Not sure offhand if that would work though.

chandlerprall commented 8 years ago

Maybe the emscripten ecosystem has changed since I was messing with it, but there are a couple places in Bullet where you can subscribe to events (such as something colliding with a ghost body). In C++ these functions are passed via pointers and there is (or was) another emscripten file which needed to be included on the page to generate a "pointer" to the JavaScript function you wanted to pass a callback, and then that pointer was passed to Ammo.js. My goal with Physijs is to make the addition of physics to a Three.js scene as painless as possible for new users, and the additional file goes against that goal.

I'll start coming up with some benchmark & comparison points that can be well applied and share it with you. Very curious to see where the various engines land.

kripken commented 8 years ago

ammo.js is just a single file, no extra things needed, including for events etc. In general binding between the languages should be much improved now since the move to idl for defining the cross-language interface, perhaps the issue you refer to was something from before that transition.

kripken commented 8 years ago

I took a quick look at cannon.js demos, it doesn't look like the physics in the demos is abstracted enough out to make it an easy thing to drop in bullet (not a criticism, the code is very modular, just not to that extreme ;)

Probably better to make new benchmarks anyhow. Let me know if I can help with the ammo integration side.

josephrocca commented 8 years ago

Also very curious to see how the engines compare! @schteppe, your input would be valuable here I think. It'd be good to have some benchmarks focusing on systems with many constraints as well as the classic stacking stuff.

A few papers I've come across which might provide some inspiration for benchmarks:

kripken commented 8 years ago

I took one of the cannon.js demos and ported it to ammo.js, in this branch of my fork:

https://github.com/kripken/cannon.js/tree/to-ammo

Running demos/pile.html in master branch shows the demo using cannon.js, and in the to-ammo branch it uses ammo.js.

The results look almost indistinguishable, including frame rate, at least on my machine, and profiling it the explanation is that it's GPU bound anyhow. So this demo is not a good benchmark.

If there is a better cannon.js demo that can serve as a benchmark, we could port it - after I ported the CANNON.demo.js infrastructure, porting more demos should be easy.

While doing the porting, I noticed some things that might make a true apples-to-apples comparison hard:

        // Since we have many bodies and they don't move very much, we can use the less accurate quaternion normalization
        world.quatNormalizeFast = true;
        world.quatNormalizeSkip = 3; // ...and we do not have to normalize every step.

which means that in that pile.html demo I ported, cannon.js is solving a less accurate problem thatnBullet is. Perhaps Bullet also has ways to tell it to take shortcuts, I'm not sure.

josephrocca commented 8 years ago

I also get very similar frame rates, and also see a definite difference between the simulations. Would be good to see that scaled up to hundreds of objects, and maybe switch out spheres for boxes and triangle meshes.

Links for easy comparison: https://rawgit.com/schteppe/cannon.js/master/demos/pile.html https://rawgit.com/kripken/cannon.js/to-ammo/demos/pile.html

I guess ideally we'd have a simple abstraction layer/API that let us run the same script across multiple physics engines (a simpler version of this: https://en.wikipedia.org/wiki/Physics_Abstraction_Layer). But then, like you said, we've still got problems with parameter tweaking so that we're comparing apples with apples.

@schteppe and @chandlerprall will probably know more about the apples-for-apples stuff.

Worst case, we'd still gain some insight just by being able to run the same benchmark, manually playing around with the parameters and judging "by eye" which one performs better. Quantitative scoring would be awesome - not sure how it could be done though.

chandlerprall commented 8 years ago

In general, looking at the same demo in the different engines, they subjectively "feel" different. Maybe one is more precise (maybe related to the last point?), or maybe there isn't a "true" solution and each approximates reality differently, maybe better in some cases or worse in others.

This is absolutely true. It's possible to modify a single value ever so slightly in an engine and get very different results. The engines don't attempt to accurately model physics, just get an acceptable visualization. I don't think there's a need to test the visual results for the benchmark, only ensure everything is working as intended. I envision a small script that knows how to examine each type of world and render it accordingly, this would allow the simulations/tests to be setup and run visually but can be completely disabled for the actual benchmark. @kripken with the emscripten output, is it possible to examine the rigid bodies in Ammo's world and discover what type of object they are? Doesn't need to be performant.

Engines we should compare: Ammo, Cannon, Oimo, Goblin (full disclosure: it's mine). I'm not aware of any other decent / popular 3D physics engines for JavaScript. Even though Goblin is mine I'm not trying to set up to prove it's the best (would love if that were the case ^.^), want to see where it can be improved.

Still coming up with the benchmark ideas, but to start with:

  1. A stack of a large number of spheres - bottom one is static - the engines should have no problem maintaining a stable stack. The sphere-sphere collision detection is fast and unlikely any engine has a poor implementation, this would test the engine's ability to create/manage memory, update/integrate objects, and resolve constraints (contacts & friction).
  2. Same as above but multiple stacks, don't need as many spheres per stack. This is to test how the engines do with parallel constraint solving via islands (Goblin doesn't do this yet, don't know if Oimo does or not, should see noticeable improvement in Cannon & Ammo).
  3. Constraints. Lots of them. Some combination of hinges and point-to-point/socket constaints would do the trick (present in all four engines, easy to setup, representative of everything the engine needs to run for constraints).
  4. Ray casting. Doesn't look like Oimo supports this. I expect Ammo will destroy Cannon and Goblin here as neither have a bounding-volume-hierarchy broadphase, only SAP which is terrible at ray casting performance.
  5. Convex hull - collision. Complex geometry can be generated by a convex hull from a list of vertices - the minimum convex shape required to wrap all of the vertices. Oimo doesn't support this; Cannon can't generate this shape from a list of vertices but if you have the vertices & faces it can construct the shape.
  6. Convex hull - creation. only Ammo and Goblin have this.
  7. Compound shape collision, used to combine multiple simple shapes into a complex one. Appears only Goblin and Ammo have this.
  8. Concave-Convex collision. Not supported by Oimo. Cannon has TriMesh, Goblin has MeshShape, and Ammo has btConcaveShape (well, Bullet does). These can all be collided with convex geometry.
  9. Concave-Concave collision. Not supported by Oimo, I don't know if Cannon's TriMesh can collide with other TriMeshes. Bullet's btConcaveShape must be static and won't move, but Bullet has GImpact classes that allow for dynamic concave-concave collision. Goblin's MeshShape can collide with other MeshShapes
  10. Bounding volume hierarchy creation. I don't know how much the various engines expose so this may be difficult. Ammo, Goblin, and Oimo are able to construct an AABB BVH tree.
kripken commented 8 years ago

Sounds like a good plan for benchmarking!

I envision a small script that knows how to examine each type of world and render it accordingly, this would allow the simulations/tests to be setup and run visually but can be completely disabled for the actual benchmark. @kripken with the emscripten output, is it possible to examine the rigid bodies in Ammo's world and discover what type of object they are?

Yes, in the cannon.js demo conversion it does that, it looks at each body and translates it into a three.js mesh for rendering.

lo-th commented 8 years ago

oimo is the fastest on simple simulation, but miss some usfull object and methode is pure javascript. http://jsdo.it/cx20/uKB1

i hope you add terrain on next release of ammo ammo is strong with big data

like liquidfun for 2d

sasha240100 commented 7 years ago

In addition to this topic: my results of ammo.js + wasm

kripken commented 7 years ago

@sasha240100: interesting, thanks for the data.