armory icon indicating copy to clipboard operation
armory copied to clipboard

[html5 (JS)] WASM Ammo.js + WebWorker

Open onelsonic opened this issue 4 years ago • 5 comments

Hi all, there is a way to speed up Armory3D when exporting to html5.

The speed up will come from the physic module. The physic module ammo.js can be used as a JS-compiled WASM module and sync physics info using a webWorker. The module then run in its own thread and the 3D objects properties are then updated using the webWorker. Meaning that for each frame there is no need to wait anymore for the physics to be calculated. (no slow FPS due to Physics) in theory : ![html5 (JS)] WASM Ammo.js + WebWorker Examples : with only Javascript Ammo.js with WASM Ammo.js + WebWorker

  1. To run the ammo.js module as a WASM module you need first to compile ammo.js to WASM. More info about compiling it yourself here : https://github.com/kripken/ammo.js/#building

    Here is the compiled file : ammo.wasm.wasm

  2. You first need to launch a webWorker using javascript that will load our module, something like :

var physicsWorker = null;
var nextPhysicsWorker = new Worker('worker.wasm.js');
if (physicsWorker) physicsWorker.terminate();
physicsWorker = nextPhysicsWorker;
nextPhysicsWorker = null;
if (!physicsWorker) physicsWorker = new Worker('worker.wasm.js');
  1. Here is what a WebWorker will look like : worker.wasm.js We probably need to rewrite the "Bullet-interfacing code" for Armory.

  2. Armory is loading the normal JS ammo.js inside the kha.js script by calling this function here : https://github.com/armory3d/armory/blob/58e4744aa10b197c34c5e929578fce4c76427003/Sources/armory/system/Starter.hx#L77

and it seems that Krom at line 80 is already using the WASM version of ammo.js - so we just need to rewrite this function for the html5 export.

  1. Finally : we need to sync 3D objects using the worker. We need to access and update all 3D objects with their transforms generated by the worker and get them update in the 3D canvas. The function will look like this :
physicsWorker.onmessage = function(event) {
var data = event.data;
if (data.objects.length != TotalNumberOfObjectsWithPhysics) return;
for (var i = 0; i < TotalNumberOfObjectsWithPhysics; i++) {
	var physicsObject = data.objects[i];
	renderObject.position[0] = physicsObject[0];
	renderObject.position[1] = physicsObject[1];
	renderObject.position[2] = physicsObject[2];
	quaternion.x = physicsObject[3];
	quaternion.y = physicsObject[4];
	quaternion.z = physicsObject[5];
	quaternion.w = physicsObject[6];
	renderObject.rotation = quaternion.toEuler();
}
};
physicsWorker.postMessage(TotalNumberOfObjectsWithPhysics);

Also here is a 3D scene with cube and added physics that can be used as a benchmark. https://github.com/onelsonic/armory_tests/raw/master/mesh_generate.7z

onelsonic avatar Sep 20 '20 18:09 onelsonic

Hey @onelsonic

This looks cool and so I did some digging. Although I am not adept with JS coding, I found this on Haxe Code Cookbook. I am willing to add this functionality but I might need to study some more about it.

QuantumCoderQC avatar Dec 27 '20 18:12 QuantumCoderQC

I cleaned up my post above and updated the ammo.wasm.wasm with the same compiled file used by Krom. The inline web workers in Haxe looks promising.

onelsonic avatar Dec 28 '20 12:12 onelsonic

I see that Kha has an HTML5 backend with workers which might work for this : https://github.com/Kode/Kha/tree/master/Backends/HTML5-Worker/kha

onelsonic avatar Aug 01 '21 12:08 onelsonic

I've added add/remove cubes option to the mesh_generate example for benchmarking. https://disktree.net/app/armory_examples_browser/#examples-mesh_generate

Source in pending pr: https://github.com/armory3d/armory_examples/pull/28/files#diff-9451dba57586c2efa810d775e2c692f5ce2bd887fb2cdc1596f16643fb4fe2c8

tong avatar Aug 02 '21 16:08 tong

Any idea what the % overhead is for moving all the transforms data back to be rendered? Does it scale linearly?

stevedekorte avatar Oct 19 '22 19:10 stevedekorte