cannon.js
A lightweight 3D physics engine written in JavaScript.
schteppe/cannon.js @ GitHub a lightweight and simple 3d physics engine for the web.
I am making a go of three.js and cannon.js, but am stuck with being able to make walls solid, or anything solid that doesn't move and does hold the player back.
http://www.trepaning.com/3js/SEA3d/elvisCollideWalls.html
Here is the code I have thus far. Any insight appreciated. I prefer figuring stuff out on my own, but this one thing of making walls solid is holding me back at the moment, and I appreciate any info to get me over this hump.
if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
var initScene;
var MARGIN = 10;
var MARGINSIDE = 0;
var WIDTH = window.innerWidth || ( 2 + 2 * MARGINSIDE );
//var WIDTH = window.innerWidth/3 || ( 2 + 2 * MARGINSIDE );
//var HEIGHT = window.innerHeight/3 || ( 2 + 2 * MARGIN );
var HEIGHT = window.innerHeight || ( 2 + 2 * MARGIN );
var SCREEN_WIDTH = WIDTH -2 * MARGINSIDE;
var SCREEN_HEIGHT = HEIGHT -2 * MARGIN;
var FAR = 10000;
var DAY = 0;
var stats, camera, scene, renderer;
var mesh, geometry;
var sunLight, pointLight, ambientLight, hemiLight;
var parameters
var clock = new THREE.Clock();
var inRender = true;
var inResize = false;
// cannon physics
var world;
var worldScale = 100;
var timeStep = 1/60;
var walls=[], balls=[], ballMeshes=[], boxes=[], boxMeshes=[];
var solidMaterial;
var playerMaterialPhy;
var playerRigid;
var playerPhysicsMesh;
var UNITSIZE = 250
var WALLHEIGHT = UNITSIZE / 3;
var map = [ // 1 2 3 4 5 6 7 8 9
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1,], // 0
[1, 1, 0, 0, 0, 0, 0, 1, 1, 1,], // 1
[1, 1, 0, 0, 2, 0, 0, 0, 0, 1,], // 2
[1, 0, 0, 1, 0, 2, 0, 0, 0, 1,], // 3
[1, 0, 0, 2, 0, 0, 2, 1, 0, 1,], // 4
[1, 0, 0, 0, 2, 0, 0, 0, 0, 1,], // 5
[1, 1, 1, 0, 0, 0, 0, 0, 1, 1,], // 6
[1, 1, 1, 0, 0, 0, 0, 0, 1, 1,], // 7
[1, 1, 1, 1, 1, 1, 0, 0, 1, 1,], // 8
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1,], // 9
], mapW = map.length, mapH = map[0].length;
// player
var loader;
var player;
var playerMaterial;
var playerMap = { map:undefined, normal:undefined};
var players=[];
var playerName = "LegoElvis";
var scaleFactor = 5;
var velocity = {x : 0, z : 0};
var playerControls = {
moveForward: false,
moveBackward: false,
moveLeft: false,
moveRight: false,
bodyOrientation: 0,
maxSpeed: 275,
maxReverseSpeed: -275,
frontAcceleration: 600,
backAcceleration: 600,
frontDecceleration: 600,
angularSpeed: 2.5,
speed: 0
};
var shadowConfig = {
Visible: false,
Near: 750,
Far: 4000,
Fov: 75,
Bias: -0.0002,
Darkness: 0.5,
Resolution:1024
};
var playerConfig = {
name: "",
loading: 0,
scale: 1,
CloneNumber: 30,
Clone: false
};
var LightConfig = {
Ambient: 0x554b3b,
Fog : 0x00283f
};
var MaterialConfig = {
shininess : 0,
specular: 1,
normalScaleX: 0,
normalScaleY: 0,
bias:0,
bumpScale: 2,
metal:false
};
var sky;
var skyCubeNight, skyCubeDay;
var skyShader;
initScene = function () {
// RENDERER
renderer = new THREE.WebGLRenderer( { clearColor: LightConfig.Fog, clearAlpha: 1, antialias: true } );
renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );
renderer.setClearColor( LightConfig.Fog, 1 );
renderer.domElement.style.position = "absolute";
document.getElementById( 'viewport' ).appendChild( renderer.domElement );
renderer.shadowMapEnabled = true;
renderer.shadowMapType = THREE.PCFSoftShadowMap;
renderer.gammaInput = true;
renderer.gammaOutput = true;
renderer.physicallyBasedShading = true;
// SCENE
scene = new THREE.Scene();
scene.fog = new THREE.Fog( LightConfig.Fog , 1000, FAR );
// CAMERA
camera = new THREE.PerspectiveCamera( 45, SCREEN_WIDTH / SCREEN_HEIGHT, 2, FAR );
camera.position.set( 50, 300, 350 );
// CAMERA CONTROL
controls = new THREE.OrbitControls( camera, renderer.domElement );
controls.center.set( 0, 0, 0 );
controls.keys = [];
controls.maxPolarAngle = toRad(90);
controls.userRotateSpeed = 1.8;
controls.zoomSpeed = 1.6;
controls.userPanSpeed = 0.8;
// GROUND
var mapGround = THREE.ImageUtils.loadTexture( "images/legoElvis.jpg" );
mapGround.anisotropy = renderer.getMaxAnisotropy();
mapGround.repeat.set( 100, 100 );
mapGround.wrapS = mapGround.wrapT = THREE.RepeatWrapping;
mapGround.magFilter = THREE.NearestFilter;
mapGround.format = THREE.RGBFormat;
var groundMaterial = new THREE.MeshPhongMaterial( { shininess: 10, ambient: 0x444444, color: 0xffffff, specular: 0xffffff, map: mapGround, metal: false } );
var planeGeometry = new THREE.PlaneGeometry( 100, 100 );
var ground = new THREE.Mesh( planeGeometry, groundMaterial );
ground.position.set( 0, 0, 0 );
ground.rotation.x = - Math.PI / 2;
ground.scale.set( 1000, 1000, 1000 );
ground.receiveShadow = true;
scene.add( ground );
initLights();
initPhysics();
loadSea3dModel();
stats = new Stats();
document.getElementById('my-stat').appendChild(stats.domElement);
// LISTENERS
window.addEventListener( 'resize', onWindowResize, false );
document.addEventListener( 'keydown', onKeyDown, false );
document.addEventListener( 'keyup', onKeyUp, false );
// TWEEN
parameters = { control: 0 };
animate();
}
//-----------------------------------------------------
// LIGHT
//-----------------------------------------------------
function initLights() {
var sunIntensity = 0.8;
var pointIntensity = 0.3;
var pointColor = 0xffffff;
var skyIntensity = 1;
ambientLight = new THREE.AmbientLight( LightConfig.Ambient );
scene.add( ambientLight );
hemiLight = new THREE.HemisphereLight( 0xffffff, 0xffffff, 0.6 );
hemiLight.color.setHSL( 0.63, 0.05, 0 );
hemiLight.groundColor.setHex( 0xe4c8a0 );
hemiLight.position.set( 0, 400, 0 );
scene.add( hemiLight );
pointLight = new THREE.PointLight( LightConfig.Moon, pointIntensity, 5000 );
pointLight.position.set( -1000, 0, -1000 );
scene.add( pointLight );
sunLight = new THREE.SpotLight( LightConfig.Sun, sunIntensity, 0, Math.PI/2, 1 );
sunLight.position.set( 1000, 2000, 1000 );
sunLight.castShadow = true;
sunLight.shadowCameraVisible = shadowConfig.Visible;
sunLight.shadowCameraNear = shadowConfig.Near;
sunLight.shadowCameraFar = shadowConfig.Far;
sunLight.shadowCameraFov = shadowConfig.Fov;
sunLight.shadowBias = shadowConfig.Bias;
sunLight.shadowDarkness = shadowConfig.Darkness * sunIntensity;
sunLight.shadowMapWidth = shadowConfig.Resolution;
sunLight.shadowMapHeight = shadowConfig.Resolution;
scene.add( sunLight );
}
function enableCascadeShadow() {
renderer.shadowMapCascade = true;
sunLight.shadowCascade = true;
sunLight.shadowCascadeCount = 3;
sunLight.shadowCascadeNearZ = [ -1.000, 0.995, 0.998 ];
sunLight.shadowCascadeFarZ = [ 0.995, 0.998, 1.000 ];
sunLight.shadowCascadeWidth = [ shadowConfig.Resolution, shadowConfig.Resolution, shadowConfig.Resolution ];
sunLight.shadowCascadeHeight = [ shadowConfig.Resolution, shadowConfig.Resolution, shadowConfig.Resolution ];
}
//-----------------------------------------------------
// RESIZE
//-----------------------------------------------------
function onWindowResize( event ) {
inResize = true;
//document.getElementById("viewport").style.background = '#222222';
SCREEN_WIDTH = window.innerWidth - 2 * MARGINSIDE;
SCREEN_HEIGHT = window.innerHeight - 2 * MARGIN;
camera.aspect = SCREEN_WIDTH / SCREEN_HEIGHT;
camera.updateProjectionMatrix();
renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );
}
//-----------------------------------------------------
// KEYBOARD
//-----------------------------------------------------
function onKeyDown ( event ) {
switch ( event.keyCode ) {
case 38: /*up*/
case 87: /*W*/
case 90: /*Z*/ playerControls.moveForward = true; break;
case 40: /*down*/
case 83: /*S*/ playerControls.moveBackward = true; break;
case 37: /*left*/
case 65: /*A*/
case 81: /*Q*/ playerControls.moveLeft = true; break;
case 39: /*right*/
case 68: /*D*/ playerControls.moveRight = true; break;
}
}
function onKeyUp ( event ) {
switch( event.keyCode ) {
case 38: /*up*/
case 87: /*W*/
case 90: /*Z*/ playerControls.moveForward = false; break;
case 40: /*down*/
case 83: /*S*/ playerControls.moveBackward = false; break;
case 37: /*left*/
case 65: /*A*/
case 81: /*Q*/ playerControls.moveLeft = false; break;
case 39: /*right*/
case 68: /*D*/ playerControls.moveRight = false; break;
}
};
//-----------------------------------------------------
// SEA3D
//-----------------------------------------------------
function loadSea3dModel() {
loader = new THREE.SEA3D( false );
//loader.matrixAutoUpdate = true;
//loader.invertCamera = true;
loader.onComplete = function( e ) {
player = loader.getMesh(playerName);
player.play("idle");
player.scale.set( playerConfig.scale*3, playerConfig.scale*3, -playerConfig.scale*3 );
scene.add( player );
creatPlayerPhysics();
};
//loader.load( 'folder/'+playerName+'.sea' );
loader.load( 'models/legoElvis.sea' );
}
// PLAYER ANIMATION
function updatePlayer(delta) {
if (playerControls.moveForward){
if (player.currentAnimation.name == "idle") player.play("walk");
} else if (playerControls.moveBackward){
if (player.currentAnimation.name == "idle") player.play("walk");
}
else {
if(player.currentAnimation.name == "walk") player.play("idle");
}
THREE.AnimationHandler.update( delta );
updatePlayerMove(delta);
}
// PLAYER MOVE
function updatePlayerMove( delta ) {
playerControls.maxReverseSpeed = -playerControls.maxSpeed;
if ( playerControls.moveForward ) playerControls.speed = THREE.Math.clamp( playerControls.speed + delta * playerControls.frontAcceleration, playerControls.maxReverseSpeed, playerControls.maxSpeed );
if ( playerControls.moveBackward ) playerControls.speed = THREE.Math.clamp( playerControls.speed - delta * playerControls.backAcceleration, playerControls.maxReverseSpeed, playerControls.maxSpeed );
// orientation based on controls
// (don't just stand while turning)
var dir = 1;
if ( playerControls.moveLeft ) {
playerControls.bodyOrientation += delta * playerControls.angularSpeed;
playerControls.speed = THREE.Math.clamp( playerControls.speed + dir * delta * playerControls.frontAcceleration, playerControls.maxReverseSpeed, playerControls.maxSpeed );
}
if ( playerControls.moveRight ) {
playerControls.bodyOrientation -= delta * playerControls.angularSpeed;
playerControls.speed = THREE.Math.clamp( playerControls.speed + dir * delta * playerControls.frontAcceleration, playerControls.maxReverseSpeed, playerControls.maxSpeed );
}
// speed decay
if ( ! ( playerControls.moveForward || playerControls.moveBackward ) ) {
if ( playerControls.speed > 0 ) {
var k = exponentialEaseOut( playerControls.speed / playerControls.maxSpeed );
playerControls.speed = THREE.Math.clamp( playerControls.speed - k * delta * playerControls.frontDecceleration, 0, playerControls.maxSpeed );
} else {
var k = exponentialEaseOut( playerControls.speed / playerControls.maxReverseSpeed );
playerControls.speed = THREE.Math.clamp( playerControls.speed + k * delta * playerControls.backAcceleration, playerControls.maxReverseSpeed, 0 );
}
}
// displacement
var forwardDelta = playerControls.speed * delta;
velocity.x = Math.sin( playerControls.bodyOrientation ) * forwardDelta;
velocity.z = Math.cos( playerControls.bodyOrientation ) * forwardDelta;
player.position.x += velocity.x;
player.position.z += velocity.z;
player.position.y = playerConfig.scale*scaleFactor;
// steering
player.rotation.y = playerControls.bodyOrientation;
if(controls){
//controls.target.set( player.position.x, player.position.y, player.position.z );
camera.position.x += velocity.x;
camera.position.z += velocity.z;
controls.center.set( player.position.x, player.position.y, player.position.z );
}
if(playerRigid){
//playerRigid.position.set(player.position.x, player.position.y+3, player.position.z );
playerRigid.position.set(player.position.x, player.position.y+80, player.position.z+15 );
playerRigid.quaternion.setFromAxisAngle(new CANNON.Vec3(0,1,0),player.rotation.y);
}
};
function exponentialEaseOut( k ) { return k === 1 ? 1 : - Math.pow( 2, - 10 * k ) + 1; };
//-----------------------------------------------------
// RENDER LOOP
//-----------------------------------------------------
function animate() {
requestAnimationFrame( animate );
if(inRender || inResize){
//if(isPad)PadTest();
//updateCamera();
var delta = clock.getDelta();
if(player!=null)updatePlayer(delta);
updatePhysics();
render();
stats.update();
}
inResize = false;
}
function render() {
TWEEN.update();
controls.update();
scene.fog.color.setHSL( 0.63, 0.05, parameters.control );
renderer.setClearColor( scene.fog.color, 1 );
pointLight.intensity = - parameters.control * 0.5 + 1;
hemiLight.color.setHSL( 0.63, 0.05, parameters.control )
sunLight.shadowDarkness = shadowConfig.Darkness * sunLight.intensity;
renderer.render( scene, camera );
}
function tell(s){
document.getElementById("debug").innerHTML = s;
}
//-----------------------------------------------------
// PHYSICS
//-----------------------------------------------------
function initPhysics() {
world = new CANNON.World();
world.quatNormalizeSkip = 0;
world.quatNormalizeFast = false;
var solver = new CANNON.GSSolver();
world.defaultContactMaterial.contactEquationStiffness = 1e9;
world.defaultContactMaterial.contactEquationRegularizationTime = 4;
solver.iterations = 3;
solver.tolerance = 0.1;
world.gravity.set(0,-9.82*worldScale,0);//world.gravity.set(0,-9.82,0); // m/s²
world.broadphase = new CANNON.NaiveBroadphase();
// Create a slippery material (friction coefficient = 0.0)
physicsMaterial = new CANNON.Material("slipperyMaterial");
solidMaterial = new CANNON.Material("solidMaterial");
playerMaterialPhy = new CANNON.Material("playerMat");
var physicsContactMaterial = new CANNON.ContactMaterial(physicsMaterial, physicsMaterial, 0.0, 0.3 );
var playerContactMaterial = new CANNON.ContactMaterial(playerMaterialPhy, playerMaterialPhy, 0.0, 0.3 );
var solidContactMaterial = new CANNON.ContactMaterial(solidMaterial, solidMaterial, 0.2, 0.6 );
world.addContactMaterial(physicsContactMaterial);
world.addContactMaterial(playerContactMaterial);
world.addContactMaterial(solidContactMaterial);
// Create infinie plane
var groundShape = new CANNON.Plane();
var groundBody = new CANNON.RigidBody(0,groundShape,physicsMaterial);
groundBody.quaternion.setFromAxisAngle(new CANNON.Vec3(1,0,0),-Math.PI/2);
world.add(groundBody);
createBoxeObject();
createBallObject();
}
function creatPlayerPhysics() {
if(playerPhysicsMesh){
scene.remove(playerPhysicsMesh);
playerPhysicsMesh.geometry.dispose();
}
if(playerRigid)world.remove(playerRigid);
//player body
var halfExtents = new CANNON.Vec3(0.5*worldScale,playerConfig.scale*80, 0.25*worldScale);
var playerShape = new CANNON.Box(halfExtents);
playerRigid = new CANNON.RigidBody(0,playerShape, playerMaterialPhy);
world.add(playerRigid);
playerRigid.linearDamping=0.01;
playerRigid.angularDamping=0.01;
var boxGeometry = new THREE.CubeGeometry(halfExtents.x*2,halfExtents.y*2,halfExtents.z*2);
playerPhysicsMesh = new THREE.Mesh( boxGeometry );
scene.add(playerPhysicsMesh);
playerPhysicsMesh.useQuaternion = true;
playerPhysicsMesh.castShadow = false;
playerPhysicsMesh.receiveShadow = false;
showPlayerPhysics();
}
function showPlayerPhysics() {
//if(OptionConfig.ShowPlayerHitBox)playerPhysicsMesh.visible = true;
//else playerPhysicsMesh.visible = true;
playerPhysicsMesh.visible = true;
}
function createBallObject() {
var s = worldScale;
var mat = new THREE.MeshLambertMaterial( { color: 0xdddddd } );
var radius;
var mass = 4;
var sphereShape;
for(var i=0; i<5; i++){
radius = (0.2+(Math.random()*0.8))*s;
sphereShape = new CANNON.Sphere(radius);
ballGeometry = new THREE.SphereGeometry(radius, 32, 32 );
var sphereBody = new CANNON.RigidBody(mass,sphereShape,physicsMaterial);
//sphereBody.linearDamping = 0.9;
var x = ((Math.random()-0.5)*20)*s;
var y = (1 + (Math.random()-0.5)*1)*s;
var z = ((Math.random()-0.5)*20)*s;
sphereBody.position.set(x,y,z);
sphereBody.linearDamping=0.03;
sphereBody.angularDamping=0.03;
world.add(sphereBody);
var ballMesh = new THREE.Mesh( ballGeometry, mat );
scene.add(ballMesh);
ballMesh.useQuaternion = true;
ballMesh.castShadow = true;
ballMesh.receiveShadow = true;
// add to array
balls.push(sphereBody);
ballMeshes.push(ballMesh);
}
}
function createBoxeObject() {
var s = worldScale;
var material = new THREE.MeshLambertMaterial( { color: 0x222222 } );
// Add boxes
var sx, xy, xz;
var halfExtents = new CANNON.Vec3(1*s,1*s,1*s);
var boxShape = new CANNON.Box(halfExtents);
var boxGeometry = new THREE.CubeGeometry(halfExtents.x*2,halfExtents.y*2,halfExtents.z*2);
for(var i=0; i<5; i++){
sx= 0.2+(Math.random()*0.8);
sy= 0.2+(Math.random()*0.8);
sz= 0.2+(Math.random()*0.8);
halfExtents = new CANNON.Vec3(sx*s,sy*s,sz*s);
boxShape = new CANNON.Box(halfExtents);
boxGeometry = new THREE.CubeGeometry(halfExtents.x*2,halfExtents.y*2,halfExtents.z*2);
var x = ((Math.random()-0.5)*20)*s;
var y = (1 + (Math.random()-0.5)*1)*s;
var z = ((Math.random()-0.5)*20)*s;
var boxBody = new CANNON.RigidBody(9,boxShape, solidMaterial);
var boxMesh = new THREE.Mesh( boxGeometry, material );
world.add(boxBody);
scene.add(boxMesh);
boxBody.position.set(x,y,z);
//boxMesh.position.set(x,y,z);
boxBody.quaternion.setFromAxisAngle(new CANNON.Vec3(0,0,0),toRad(Math.random()*360));
boxMesh.castShadow = true;
boxMesh.receiveShadow = true;
boxMesh.useQuaternion = true;
boxes.push(boxBody);
boxMeshes.push(boxMesh);
}
function createObstacle() {
obstacleMesh = new THREE.CubeGeometry(150, 50, 50)
obstacleMaterial = new THREE.MeshLambertMaterial( { color: 0x666666 } );
obstacleObject = new THREE.Mesh(obstacleMesh, obstacleMaterial);
obstacleObject.position.set(0, 26, 200);
obstacleObject.castShadow = true;
obstacleObject.receiveShadow = true;
scene.add(obstacleObject);
}
createObstacle();
function setupScene() {
var units = mapW;
// Geometry: walls
var cube = new THREE.CubeGeometry(UNITSIZE, WALLHEIGHT, UNITSIZE);
var materials = [
new THREE.MeshLambertMaterial({map: THREE.ImageUtils.loadTexture('images/legoElvisR.jpg')}), //wall 1
new THREE.MeshLambertMaterial({map: THREE.ImageUtils.loadTexture('images/legoElvisG.jpg')}), //wall 2
];
for (var i = 0; i < mapW; i++) {
for (var j = 0, m = map[i].length; j < m; j++) {
if (map[i][j]) {
var wall = new THREE.Mesh(cube, materials[map[i][j]-1]);
wall.position.x = (i - units/2) * UNITSIZE;
wall.position.y = WALLHEIGHT/2;
wall.position.z = (j - units/2) * UNITSIZE;
wall.castShadow = true;
wall.receiveShadow = true;
scene.add(wall);
}
}
}
}
setupScene();
// Add linked boxes
var size = 0.5*s;
var he = new CANNON.Vec3(size,size,size*0.1);
var boxShape = new CANNON.Box(he);
var mass = 0;
var space = 0.1*size;
var N=5, last;
var boxGeometry = new THREE.CubeGeometry(he.x*2,he.y*2,he.z*2);
for(var i=0; i<N; i++){
var boxbody = new CANNON.RigidBody(mass,boxShape, solidMaterial);
var boxMesh = new THREE.Mesh( boxGeometry, material );
boxbody.position.set(5*s,((N-i)*(size*2+2*space) + size*2+space)-150,0);
boxbody.linearDamping=0.01;
boxbody.angularDamping=0.01;
boxMesh.useQuaternion = true;
boxMesh.castShadow = true;
boxMesh.receiveShadow = true;
world.add(boxbody);
scene.add(boxMesh);
boxes.push(boxbody);
boxMeshes.push(boxMesh);
if(i!=0){
// Connect this body to the last one
var c1 = new CANNON.PointToPointConstraint(boxbody,new CANNON.Vec3(-size,size+space,0),last,new CANNON.Vec3(-size,-size-space,0));
var c2 = new CANNON.PointToPointConstraint(boxbody,new CANNON.Vec3(size,size+space,0),last,new CANNON.Vec3(size,-size-space,0));
world.addConstraint(c1);
world.addConstraint(c2);
} else {
mass=0.3;
}
last = boxbody;
}
}
function updatePhysics() {
if(!world) return;
world.step(timeStep);
// update player mesh test
if(playerRigid !== undefined){
playerRigid.position.copy(playerPhysicsMesh.position);
playerRigid.quaternion.copy(playerPhysicsMesh.quaternion);
}
// Update ball positions
for(var i=0; i<balls.length; i++){
balls[i].position.copy(ballMeshes[i].position);
balls[i].quaternion.copy(ballMeshes[i].quaternion);
}
// Update box positions
for(var i=0; i<boxes.length; i++){
boxes[i].position.copy(boxMeshes[i].position);
boxes[i].quaternion.copy(boxMeshes[i].quaternion);
}
}
//-----------------------------------------------------
// MATH
//-----------------------------------------------------
function toRad(Value) {
return Value * Math.PI / 180;
}
window.onload = initScene;
Source: (StackOverflow)
Does anyone know how I can rotate a CannonJS (the physics library) CANNON.RigidBody
? I'm trying to make the object rotate with the camera, so both are facing the same direction. I know I have to modify the quaternion, but this doesn't work correctly:
mPlayer.objectBody.quaternion.set(0, mPlayer.yawObject.rotation.y, 0, 1);
It also changes the Y-position of the object, not just the rotation.
Here's a demo (WASD to move the red rectangle - which is what I want to rotate)
Here's the main script
At the moment it automatically rotates based on the physics. Thanks for the help!
EDIT:
I've sort of got it working now. But it doesn't rotate fully (the whole 360 degrees) and the angle it rotates isn't quite right. If someone could take a look and see what's wrong I would really appreciate it! :)
Same link as before but the rectangle/body is below the camera now, so I can see if it's rotating correctly.
I added this code to make it rotate:
mPlayer.objectBody.quaternion.y = mPlayer.yawObject.rotation.y;
mPlayer.objectBody.quaternion.w = 1;
mPlayer.objectBody.quaternion.normalize();
To save you looking through the code, mPlayer.yawObject.rotation.y
is set in the MouseMove event:
var onMouseMove = function ( event ) {
var movementX = event.movementX || event.mozMovementX || event.webkitMovementX || 0;
var movementY = event.movementY || event.mozMovementY || event.webkitMovementY || 0;
mPlayer.yawObject.rotation.y -= movementX * 0.002;
mPlayer.pitchObject.rotation.x -= movementY * 0.002;
mPlayer.pitchObject.rotation.x = Math.max( - PI_2, Math.min( PI_2, mPlayer.pitchObject.rotation.x ) );
};
Thanks again!
Source: (StackOverflow)
I'm creating simple car game with cannon.js and I'm struggling with this.
What I want to do:
When I run with car into another object (e.g. sphere) I want to know about it.
For example increase score or whatever, but without applying forces to both objects.
What I unsuccesfully tried:
Use
chassisBody.addEventListener("collide",function(e){ "mycode"};
with combination groups
var GROUP1 = 1; etc..
but point of groups I guess is mark which object I want and don't want to collide, and I want them to "collide" but without actually applying forces to them, only registering that their bodies intersected and firing my scoring code etc.
( I added threejs tag just in case someone might have stumbled across this, and I'm using it anyway )
Source: (StackOverflow)
I understand that I can use body.position.set(x, y, z) to instantaneously move a body, but how can I move it smoothly in an animated manner where it's movement will adhere to the physics and collide with any other bodies on its journey? Using body.velocity.set(x, y, z) will set its velocity, and using body.linearDamping = v, will provide some friction/resistance... but it's still not good enough to allow me to specify exactly where I want the body to stop.
Source: (StackOverflow)
I'm tinkering a bit with cannon.js and three.js, and i wish to have terrain. This would require a custom CANNON.RigidBody
. I've seen the predefined shapes, like plane, box and sphere, but i cannot seem to figure out where or how cannon defines its shapes. is there a way to create a CANNON.RigidBody
from a THREE.Geometry
, or THREE.Mesh
or even define it poly, by poly?
Source: (StackOverflow)
Is there an easy way to make the camera behave like a body so that it can collide with other bodies?
Source: (StackOverflow)
Is it possible to store user data in a CANNON.Body
object for later use? For example:
var ballBody = new CANNON.Body({ mass: 1 });
ballBody.userData = { name: 'tester' };
// ...
world.add(ballBody);
// ...
player.addEventListener('collide', function(e) {
console.log(e.contact.bi.userData.name); // ==> tester
});
Source: (StackOverflow)
when i try to make collision between a platform created with cannon.js an another box... the collision depend of the position where i put this box. Sometimes the box go throught de plattform.
However if i make a collision between this platfmorm and a sphere its run pefectly.
My cuestion is,Why is happen this?
And most important... What can i do to solve its?
please excuse my posibles erros writting... my level of english is not good jeje.
Here is the code, thanks in advance:
<!DOCTYPE html>
<html>
<head>
<title>pruebas</title>
<style>canvas { width: 100%; height: 100% }
body {margin:0px; padding: 0px}
</style>
<script src="JS/ThreeJS/three.js"></script>
<script src="JS/cannon.js"></script>
</head>
<body>
<script>
//************************************** FISICA
var world = new CANNON.World();
world.gravity.set(0,-50,0);
world.broadphase = new CANNON.NaiveBroadphase();
//*************************************** RENDERER
var scene = new THREE.Scene();
var renderer = new THREE.WebGLRenderer( { antialias: true } );
document.body.appendChild(renderer.domElement);
renderer.setClearColor("#000000");
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMapEnabled = true;
renderer.shadowMapSoft = true;
//**************************************** LIGHT
var light = new THREE.SpotLight("white");
light.position.set(-180,100,-90);
light.castShadow = true;
light.shadowDarkness = 1;
light.intensity = 3;
scene.add(light);
//****************************************** PLATFORMS
//plane_fisic
var groundShape = new CANNON.Plane();
var groundBody = new CANNON.RigidBody(0,groundShape);
groundBody.quaternion.setFromAxisAngle(new CANNON.Vec3(1,0,0),-Math.PI/2);
world.add(groundBody);
//plane_mesh
var geometry = new THREE.PlaneGeometry( 300, 300, 50, 50 );
geometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) );
var material = new THREE.MeshLambertMaterial( { color: 0xdddddd } );
var plano = new THREE.Mesh( geometry, material );
plano.castShadow = true;
plano.receiveShadow = true;
scene.add(plano);
//box_fisic
var forma = new CANNON.Box(new CANNON.Vec3(80,5,50));
var mass = 0;
var alma_table = new CANNON.RigidBody(mass,forma);
alma_table.position.y = 35;
alma_table.useQuaternion = true;
world.add(alma_table);
//box_mesh
var floorMaterial = new THREE.MeshPhongMaterial();
var tableGeometry = new THREE.CubeGeometry(160,10,100);
var table = new THREE.Mesh(tableGeometry,floorMaterial);
table.castShadow = true;
table.receiveShadow = true;
table.ambientLightColor = true;
scene.add(table);
//************************************** OBJETS
//BOX
//fisic
var forma = new CANNON.Box(new CANNON.Vec3(8,8,8));
var mass = 2;
var box_alma = new CANNON.RigidBody(mass,forma);
box_alma.position.y = 80;
box_alma.position.x = 0;
box_alma.position.z = 0;
box_alma.useQuaternion = true;
world.add(box_alma);
//mesh
var floorMaterial = new THREE.MeshPhongMaterial();
var tableGeometry =new THREE.CubeGeometry(16,16,16);
var box = new THREE.Mesh(tableGeometry,floorMaterial);
box.castShadow = true;
box.receiveShadow = true;
box.ambientLightColor = true;
scene.add(box);
//BOX2
//fisic
var forma = new CANNON.Box(new CANNON.Vec3(8,8,8));
var mass = 2;
var box_alma2 = new CANNON.RigidBody(mass,forma);
box_alma2.position.y = 80;
box_alma2.position.x = -40;
box_alma2.position.z = +20;
box_alma2.useQuaternion = true;
world.add(box_alma2);
//mesh
var floorMaterial = new THREE.MeshPhongMaterial();
var tableGeometry =new THREE.CubeGeometry(16,16,16);
var box2 = new THREE.Mesh(tableGeometry,floorMaterial);
box2.castShadow = true;
box2.receiveShadow = true;
box2.ambientLightColor = true;
scene.add(box2);
//BOX3
//fisic
var forma = new CANNON.Box(new CANNON.Vec3(8,8,8));
var mass = 2;
var box_alma3 = new CANNON.RigidBody(mass,forma);
box_alma3.position.y = 80;
box_alma3.position.x = 50;
box_alma3.position.z = 0;
box_alma3.useQuaternion = true;
world.add(box_alma3);
//mesh
var floorMaterial = new THREE.MeshPhongMaterial();
var tableGeometry =new THREE.CubeGeometry(16,16,16);
var box3 = new THREE.Mesh(tableGeometry,floorMaterial);
box3.castShadow = true;
box3.receiveShadow = true;
box3.ambientLightColor = true;
scene.add(box3);
//****************************************************** CÁMARA
var camera = new THREE.PerspectiveCamera(40, window.innerWidth/window.innerHeight, 0.1, 150000);
camera.position.z =300;
camera.position.y=130;
camera.position.x=0;
camera.lookAt(scene.position)
update = function(){
world.step(1/60);
alma_table.position.copy(table.position);
alma_table.quaternion.copy(table.quaternion);
box_alma2.position.copy(box2.position);
box_alma2.quaternion.copy(box2.quaternion);
box_alma.position.copy(box.position);
box_alma.quaternion.copy(box.quaternion);
box_alma3.position.copy(box3.position);
box_alma3.quaternion.copy(box3.quaternion);
}
var loop = function () {
requestAnimationFrame(loop);
renderer.render(scene,camera);
update();
}
loop();
</script>
</body>
</html>
Source: (StackOverflow)
here is a demo
i have recently started using three.js (i am familiar with OpenGL and C++ so doing this in javascript is not a huge learning curve) i have looked through a lot of the three.js examples to understand how to set things up and i saw this video [xttp://www.youtube.com/watch?v=1ENVYLp_NgY] explaining how to include cannon.js and i wanted to experiment with that also :)
my goal is to have a 3D world with shadows and physics with an animated player that can interact with the other objects. I chose this example [xttp://threejs.org/examples/webgl_morphtargets_md2_control.html] as a starting point because it already had the animated player mesh and the player controls were also about right, i added OrbitControls to the camera so that it can look around.
everything seems to work well except whenever i try to link the player mesh to any kind of object that exists in the physics world (so that he can repel / push the stone blocks), i wanted to start simple to avoid any confusion because of the player mesh being a compound object (imported md2), so i just use a basic sphere shape, but if i try to update the coordinates of the object in the physics world so that it will follow whenever the player mesh moves, the player mesh animates but does not move (so i uncommented those lines in the update() function).
/**
* Problem: This prevents player from moving :(
**/
player.position.copy( playerMesh.root.position );
player.quaternion.copy( playerMesh.root.quaternion );
player.velocity.copy( new THREE.Vector3() );
there is also something called a "gyro" involved in the md2 player mesh object which seems to move the light position so that it coordinates with player movement but i'm not sure how that happens (the gyroscope part is not something i understand but i'm not sure if thats part of the problem either).
the code repo is hosted on github
UPDATE: Fixed, please see the commit on github :)
Source: (StackOverflow)
Noob Question: I'm trying to drop a ball to the floor and make it stick there or even roll over a plane. Right now it passes trough the plane. I'm not sure where I made a mistake or if I'm doing anything wrong.
var world, timeStep=1/60, scene, renderer, camera,
icosahedronBody, sphereShape, groundShape,
ground, groundBody, groundShape;
// CONSTANTS
var GRID_HELPER_SIZE = 40,
GRID_HELPER_STEP = 2,
MASS = 5;
initThree();
initCannon();
animate();
function initCannon() {
world = new CANNON.World();
world.broadphase = new CANNON.NaiveBroadphase();
sphereShape = new CANNON.Sphere();
groundShape = new CANNON.Plane();
icosahedronBody = new CANNON.Body({
mass: MASS,
});
groundBody = new CANNON.Body({
mass: 0, // mass == 0 makes the body static
});
world.solver.iterations = 10;
world.gravity.set(0,-9.8,0);
world.defaultContactMaterial.contactEquationStiffness = 1e9;
world.defaultContactMaterial.contactEquationRegularizationTime = 4;
icosahedronBody.addShape(sphereShape);
icosahedronBody.position.set(0,50,0)
icosahedronBody.linearDamping = 0.5;
world.addBody(icosahedronBody);
groundBody.addShape(groundShape);
groundBody.quaternion.setFromAxisAngle(new CANNON.Vec3(0,1,0),-Math.PI/2);
world.addBody(groundBody);
var ballContact = new CANNON.ContactMaterial( groundBody, icosahedronBody, 0.0, 0.0);
world.addContactMaterial(ballContact);
}
function initThree(){
// INITIALIZE CANVAS
scene = new THREE.Scene();
renderer = new THREE.WebGLRenderer();
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
var light = new THREE.AmbientLight( 0x404040 ),
directionalLight = new THREE.DirectionalLight( 0xffffff ),
gridHelper = new THREE.GridHelper( GRID_HELPER_SIZE, GRID_HELPER_STEP );
renderer.setSize( window.innerWidth - 100 , window.innerHeight - 100 );
renderer.setClearColor( 0x757575 );
document.body.appendChild( renderer.domElement );
camera.position.set(1,25,100); // camera position to x , y , z
camera.lookAt( new THREE.Vector3() )
directionalLight.position.set( 1, 0.75, 0.5 ).normalize();
// INITIAL CANVAS
scene.add( directionalLight );
scene.add( light );
scene.add( camera );
scene.add( gridHelper );
// MATERIALS
var icoGeometry = new THREE.IcosahedronGeometry(10, 1),
icoMaterial = new THREE.MeshLambertMaterial( {color: 0xff0000} );
icosahedron = new THREE.Mesh( icoGeometry, icoMaterial );
var groundGeometry = new THREE.BoxGeometry(100 , 1, 100),
groundMaterial = new THREE.MeshLambertMaterial( {color: 0xcccccc} );
ground = new THREE.Mesh( groundGeometry, groundMaterial );
ground.receiveShadow = true;
// ADD OBJECTS TO SCENE
scene.add( icosahedron );
scene.add( ground );
}
function animate() {
requestAnimationFrame( animate );
updatePhysics();
render();
}
function updatePhysics() {
// Step the physics world
world.step(timeStep);
// Copy coordinates from Cannon.js to Three.js
icosahedron.position.copy(icosahedronBody.position);
icosahedron.quaternion.copy(icosahedronBody.quaternion);
ground.position.copy(groundBody.position);
ground.quaternion.copy(groundBody.quaternion);
}
function render() {
renderer.render( scene, camera );
}
Source: (StackOverflow)
I'm just getting started with Three.js and cannon.js and I've been trying to create a simple room for a while with no success. I'm working off of this example and I've been trying to add walls and a ceiling. What is the easiest way to do this? Right now I have
// wall?
wallGeometry = new THREE.PlaneGeometry( 300, 300 );
wallGeometry.applyMatrix( new THREE.Matrix4().makeRotationX( Math.PI));
wallMesh = new THREE.Mesh( wallGeometry, material );
wallMesh.castShadow = false;
wallMesh.receiveShadow = true;
scene.add(wallMesh);
But it's light up weird and I don't bump into it.... And if I try to add it through cannon.js I get an invisible wall but can't see it. Can anyone point me to the right direction?
Source: (StackOverflow)
(This question is targeted at Cannon.js (by @schteppe), but hopefully answer(s) will be applicable to other engines for the benefit of others not using Cannon.)
It seems like one strategy for building a huge spherical world in a physics engine is to start with 6 heightmaps forming a cube, and then to warp that cube into a sphere (the "cubic sphere" approach, see this explanation).
So that approach looks fine, and I was about to implement it just because it's what everyone else seems to be doing, but I've got a nagging (and very likely naive) question in the back of my head:
Why not just generate a (non-rigidbody) spherical surface and use it
in the pre-step of the simulation to provide a reaction force
against vertices that fall below that surface? Are there any problems
with this approach that make people avoid it and choose the cube
sphere approach instead?
Gravity on all objects is allso applied during the pre-step, so it seems like it would just be a matter of checking the object's vertices while I'm at it?
In my particular case the world doesn't need to be high-resolution, and could even be a blocky, minecraft-type world. It also doesn't need any textures or anything like that, if that has some impact on many people choosing the cube sphere approach. Thanks!
Source: (StackOverflow)
This has to do with Three.js + Socket IO + CANNON.js. I have an CANNON.RigidBody object on my SERVER, that i cannot send as it is. So i transform it like this:
// Create a sphere
var mass = 5,
radius = 1.8;
var sphereShape = new CANNON.Sphere(radius);
var physicsMaterial = new CANNON.Material("slipperyMaterial");
var sphereBody = new CANNON.RigidBody(mass, sphereShape, physicsMaterial);
sphereBody.position.set(0, 10, 0);
sphereBody.linearDamping = 0.9;
cannonWorld.add(sphereBody);
cannonEntities[(numBodies++).toString()] = sphereBody;
player = {
type: "player",
data: {
id:((numBodies++).toString()),
position: sphereBody.position,
quaternion: sphereBody.quaternion,
velocity: sphereBody.velocity,
radius:radius,
mass:mass
} }
and sent it to my CLIENT....
broadcastJsonEvent(JSON.stringify(player))
In my CLIENT i pass this "player" object into my control, Normally instead of player one would pass the CANNON.RigidBody object.
controls = new PointerLockControls(camera, player);
scene.add(controls.getObject());
Because i cannot send the full object which is.... a CANNON.RigidBody i send it as that player object, and in PointerLockControls the last line looks like this... And this is where all fails.
cannonBody.position.copy(yawObject.position);
Now my player object does not have the copy method. What can i do?
Please help. This is what i tried. Remember cannonBody = player!! And even if i get the
copy method it still does not work.
var copyBody = new CANNON.Vec3(cannonBody.position.x,cannonBody.position.y,cannonBody.position.z);
cannonBody = $.extend(cannonBody,new CANNON.RigidBody(cannonBody.mass,new CANNON.Sphere(1.8),new CANNON.Material("slipperyMaterial")));
cannonBody.position = $.extend(copyBody);
cannonBody.position.copy(yawObject.position);
And even if i get the
copy method it still does not work. :(
Source: (StackOverflow)
i've looked in the cannon.js examples, and they seem to mostly use between -10 and -40 for gravity and something between 1 and 10 for the mass of an object (or CANNON.RigidBody as they are called), these demo objects are "well behaved" with these values in that they are just "heavy" enough to overcome gravity and not so "heavy" that they make the ground plane look fake.. by that i mean that i have tried increasing the masses of falling objects and the more mass they have the more they make the floor look like it is made of marshmallow (i.e. spongy) when they land.
(btw: yes, i do know that mass and weight are not the same thing ;-)
gravity is usually 9.8 m/s/s in mathematics so how could that be implemented in CANNON.World.gravity ?
i have found on the internet that the mass of stone is 2515 kilograms/cubic metre, so if i wanted to drop a 1x1x1 metre stone block how would that translate into mass for:
var block = new CANNON.RigidBody(mass, shape, material);
and then there is this material
parameter.. would i need to have 2 materials (1 for the floor and 1 for the stone block) and then how would i set the friction coefficient and restitution values for the materials to react when they collide?
i know this seems like many questions, and i'm not aiming for absolute accuracy, just needing guidance because of a) my lack of knowledge with physics and b) not much documentation for those of us trying to use cannon.js who are not physics professors ;-)
the real question is "How to approximate realism" i guess.
cannon.js is great, works really well, and i really appreciate all the hard work that Stefan Hedman (schteppe) has put into it so far.
Source: (StackOverflow)
I am creating a THREE.Mesh
object using a THREE.JSONLoader
object like so:
// Create castle.
loader.load('/Meshes/CastleTower.js', function(geometry, materials) {
var tmp_material = new THREE.MeshLambertMaterial();
THREE.ColorUtils.adjustHSV(tmp_material.color, 0, 0, 0.9);
var castle = new THREE.Mesh(geometry, tmp_material);
castle.scale.set(0.2, 0.2, 0.2);
castle.rotation.setX(-Math.PI/2);
scene.add(castle);
});
Is it possible to create a CANNON.RigidBody
from the THREE.Mesh
(var castle
) or THREE.Geometry
(var geometry
) object? Another way you could read this is: How do you make any custom THREE.Mesh
"solid"?
Source: (StackOverflow)