# Tutorial on JavaScript Physics Using AmmoJS and ThreeJS

Hello All

Just wanted to share a tutorial I wrote on medium about JavaScript 3D physics. Its more like an introductory tutorial using Ammo.js and threejs.

I hope someone finds it helpful Intro to JavaScript 3D Physics using Ammo.js and Three.js

Update
Still in the same spirit, a follow up article has been published Moving Objects In JavaScript 3D Physics using Ammo.js and Three.js

Another Update
Third article; based on collision detection Collision Detection In Javascript 3D Physics using Ammo.js and Three.js

18 Likes

Nice tutorial 4 Likes

Thanks 1 Like

is ammo.js best physics engine ?

I can’t really say. But I do know that Bullet Physics, it’s parent, is widely used.

@extremety1989

Think of it like this. Ammo.js to, say, Phys.js is what Fighter Jet is to a paper airplane. If you need a fully featured physics engine - there’s just no competition on the market to Ammo at the moment. If you only need a subset of what a physics engine typically is - you can get excellent results with the few other decent engines on the market.

4 Likes

Added a new article on collision detection.

1 Like

Thanks for this tutorial, I appreciate your efforts.

1 Like

This is the best tutorial about Ammo.js for beginners in Ammo.js. I study the Collision Detection lesson. I use TypeScript as a programming language and pure WebGL 1.0 to draw objects: I want to print names of colliding objects as in the lesson. I try to use setUserPointer/getUserPointer.

I created an object to keep a user data:

``````const userData = { name: name };
``````

I keep this object in a body using setUserPointer:

``````this.body.setUserPointer(userData);
``````

I try to get these names using getUserPointer and print them. But I get “undefined” instead of names:

``````function detectCollison(): void
{
const dispatcher = physicsWorld.getDispatcher();
const numManifolds = dispatcher.getNumManifolds();

for (let i = 0; i < numManifolds; i++)
{
const contactManifold = dispatcher.getManifoldByIndexInternal(i);
const body0 = contactManifold.getBody0();
const body1 = contactManifold.getBody1();

const p0 = body0.getUserPointer();
const p1 = body1.getUserPointer();

console.log("first object: " + (p0 as any).name);
console.log("second object: " + (p1 as any).name);
}
}
``````

This is a solution for my problem above:

``````const userData = { name: name };
(this.body as any).userData = userData;
``````
``````function detectCollison(): void
{
const dispatcher = physicsWorld.getDispatcher();
const numManifolds = dispatcher.getNumManifolds();

for (let i = 0; i < numManifolds; i++)
{
const contactManifold = dispatcher.getManifoldByIndexInternal(i);
const body0 = contactManifold.getBody0();
const body1 = contactManifold.getBody1();

const rb0 = (Ammo as any).castObject( contactManifold.getBody0(), Ammo.btRigidBody );
const rb1 = (Ammo as any).castObject( contactManifold.getBody1(), Ammo.btRigidBody );

console.log("first object:", rb0.userData);
console.log("second object:", rb1.userData);
}
}
``````
1 Like

Glad you found a solution. Sorry I wasn’t on time to reply.

1 Like

Hi, thanks for the tutorial links they are great!

I haven’t had the chance to test the code yet. BUT ( ) It looks to me as though all transforms are flat. As in they are all tied to the scene/world transform (or rather the `.setIdentity()` matrix) and not nested children of other Mesh/RigidBody objects. In your example it works fine as the ThreeJS Mesh objects are all children of the Scene.

In the initialisation functions, `createBall` and `createBlock`.

``````let transform = new Ammo.btTransform();
transform.setIdentity();
transform.setOrigin( new Ammo.btVector3( pos.x, pos.y, pos.z ) );
transform.setRotation( new Ammo.btQuaternion( quat.x, quat.y, quat.z, quat.w ) );
let motionState = new Ammo.btDefaultMotionState( transform );
``````

It doesn’t look like parent transforms are factored in.

And neither in the `updatePhysics` function:

``````ms.getWorldTransform( tmpTrans );
let p = tmpTrans.getOrigin();
let q = tmpTrans.getRotation();
objThree.position.set( p.x(), p.y(), p.z() );
objThree.quaternion.set( q.x(), q.y(), q.z(), q.w() );
``````

Here the `.getWorldTransform` is computed, but nested transforms weren’t setup in the `createBlock` and `createBall` functions.

Is it the case that for this tutorial we just don’t worry about nested transforms or will this still work?

Is bullet even designed to work this way with nested transforms (Possibly need to use some sort of weld joint instead)?

If so, do you know what the extra steps required would be to include a joint or parent/child relationship?

Thanks again!

1 Like
{"ft_lang_label":"__label__en","ft_lang_prob":0.7939187,"math_prob":0.5617884,"size":1492,"snap":"2022-05-2022-21","text_gpt3_token_len":341,"char_repetition_ratio":0.1297043,"word_repetition_ratio":0.0,"special_character_ratio":0.23257373,"punctuation_ratio":0.21474358,"nsfw_num_words":0,"has_unicode_error":false,"math_prob_llama3":0.9502557,"pos_list":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14],"im_url_duplicate_count":[null,null,null,null,null,null,null,null,null,null,null,1,null,null,null],"WARC_HEADER":"{\"WARC-Type\":\"response\",\"WARC-Date\":\"2022-05-27T06:16:49Z\",\"WARC-Record-ID\":\"<urn:uuid:92f568e5-b030-4055-91ab-24e3c0a57846>\",\"Content-Length\":\"50734\",\"Content-Type\":\"application/http; msgtype=response\",\"WARC-Warcinfo-ID\":\"<urn:uuid:d2b679bd-6791-4c7d-9ffc-94ca148abb98>\",\"WARC-Concurrent-To\":\"<urn:uuid:69995ebc-4d7f-4f4b-aae6-ac93ef4a99d8>\",\"WARC-IP-Address\":\"64.62.250.111\",\"WARC-Target-URI\":\"https://discourse.threejs.org/t/tutorial-on-javascript-physics-using-ammojs-and-threejs/7285\",\"WARC-Payload-Digest\":\"sha1:XHUUTL2W25NTA3TX6TDI5O77CABUMFCF\",\"WARC-Block-Digest\":\"sha1:TDBUZBE3HQ2YQYFNGUCCYGA37OCMCZMS\",\"WARC-Identified-Payload-Type\":\"text/html\",\"warc_filename\":\"/cc_download/warc_2022/CC-MAIN-2022-21/CC-MAIN-2022-21_segments_1652662636717.74_warc_CC-MAIN-20220527050925-20220527080925-00094.warc.gz\"}"}