How to add ammo.js physic to gltf file?

hello, i want to add physic to the claw gltf file.
gltf link: [https://three.tzjjtech.cn/house2/model/claw.glb](https://claw gltf)
I want to add it to physic, i don’t want to set it Box/Spere physic Mesh.I want to set it to its own grid shape.I want to consult you and what should I do. Thanks a lot!

You need to convert your geometry into convex hull
The following code can be used to create custom convex shape for ammo.js
It require a clean mesh with relatively ordered triangles, and expect you already have the rest of the code to generate physics from ammo shapes.

// new empty ammo shape
const shape = new AmmoLib.btConvexHullShape();

//new ammo triangles
let triangle, triangle_mesh = new Ammo.btTriangleMesh;

//new ammo vectors
let vectA = new AmmoLib.btVector3(0,0,0);
let vectB = new AmmoLib.btVector3(0,0,0);
let vectC = new AmmoLib.btVector3(0,0,0);

//retrieve vertices positions from object
let verticesPos = geometry.getAttribute('position').array;
let triangles = [];
for ( let i = 0; i < verticesPos.length; i += 3 ) {
	triangles.push({ x:verticesPos[i], y:verticesPos[i+1], z:verticesPos[i+2] })
}

//use triangles data to draw ammo shape
for ( let i = 0; i < triangles.length-3; i += 3 ) {
		
	vectA.setX(triangles[i].x);
	vectA.setY(triangles[i].y);
	vectA.setZ(triangles[i].z);
	shape.addPoint(vectA,true);

	vectB.setX(triangles[i+1].x);
	vectB.setY(triangles[i+1].y);
	vectB.setZ(triangles[i+1].z);
	shape.addPoint(vectB,true);

	vectC.setX(triangles[i+2].x);
	vectC.setY(triangles[i+2].y);
	vectC.setZ(triangles[i+2].z);
	shape.addPoint(vectC,true);
		
	triangle_mesh.addTriangle( vectA, vectB, vectC, true );
}

Thank you for your response! I try cannon.js and three-to-cannon lib.It’s easy to use.
Thank you very much!

I’m trying this code but how do I setAttribute(‘position’), can you please help?

Sure!
Here is a github repo with working example, and links with sources used

this is basically a package merging mr Doob + Blue Magnificent amazing works.

code start at line 91
https://github.com/Oxynt/AmmoPhysics-extended/blob/7bd2f03d1984a96f584f5b85d769f37701f8101d/js/physics.js
you can see the shape in action in the example (the weird conic pentagon)

btw ammo.js got updated recently, my code is not perfect, but I should update this with missing shapes (terrain and impact trimesh) :thinking:

1 Like

Thanks for the repo! Actually, I’m digging a lot deeper into ammo from articles on bullet and ammo by Blue Magnificient but I’m getting this error

This is how I’m adding gltf and floor, this is the same problem i was encountering before, if we are doing getAttribute(‘position’) for gltf then first i have to do setAttribute(‘position’) like you have done in TeapotGeometry.js - this.setAttribute( ‘position’, new BufferAttribute( vertices, 3 ) ); at line 695

This is how I’m adding

createObjects(){
		let tempMesh

		//PLANE
		tempMesh = this.meshes.push(new THREE.Mesh(new THREE.BoxGeometry(30, 30, 1), new THREE.MeshPhongMaterial({ color: 0xffffff })))
		this.meshes[tempMesh - 1].rotation.x = -Math.PI / 2
		this.meshes[tempMesh - 1].receiveShadow = true
		this.meshes[tempMesh - 1].mass = 0
		this.rigidBodies.push(this.meshes[tempMesh - 1])

		//head
		tempMesh = this.meshes.push(this.headGLTF);
		this.meshes[tempMesh - 1].geometry.name = 'hull'
		this.meshes[tempMesh - 1].position.set(0, 15, 0)
		this.meshes[tempMesh - 1].mass = 1
		this.rigidBodies.push(this.meshes[tempMesh - 1])

		//PHYSICS SETUP
		for (let i in this.meshes) {
			this.meshes[i].index = i;
			
			//shadows
			this.meshes[i].traverse(function(child) {
				if (child.visible == true && child.isMesh) {
					child.castShadow = true
					child.receiveShadow = true
				}
			});
			
			this.physics.addMesh(this.meshes[i], this.rigidBodies[i], this.meshes[i].mass)
			
			this.physics.setMeshPosition(this.meshes[i], this.meshes[i].position, this.meshes[i].quaternion, 0)
			
			if (this.meshes[i].visible == true) {
				this.scene.add(this.meshes[i])
			}
		}
	}

What I am doing here wrong?

Yeah the convex hull function is a partial answer.
The attributes tag is not the same type if you use primitives or gltfLoader
It require some conversion beforehand.

Here is two console output: a raw loaded geometry, and a native plane. You can see they are not the same.

How can i convert attributes of gltfLoader?

Hello @Oxyn I think I have made a work around, but have some issues. Glft model goes inside the plane, Probably some mistake in calculating vertices or something, or should I add more margin? can you look into it, please! I have attached a video of it below and this is the code

createMask(Ammo){
		let head
		let position = {x: 0, y: 70, z: 0},
		quaternion = {x: 0, y: 0, z: 0, w: 1},
		mass = 1

		const scale = 5

		this.loader = new GLTFLoader()
		const dracoLoader = new DRACOLoader()
		dracoLoader.setDecoderPath('/draco/')
		this.loader.setDRACOLoader(dracoLoader)
		this.loader.load('assets/models/mask.glb', (gltf) => {
			
			head = gltf.scene.children[0]
			head.scale.set(scale,scale,scale)
			head.position.set(0, position.y, 0)
			head.castShadow = true
			
			this.scene.add(head)

			//physics

			const transform = new Ammo.btTransform();
			transform.setIdentity();
			transform.setOrigin(new Ammo.btVector3(position.x, position.y, position.z));
			transform.setRotation(new Ammo.btQuaternion(quaternion.x, quaternion.y, quaternion.z, quaternion.w));

			const shape = new Ammo.btConvexHullShape();

            //new ammo triangles
            let triangle, triangle_mesh = new Ammo.btTriangleMesh;

            //declare triangles position vectors
            let vectA = new Ammo.btVector3(0, 0, 0);
            let vectB = new Ammo.btVector3(0, 0, 0);
            let vectC = new Ammo.btVector3(0, 0, 0);

            //retrieve vertices positions from object
            let verticesPos = head.geometry.getAttribute('position').array;
			console.log(verticesPos)
            let triangles = [];
            for (let i = 0; i < verticesPos.length; i += 3) {
                triangles.push({
                    x: verticesPos[i],
                    y: verticesPos[i + 1],
                    z: verticesPos[i + 2]
                })
            }

            //use triangles data to draw ammo shape
            for (let i = 0; i < triangles.length - 3; i += 3) {

                vectA.setX(triangles[i].x);
                vectA.setY(triangles[i].y);
                vectA.setZ(triangles[i].z);
                shape.addPoint(vectA, true);

                vectB.setX(triangles[i + 1].x);
                vectB.setY(triangles[i + 1].y);
                vectB.setZ(triangles[i + 1].z);
                shape.addPoint(vectB, true);

                vectC.setX(triangles[i + 2].x);
                vectC.setY(triangles[i + 2].y);
                vectC.setZ(triangles[i + 2].z);
                shape.addPoint(vectC, true);

                triangle_mesh.addTriangle(vectA, vectB, vectC, true);
            }
			
			Ammo.destroy(vectA);
            Ammo.destroy(vectB);
            Ammo.destroy(vectC);

            shape.setMargin(0.05);
			const motionState = new Ammo.btDefaultMotionState(transform);

			const localInertia = new Ammo.btVector3(0, 0, 0);
			shape.calculateLocalInertia(mass, localInertia);
			
			const rbInfo = new Ammo.btRigidBodyConstructionInfo(mass, motionState, shape, localInertia);

			const rBody = new Ammo.btRigidBody(rbInfo);
			this.physicsWorld.addRigidBody(rBody)
			head.userData.physicsBody = rBody
			this.rigidBodies.push(head)
		})

	}

By the look of it, seem the vertices are either offset or not scaling with the mesh.
Yeah just checked your code, could be the re-scale…try to update vertices data
verticesNeedUpdate = true
I suggest to use https://enable3d.io/ to make some light on this.

it’s a more automated wrapper, same as ammoPhysics.js (still require ammo.js). But providing helpers to visualize ammo bodies on screen. Since I can only provide speculative answers from this point and may lead you to wrong direction.

In practice you have 3 options:

  • try without re-scaling the model
  • test your function against enable3d version (gltf example linked bellow) and see how it goes.
  • use enable3d directly if you rather avoid coding your own wrapper

Hey @Oxyn thanks for helping, I removed scaling on gltf and added verticesNeedUpdate = true
and it worked properly as expected but enable3d also helped in a way to learn its work-around.
Thanks again!

1 Like