📜 ⬆️ ⬇️

Browser physics simulation



In this article I want to give a description of existing solutions for creating applications with physics simulation, compare their performance and the tools provided.

Introduction


The article will consider the following engines:

Ammo.js
Cannon.js
Oimo.js
box2dweb
Unity3d webgl

The main goal was to choose the most productive, convenient and lightweight engine for developing games and applications using physics simulation.

Ammo.js


It is a port of the Bullet physics engine in javascript using the Emscripten compiler and, according to the developers, has almost identical functionality. The functionality of Ammo.js is really extensive. To work with it, you will need a separate library for visualization. Most often used by Three.js. In this case, each redraw cycle will have to manually synchronize the position and rotation of each object on the scene with its physical model, the engine does not automatically do this.

As for performance, it is not too high, but there will be no noticeable fps drawdown in most projects.

The API can sometimes be quite confusing and the documentation doesn’t really help.
In general, a very good tool that continues to evolve and refine.

Cannon.js


Cannon.js is an open source lightweight physics engine. Unlike the previous one, it was originally written in javascript and allows you to use all its features and optimizations. In fact, it is difficult to say whether this is a plus or a minus, since compiled code can be much more efficient than writing from scratch. Nevertheless, cannon.js compared with ammo.js is considered more compact, more productive, and also easier to understand, but at the same time it does not have so many functions. In practice, their performance is often about the same.

The process of working with the engine is quite simple:

// Инициализируем движок var world = new CANNON.World(); world.gravity.set(0, 0, -9.82); // Устанавливаем гравитацию (движок использует единицы СИ) // Создаём объект и добавляем его на сцену var radius = 1; var sphereBody = new CANNON.Body({ mass: 5, position: new CANNON.Vec3(0, 0, 10), shape: new CANNON.Sphere(radius) }); world.addBody(sphereBody); var fixedTimeStep = 1.0 / 60.0; var maxSubSteps = 3; // Запускаем цикл симуляции var lastTime; (function simloop(time){ requestAnimationFrame(simloop); if(lastTime !== undefined){ var dt = (time - lastTime) / 1000; world.step(fixedTimeStep, dt, maxSubSteps); } lastTime = time; })(); 

The work also requires a third-party graphic library, and each cycle of drawing will have to manually move the corresponding object on the scene to the location of the physical object.

 mesh.position.x = body.position.x; mesh.position.y = body.position.y; mesh.position.z = body.position.z; mesh.quaternion.x = body.quaternion.x; mesh.quaternion.y = body.quaternion.y; mesh.quaternion.z = body.quaternion.z; mesh.quaternion.w = body.quaternion.w; 

At the moment, the engine practically does not develop, the last activity in the project repository more than 2 years ago, and at that time the engine was just beginning to develop, so in some places it may not be worked out.

Oimo.js


Oimo.js is a version of the OimoPhysics engine rewritten in pure javascript. Compared to other solutions, it has very good performance and accuracy, however, it only supports primitive geometry (cubes and spheres). Included with Babylon.js - a framework for rendering 2D and 3D graphics, so no additional libraries will be required.

 // Инициализируем движок world = new OIMO.World({ timestep: 1/60, iterations: 8, broadphase: 2, worldscale: 1, random: true, info: false, gravity: [0,-9.8,0] }); // Добавляем физические объекты var body = world.add({ type:'sphere', size:[1,1,1], pos:[0,0,0], rot:[0,0,90], move:true, density: 1, friction: 0.2, restitution: 0.2, belongsTo: 1, collidesWith: 0xffffffff; }); var body = world.add({ type:'jointHinge', body1: "b1", body2: "b1", }); world.step(); // Копировать позицию и вращение так же нужно каждый цикл отрисовки myMesh.position.copy( body.getPosition() ); myMesh.quaternion.copy( body.getQuaternion() ); 

The big drawback of the engine is not very high quality documentation, but the developers continue to work on it.

At the moment, the engine continues to evolve.

box2dweb


box2dweb is the javascript box2d port. As the name implies, it specializes in the simulation of 2D physics. Despite this, box2dweb is quite a powerful tool that does not lag behind its 3D counterparts in the least. For example, the engine includes extremely convenient systems for collision detection and connection imitation (constraint).

As for performance, you need to try very hard to write non-optimal code so that fps sags appear.

One of the advantages is also worth mentioning the simplicity of the API and user-friendly documentation.

Unity3d


Unity3D is a popular cross-platform game engine. It includes a simple handy drag & drop editor and extensive tools for creating 3D content. The latest version of the engine for writing game logic supports C #.

Unity has a built-in physics simulation, using the built-in PhysX engine from NVIDIA. PhysX provides extensive functionality for simulating the physics of solids, liquids and tissues, it has very good performance, although many advantages are canceled when working on graphics accelerators not from NVIDIA. It is a very pleasant fact that since December 3, 2018 the source code of the engine is available under an open BSD-3 license, however the engine is too complicated to try to rewrite it for yourself or to understand its device, so the documentation will help you here.

In this list, Unity was, because there is an opportunity to build a project on it under WebGL. To do this, it is enough to select the appropriate item in the assembly settings.



Nevertheless, the WebGL version of Unity, due to its architecture (translation of code from C # to C ++ and further to JavaScript), has several problems with performance, memory consumption and performance on mobile devices, and it does not seem that developers are going with this something to do soon. Therefore, this option is not popular and I will not consider it in detail.

Performance comparison


Let's compare the performance of engines by the way they cope with handling collisions of a large number of objects. The browser used is Firefox 64.0.2 x64.
Enginefps when processing 100 objectsfps when processing 500 objectsfps when processing 1000 objects
ammo.js40-5025-2715-25
cannon.js30-4020-2515-20
oimo.js45-5535-4035-40

According to the test results, Oimo.js shows the best performance.

Of course, these results do not give an adequate assessment of performance, since they depend on many third-party factors, but a full-fledged study would require much more time and I did not set myself such a goal. In addition, it is noticeable that the performance of all engines being compared is rather small, so these solutions are suitable for writing not every game, but they are well suited for creating small demos.

Conclusion


In general, the choice of a specific engine depends on the task. If an easy-to-understand and easily mastered engine is required, Cannon.js or Oimo.js works well. If more functionality is required, it is better to use Ammo.js. In certain situations, if you do not need more performance, you can try using Unity.

Source: https://habr.com/ru/post/436192/