I want to make a browser VR shooting game, using Three.js and Ammo.js for the physics and rigidbodies. The vr head and controllers are set up the models are loaded, but the bullets won't shoot from the gun as I want to. When I tried to do the same using only Three.js with no rigidbodies in the scene, I used the "vector.applyQuaternion" from the Three.js documentation, and it worked, the bullets were fired from the top of the gun. The problem is I didn't find anything similar for using ammo.js
Code without using ammo.js
... function handleController( controller ) {
if ( controller1.userData.isSelecting ) {
bullet1.position.set( controller1.position.x , controller1.position.y + 0.018 , controller1.position.z -0.01);
bullet1.userData.velocity.x = 0;
bullet1.userData.velocity.y = 10;
bullet1.userData.velocity.z = 10;
bullet1.userData.velocity.applyQuaternion( controller1.quaternion );
scene.add(bullet1);
}
if ( controller2.userData.isSelecting ) {
bullet2.position.set( controller2.position.x , controller2.position.y + 0.018 , controller2.position.z -0.01 );
bullet2.userData.velocity.x = 0;
bullet2.userData.velocity.y = 10;
bullet2.userData.velocity.z = 10;
bullet2.userData.velocity.applyQuaternion( controller2.quaternion );
scene.add(bullet2);
}
} ...
function render() {
handleController( controller1 );
handleController( controller2 );
var delta = clock.getDelta()
bullet1.position.x -= bullet1.userData.velocity.x * delta;
bullet1.position.y -= bullet1.userData.velocity.y * delta;
bullet1.position.z -= bullet1.userData.velocity.z * delta;
bullet2.position.x -= bullet2.userData.velocity.x * delta;
bullet2.position.y -= bullet2.userData.velocity.y * delta;
bullet2.position.z -= bullet2.userData.velocity.z * delta;
renderer.render( scene, camera );
}
code with ammo.js
function createBullet1RigidBody( threeObject, physicsShape, mass ) {
//threeObject.position.copy( pos );
//threeObject.quaternion.copy( quat1 );
quat1.set( controller1.position.x, controller1.position.y , controller1.position.z , Math.PI/2 );
pos1 = new THREE.Vector3 ( controller1.position.x, controller1.position.y , controller1.position.z );
var transform = new Ammo.btTransform();
transform.setIdentity();
transform.setOrigin( new Ammo.btVector3( controller1.position.x, controller1.position.y, controller1.position.z -0.5) );
transform.setRotation( new Ammo.btQuaternion( quat1.x, quat1.y, quat1.z, quat1.w ) );
var motionState = new Ammo.btDefaultMotionState( transform );
var localInertia = new Ammo.btVector3( 0, 0, 0 );
physicsShape.calculateLocalInertia( mass, localInertia );
var rbInfo = new Ammo.btRigidBodyConstructionInfo( mass, motionState, physicsShape, localInertia );
var body1 = new Ammo.btRigidBody( rbInfo );
threeObject.userData.physicsBody = body1;
scene.add( threeObject );
if ( mass > 0 ) {
bullet1Bodies.push( threeObject );
// Disable deactivation
body1.setActivationState( 4 );
}
physicsWorld.addRigidBody( body1 );
return body1;
}
function createBullet2RigidBody( threeObject, physicsShape, mass ) {
//threeObject.position.copy( pos );
//threeObject.quaternion.copy( quat2 );
var transform = new Ammo.btTransform();
transform.setIdentity();
transform.setOrigin( new Ammo.btVector3( controller2.position.x, controller2.position.y, controller2.position.z -0.5 ) );
transform.setRotation( new Ammo.btQuaternion( quat.x, quat.y, quat.z, quat.w ) );
var motionState = new Ammo.btDefaultMotionState( transform );
var localInertia = new Ammo.btVector3( 0, 0, 0 );
physicsShape.calculateLocalInertia( mass, localInertia );
var rbInfo = new Ammo.btRigidBodyConstructionInfo( mass, motionState, physicsShape, localInertia );
var body2 = new Ammo.btRigidBody( rbInfo );
threeObject.userData.physicsBody = body2;
scene.add( threeObject );
if ( mass > 0 ) {
bullet2Bodies.push( threeObject );
// Disable deactivation
body2.setActivationState( 4 );
}
physicsWorld.addRigidBody( body2 );
return body2;
}
...
function handleController( controller ) {
if ( controller1.userData.isSelecting ) {
var bullet1Mass = 0.1;
var bullet1Radius = 0.6;
var bullet1 = new THREE.Mesh( geometry_bullet, new THREE.MeshLambertMaterial( { color: 0x2661b9 } ) );
var bullet1Shape = new Ammo.btSphereShape ( bullet1Radius );
bullet1Shape.setMargin ( margin );
var bullet1_body = createBullet1RigidBody( bullet1, bullet1Shape, bullet1Mass, bullet1Radius );
//bullet1.position.set( pos1.x, pos1.y, pos1.z );
bullet1.userData.physicsBody.setFriction( 0 );
bullet1_body.setLinearVelocity( new Ammo.btVector3( 100, 100, 100 , controller1.quaternion) );
}
if ( controller2.userData.isSelecting ) {
var bullet2Mass = 0.1;
var bullet2Radius = 0.6;
var bullet2 = new THREE.Mesh( geometry_bullet, new THREE.MeshLambertMaterial( { color: 0xee2f2f } ) );
var bullet2Shape = new Ammo.btSphereShape ( bullet2Radius );
var pos2 = new THREE.Vector3 ( controller2.position.x, controller2.position.y + 10, controller2.position.z +10 );
bullet2Shape.setMargin ( margin );
//quat2.set( 0,0,0,1 );
var bullet2_body = createBullet2RigidBody( bullet2, bullet2Shape, bullet2Mass, bullet2Radius, pos2, quat2 );
//var pos2 = bullet2.position.set( controller2.position.x, controller2.position.y, controller2.position.z -0.1 );
bullet2.userData.physicsBody.setFriction( 0 );
bullet2_body.setLinearVelocity( new Ammo.btVector3( 0, 0, controller2.position.z *100 ) );
//bullet2.userData.physicsBody.applyQuaternion(controller2.quaternion);
}
}
The result is that the bullets are created but they're moving only on the z axis. The velocity of the bullet2 changes if I move the controller on the x axis, and the bullets are moving only on z axis. Bullets of the bullet1 follows the movement on the x,y,z axis but not the rotation of the controller. The "bullet2.userData.physicsBody.applyQuaternion(controller2.quaternion);" line is a comment, if I remove the bars I get this error "TypeError: bullet2.userData.physicsBody.applyQuaternion is not a function". I was expecting to do the same as I did in the previous example without ammo (userData.velocity.applyQuaternion) but there's no LinearVelocity in the ammo.js, I can only use getLinearVelocity and setLinearVelocity.
Based on ammo versions I've seen, your call to setLinearVelocity() is not correct. The btVector3 constructor must take x,y,z only. Calculate it using ThreeJS math similarly to where you've done elsewhere (choose magnitude and rotate the vector3 by the controller's quaternion). That probably solves your issue.
Note: I question why your bullets need to be physically simulated. Most shooting games do not do this. Easier and faster is to visually update its progress while checking for when it intercepts a player/wall. If you desire a gravity effect then apply small vertical drop every frame. If you want ricochet then use the normal of the intercepted surface to alter the velocity. Ammo engine is good for things like a grenade bouncing (complex, unpredictable interactions).