EzDevInfo.com

cannon.js

A lightweight 3D physics engine written in JavaScript. schteppe/cannon.js @ GitHub a lightweight and simple 3d physics engine for the web.

Cannon.JS make walls solid

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)

How to rotate a CannonJS RigidBody?

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)

Advertisements

cannon.js registering collision without colliding

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)

Moving a body to a specific position

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)

CANNON.js custom rigid body

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)

How to detect collision between camera and bodies

Is there an easy way to make the camera behave like a body so that it can collide with other bodies?


Source: (StackOverflow)

Store user data in CANNON.Body for later use?

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)

How to do collision between two cubes in cannon.js?

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)

How to control three.js player mesh (md2) when using cannon.js physics?

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)

CannonJS floor. Make a ball stick to the ground

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)

Creating a room with Three.js and cannon.js

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)

Large-scale spherical world in a physics engine

(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)

Convert javaScript object to different object type

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)

What would be "realistic" values for gravity, mass and contact material in cannon.js? [closed]

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)

Create CANNON.RigidBody from THREE.Mesh or THREE.Geometry

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)