UNPKG

cannon

Version:

A lightweight 3D physics engine written in JavaScript.

269 lines (223 loc) 9.15 kB
<!DOCTYPE html> <html lang="en"> <head> <title>cannon.js worker example</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"> <style> body { font-family: Monospace; background-color: #000; color: #000; margin: 0px; overflow: hidden; } #info { text-align: center; padding: 10px; z-index: 10; width: 100%; position: absolute; color:white; } a { text-decoration: underline; cursor: pointer; } </style> </head> <body> <div id="info"> <a href="http://github.com/schteppe/cannon.js">Cannon.js</a> web worker example </div> <script src="../libs/Three.js"></script> <script src="../libs/Detector.js"></script> <script src="../libs/TrackballControls.js"></script> <!-- Worker script, will be run in separate thread --> <script id="worker1" type="javascript/worker"> var world; self.onmessage = function(e) { if (e.data.cannonUrl && !world) { // Load cannon.js importScripts(e.data.cannonUrl); // Init physics world = new CANNON.World(); world.broadphase = new CANNON.NaiveBroadphase(); world.gravity.set(0,-10,0); world.solver.tolerance = 0.001; // Ground plane var plane = new CANNON.Plane(); var groundBody = new CANNON.Body({ mass: 0 }); groundBody.addShape(plane); groundBody.quaternion.setFromAxisAngle(new CANNON.Vec3(1,0,0),-Math.PI/2); world.add(groundBody); // Create N cubes var shape = new CANNON.Box(new CANNON.Vec3(0.5,0.5,0.5)); for(var i=0; i!==e.data.N; i++){ var body = new CANNON.Body({ mass: 1 }); body.addShape(shape); body.position.set(Math.random()-0.5,2.5*i+0.5,Math.random()-0.5); world.add(body); } } // Step the world world.step(e.data.dt); // Copy over the data to the buffers var positions = e.data.positions; var quaternions = e.data.quaternions; for(var i=0; i!==world.bodies.length; i++){ var b = world.bodies[i], p = b.position, q = b.quaternion; positions[3*i + 0] = p.x; positions[3*i + 1] = p.y; positions[3*i + 2] = p.z; quaternions[4*i + 0] = q.x; quaternions[4*i + 1] = q.y; quaternions[4*i + 2] = q.z; quaternions[4*i + 3] = q.w; } // Send data back to the main thread self.postMessage({ positions:positions, quaternions:quaternions }, [positions.buffer, quaternions.buffer]); }; </script> <script> // Parameters var dt = 1/60, N=40; // Data arrays. Contains all our kinematic data we need for rendering. var positions = new Float32Array(N*3); var quaternions = new Float32Array(N*4); // Create a blob for the inline worker code var blob = new Blob([document.querySelector('#worker1').textContent],{type:'text/javascript'}); // Create worker var worker = new Worker(window.URL.createObjectURL(blob)); worker.postMessage = worker.webkitPostMessage || worker.postMessage; var sendTime; // Time when we sent last message worker.onmessage = function(e) { // Get fresh data from the worker positions = e.data.positions; quaternions = e.data.quaternions; // Update rendering meshes for(var i=0; i!==meshes.length; i++){ meshes[i].position.set( positions[3*i+0], positions[3*i+1], positions[3*i+2] ); meshes[i].quaternion.set(quaternions[4*i+0], quaternions[4*i+1], quaternions[4*i+2], quaternions[4*i+3]); } // If the worker was faster than the time step (dt seconds), we want to delay the next timestep var delay = dt * 1000 - (Date.now()-sendTime); if(delay < 0){ delay = 0; } setTimeout(sendDataToWorker,delay); } function sendDataToWorker(){ sendTime = Date.now(); worker.postMessage({ N : N, dt : dt, cannonUrl : document.location.href.replace(/\/[^/]*$/,"/") + "../build/cannon.js", positions : positions, quaternions : quaternions },[positions.buffer, quaternions.buffer]); } // Initialize Three.js if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); var container, camera, scene, renderer; var meshes=[]; init(); animate(); function init() { container = document.createElement( 'div' ); document.body.appendChild( container ); // scene scene = new THREE.Scene(); scene.fog = new THREE.Fog( 0x000000, 500, 10000 ); // camera camera = new THREE.PerspectiveCamera( 30, window.innerWidth / window.innerHeight, 0.5, 10000 ); camera.position.set(Math.cos( Math.PI/5 ) * 30, 5, Math.sin( Math.PI/5 ) * 30); scene.add( camera ); // Controls controls = new THREE.TrackballControls( camera ); controls.rotateSpeed = 1.0; controls.zoomSpeed = 1.2; controls.panSpeed = 0.8; controls.noZoom = false; controls.noPan = false; controls.staticMoving = true; controls.dynamicDampingFactor = 0.3; controls.keys = [ 65, 83, 68 ]; // lights var light, materials; scene.add( new THREE.AmbientLight( 0x666666 ) ); light = new THREE.DirectionalLight( 0xffffff, 1.75 ); var d = 20; light.position.set( d, d, d ); light.castShadow = true; //light.shadowCameraVisible = true; light.shadowMapWidth = 1024; light.shadowMapHeight = 1024; light.shadowCameraLeft = -d; light.shadowCameraRight = d; light.shadowCameraTop = d; light.shadowCameraBottom = -d; light.shadowCameraFar = 3*d; light.shadowCameraNear = d; light.shadowDarkness = 0.5; scene.add( light ); // floor geometry = new THREE.PlaneGeometry( 100, 100, 1, 1 ); //geometry.applyMatrix( new THREE.Matrix4().makeRotationX( Math.PI / 2 ) ); material = new THREE.MeshLambertMaterial( { color: 0x777777 } ); //THREE.ColorUtils.adjustHSV( material.color, 0, 0, 0.9 ); mesh = new THREE.Mesh( geometry, material ); mesh.castShadow = true; mesh.receiveShadow = true; meshes.push(mesh); scene.add( mesh ); // cubes var cubeGeo = new THREE.BoxGeometry( 1, 1, 1, 10, 10 ); var cubeMaterial = new THREE.MeshPhongMaterial( { color: 0x888888 } ); for(var i=0; i<N; i++){ cubeMesh = new THREE.Mesh( cubeGeo, cubeMaterial ); cubeMesh.castShadow = true; meshes.push(cubeMesh); scene.add( cubeMesh ); } renderer = new THREE.WebGLRenderer( { antialias: true } ); renderer.setSize( window.innerWidth, window.innerHeight ); renderer.setClearColor( scene.fog.color ); container.appendChild( renderer.domElement ); renderer.gammaInput = true; renderer.gammaOutput = true; renderer.shadowMapEnabled = true; window.addEventListener( 'resize', onWindowResize, false ); } function onWindowResize() { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); controls.handleResize(); renderer.setSize( window.innerWidth, window.innerHeight ); } function animate() { requestAnimationFrame( animate ); controls.update(); render(); } function render() { renderer.render( scene, camera ); } // Start the worker! sendDataToWorker(); </script> </body> </html>