/* global CANNON,THREE,Detector */ CANNON = CANNON || {}; /** * Demo framework class. If you want to learn how to connect Cannon.js with Three.js, please look at the examples/ instead. * @class Demo * @constructor * @param {Object} options */ CANNON.Demo = function(options){ var that = this; // API this.addScene = addScene; this.restartCurrentScene = restartCurrentScene; this.changeScene = changeScene; this.start = start; var sceneFolder; // Global settings var settings = this.settings = { stepFrequency: 60, quatNormalizeSkip: 2, quatNormalizeFast: true, gx: 0, gy: 0, gz: 0, iterations: 3, tolerance: 0.0001, k: 1e6, d: 3, scene: 0, paused: false, rendermode: "solid", constraints: false, contacts: false, // Contact points cm2contact: false, // center of mass to contact points normals: false, // contact normals axes: false, // "local" frame axes particleSize: 0.1, shadows: false, aabbs: false, profiling: false, maxSubSteps:3 }; // Extend settings with options options = options || {}; for(var key in options){ if(key in settings){ settings[key] = options[key]; } } if(settings.stepFrequency % 60 !== 0){ throw new Error("stepFrequency must be a multiple of 60."); } var bodies = this.bodies = []; var visuals = this.visuals = []; var scenes = []; var gui = null; var smoothie = null; var smoothieCanvas = null; var scenePicker = {}; var three_contactpoint_geo = new THREE.SphereGeometry( 0.1, 6, 6); var particleGeo = this.particleGeo = new THREE.SphereGeometry( 1, 16, 8 ); // Material var materialColor = 0xdddddd; var solidMaterial = new THREE.MeshLambertMaterial( { color: materialColor } ); //THREE.ColorUtils.adjustHSV( solidMaterial.color, 0, 0, 0.9 ); var wireframeMaterial = new THREE.MeshLambertMaterial( { color: 0xffffff, wireframe:true } ); this.currentMaterial = solidMaterial; var contactDotMaterial = new THREE.MeshLambertMaterial( { color: 0xff0000 } ); var particleMaterial = this.particleMaterial = new THREE.MeshLambertMaterial( { color: 0xff0000 } ); // Geometry caches var contactMeshCache = new GeometryCache(function(){ return new THREE.Mesh( three_contactpoint_geo, contactDotMaterial ); }); var cm2contactMeshCache = new GeometryCache(function(){ var geometry = new THREE.Geometry(); geometry.vertices.push(new THREE.Vector3(0,0,0)); geometry.vertices.push(new THREE.Vector3(1,1,1)); return new THREE.Line( geometry, new THREE.LineBasicMaterial( { color: 0xff0000 } ) ); }); var bboxGeometry = new THREE.BoxGeometry(1,1,1); var bboxMaterial = new THREE.MeshBasicMaterial({ color: materialColor, wireframe:true }); var bboxMeshCache = new GeometryCache(function(){ return new THREE.Mesh(bboxGeometry,bboxMaterial); }); var distanceConstraintMeshCache = new GeometryCache(function(){ var geometry = new THREE.Geometry(); geometry.vertices.push(new THREE.Vector3(0,0,0)); geometry.vertices.push(new THREE.Vector3(1,1,1)); return new THREE.Line( geometry, new THREE.LineBasicMaterial( { color: 0xff0000 } ) ); }); var p2pConstraintMeshCache = new GeometryCache(function(){ var geometry = new THREE.Geometry(); geometry.vertices.push(new THREE.Vector3(0,0,0)); geometry.vertices.push(new THREE.Vector3(1,1,1)); return new THREE.Line( geometry, new THREE.LineBasicMaterial( { color: 0xff0000 } ) ); }); var normalMeshCache = new GeometryCache(function(){ var geometry = new THREE.Geometry(); geometry.vertices.push(new THREE.Vector3(0,0,0)); geometry.vertices.push(new THREE.Vector3(1,1,1)); return new THREE.Line( geometry, new THREE.LineBasicMaterial({color:0x00ff00})); }); var axesMeshCache = new GeometryCache(function(){ var mesh = new THREE.Object3D(); //mesh.useQuaternion = true; var origin = new THREE.Vector3(0,0,0); var gX = new THREE.Geometry(); var gY = new THREE.Geometry(); var gZ = new THREE.Geometry(); gX.vertices.push(origin); gY.vertices.push(origin); gZ.vertices.push(origin); gX.vertices.push(new THREE.Vector3(1,0,0)); gY.vertices.push(new THREE.Vector3(0,1,0)); gZ.vertices.push(new THREE.Vector3(0,0,1)); var lineX = new THREE.Line( gX, new THREE.LineBasicMaterial({color:0xff0000})); var lineY = new THREE.Line( gY, new THREE.LineBasicMaterial({color:0x00ff00})); var lineZ = new THREE.Line( gZ, new THREE.LineBasicMaterial({color:0x0000ff})); mesh.add(lineX); mesh.add(lineY); mesh.add(lineZ); return mesh; }); function restartGeometryCaches(){ contactMeshCache.restart(); contactMeshCache.hideCached(); cm2contactMeshCache.restart(); cm2contactMeshCache.hideCached(); distanceConstraintMeshCache.restart(); distanceConstraintMeshCache.hideCached(); normalMeshCache.restart(); normalMeshCache.hideCached(); } // Create physics world var world = this.world = new CANNON.World(); world.broadphase = new CANNON.NaiveBroadphase(); var renderModes = ["solid","wireframe"]; function updategui(){ if(gui){ // First level for (var i in gui.__controllers){ gui.__controllers[i].updateDisplay(); } // Second level for (var f in gui.__folders){ for (var i in gui.__folders[f].__controllers){ gui.__folders[f].__controllers[i].updateDisplay(); } } } } var light, scene, ambient, stats, info; function setRenderMode(mode){ if(renderModes.indexOf(mode) === -1){ throw new Error("Render mode "+mode+" not found!"); } switch(mode){ case "solid": that.currentMaterial = solidMaterial; light.intensity = 1; ambient.color.setHex(0x222222); break; case "wireframe": that.currentMaterial = wireframeMaterial; light.intensity = 0; ambient.color.setHex(0xffffff); break; } function setMaterial(node,mat){ if(node.material){ node.material = mat; } for(var i=0; i e.keyCode-49 && !document.activeElement.localName.match(/input/)){ changeScene(e.keyCode-49); } break; } } }); function changeScene(n){ that.dispatchEvent({ type: 'destroy' }); settings.paused = false; updategui(); buildScene(n); } function start(){ buildScene(0); } function buildScene(n){ // Remove current bodies and visuals var num = visuals.length; for(var i=0; iid ? j-1 : j; bodies[i] = old_b[j]; visuals[i] = old_v[j]; bodies[i].visualref = old_b[j].visualref; bodies[i].visualref.visualId = i; } } body.visualref.visualId = null; this.scene.remove(body.visualref); body.visualref = null; } }; CANNON.Demo.prototype.removeAllVisuals = function(){ while(this.bodies.length) { this.removeVisual(this.bodies[0]); } }; CANNON.Demo.prototype.shape2mesh = function(body){ var wireframe = this.settings.renderMode === "wireframe"; var obj = new THREE.Object3D(); for (var l = 0; l < body.shapes.length; l++) { var shape = body.shapes[l]; var mesh; switch(shape.type){ case CANNON.Shape.types.SPHERE: var sphere_geometry = new THREE.SphereGeometry( shape.radius, 8, 8); mesh = new THREE.Mesh( sphere_geometry, this.currentMaterial ); break; case CANNON.Shape.types.PARTICLE: mesh = new THREE.Mesh( this.particleGeo, this.particleMaterial ); var s = this.settings; mesh.scale.set(s.particleSize,s.particleSize,s.particleSize); break; case CANNON.Shape.types.PLANE: var geometry = new THREE.PlaneGeometry(10, 10, 4, 4); mesh = new THREE.Object3D(); var submesh = new THREE.Object3D(); var ground = new THREE.Mesh( geometry, this.currentMaterial ); ground.scale.set(100, 100, 100); submesh.add(ground); ground.castShadow = true; ground.receiveShadow = true; mesh.add(submesh); break; case CANNON.Shape.types.BOX: var box_geometry = new THREE.BoxGeometry( shape.halfExtents.x*2, shape.halfExtents.y*2, shape.halfExtents.z*2 ); mesh = new THREE.Mesh( box_geometry, this.currentMaterial ); break; case CANNON.Shape.types.CONVEXPOLYHEDRON: var geo = new THREE.Geometry(); // Add vertices for (var i = 0; i < shape.vertices.length; i++) { var v = shape.vertices[i]; geo.vertices.push(new THREE.Vector3(v.x, v.y, v.z)); } for(var i=0; i < shape.faces.length; i++){ var face = shape.faces[i]; // add triangles var a = face[0]; for (var j = 1; j < face.length - 1; j++) { var b = face[j]; var c = face[j + 1]; geo.faces.push(new THREE.Face3(a, b, c)); } } geo.computeBoundingSphere(); geo.computeFaceNormals(); mesh = new THREE.Mesh( geo, this.currentMaterial ); break; case CANNON.Shape.types.HEIGHTFIELD: var geometry = new THREE.Geometry(); var v0 = new CANNON.Vec3(); var v1 = new CANNON.Vec3(); var v2 = new CANNON.Vec3(); for (var xi = 0; xi < shape.data.length - 1; xi++) { for (var yi = 0; yi < shape.data[xi].length - 1; yi++) { for (var k = 0; k < 2; k++) { shape.getConvexTrianglePillar(xi, yi, k===0); v0.copy(shape.pillarConvex.vertices[0]); v1.copy(shape.pillarConvex.vertices[1]); v2.copy(shape.pillarConvex.vertices[2]); v0.vadd(shape.pillarOffset, v0); v1.vadd(shape.pillarOffset, v1); v2.vadd(shape.pillarOffset, v2); geometry.vertices.push( new THREE.Vector3(v0.x, v0.y, v0.z), new THREE.Vector3(v1.x, v1.y, v1.z), new THREE.Vector3(v2.x, v2.y, v2.z) ); var i = geometry.vertices.length - 3; geometry.faces.push(new THREE.Face3(i, i+1, i+2)); } } } geometry.computeBoundingSphere(); geometry.computeFaceNormals(); mesh = new THREE.Mesh(geometry, this.currentMaterial); break; case CANNON.Shape.types.TRIMESH: var geometry = new THREE.Geometry(); var v0 = new CANNON.Vec3(); var v1 = new CANNON.Vec3(); var v2 = new CANNON.Vec3(); for (var i = 0; i < shape.indices.length / 3; i++) { shape.getTriangleVertices(i, v0, v1, v2); geometry.vertices.push( new THREE.Vector3(v0.x, v0.y, v0.z), new THREE.Vector3(v1.x, v1.y, v1.z), new THREE.Vector3(v2.x, v2.y, v2.z) ); var j = geometry.vertices.length - 3; geometry.faces.push(new THREE.Face3(j, j+1, j+2)); } geometry.computeBoundingSphere(); geometry.computeFaceNormals(); mesh = new THREE.Mesh(geometry, this.currentMaterial); break; default: throw "Visual type not recognized: "+shape.type; } mesh.receiveShadow = true; mesh.castShadow = true; if(mesh.children){ for(var i=0; i