├── README.md ├── raw_box.html ├── raw_point.html ├── raw_sphere.html ├── physics.html ├── api_box.html ├── api_point.html ├── styles.css ├── index.html ├── js ├── api_point.js ├── raw_point.js ├── api_box.js ├── raw_sphere.js ├── raw_box.js ├── common.js ├── physics.js └── lib │ ├── transform-controls.js │ └── cannon.min.js └── LICENSE /README.md: -------------------------------------------------------------------------------- 1 | # JS game development examples - 3D AABB collisions 2 | 3 | This is a collection of examples showcasing collision detection in 3D environments with **Axis-Aligned Bounding-Boxes**. 4 | 5 | You can take a look [at the live demos](http://mozdevs.github.io/gamedev-js-3d-aabb/). 6 | -------------------------------------------------------------------------------- /raw_box.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 3D AABB collisions 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |

3D AABB collisions

16 |

Box vs Box/Sphere (THREE.js Box3 and Sphere)

17 |
18 | 19 |
20 |
21 | 22 | 25 |
26 | 27 | 30 |
31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /raw_point.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 3D AABB collisions 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |

3D AABB collisions

16 |

Point vs Box/Sphere (THREE.js Box3 and Sphere)

17 |
18 | 19 |
20 |
21 | 22 | 25 |
26 | 27 | 30 |
31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /raw_sphere.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 3D AABB collisions 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |

3D AABB collisions

16 |

Sphere vs Box/Sphere (THREE.js Box3 and Sphere)

17 |
18 | 19 |
20 |
21 | 22 | 25 |
26 | 27 | 30 |
31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /physics.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 3D AABB collisions 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |

3D AABB collisions

17 |

Using cannon.js (physics engine)

18 |
19 | 20 |
21 |
22 | 23 | 26 |
27 | 28 | 31 |
32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /api_box.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 3D AABB collisions 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |

3D AABB collisions

16 |

Box vs Box (THREE.js AABB api)

17 |
18 | 19 |
20 |
21 | 22 | 26 |
27 | 28 | 31 |
32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /api_point.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 3D AABB collisions 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |

3D AABB collisions

16 |

Point vs Box (THREE.js AABB api)

17 |
18 | 19 |
20 |
21 | 22 | 26 |
27 | 28 | 31 |
32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: 'Source Code Pro', 'Courier', monospace; 3 | margin: 0; 4 | } 5 | 6 | canvas { 7 | background: #000; 8 | padding: 0; 9 | margin: 0; 10 | } 11 | 12 | a, a:hover, a:visited { 13 | color: #000; 14 | text-decoration: none; 15 | } 16 | 17 | a { 18 | border-bottom: 2px solid #31ffd5; 19 | } 20 | 21 | a:hover { 22 | background:#31ffd5; 23 | } 24 | 25 | .main-wrapper { 26 | width: 512px; 27 | padding-left: 1em; 28 | padding-right: 1em; 29 | margin: 0 auto; 30 | } 31 | 32 | .main-header, .main-footer { 33 | text-align: center; 34 | } 35 | 36 | .subtitle { 37 | font-size: 1.5em; 38 | } 39 | 40 | .main-header { 41 | margin-top: 0; 42 | margin-bottom: 2em; 43 | } 44 | 45 | .main-header h1 { 46 | margin: 0; 47 | background: #31ffd5; 48 | padding: 0.5em 1em; 49 | } 50 | 51 | .main-header a { 52 | color: #000; 53 | text-decoration: none; 54 | } 55 | 56 | .main-footer { 57 | margin-top: 2em; 58 | } 59 | 60 | .canvas-wrapper { 61 | position: relative; 62 | background: red; 63 | height: 512px; 64 | } 65 | 66 | .message { 67 | position: absolute; 68 | color: #fff; 69 | bottom: 0; 70 | left: 0; 71 | right: 0; 72 | padding: 5px; 73 | text-align: center; 74 | } 75 | 76 | .message strong { 77 | color: #31ffd5; 78 | } 79 | 80 | li, p { 81 | line-height: 1.25em; 82 | } 83 | 84 | li { 85 | margin: 0.5em 0; 86 | } 87 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 3D AABB collisions 5 | 6 | 7 | 8 | 9 | 10 |
11 |

3D AABB collisions

12 |

Index

13 |
14 | 15 |
16 |

This is a collection of demos and examples on how to use and implement 17 | 3D Axis-Aligned Bounding-Box collision detection in HTML 5 games.

18 |

It is recommended to also read the companion articles at the 19 | Mozilla Developer Network. 20 |

21 | 22 | 40 | 41 | 44 |
45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /js/api_point.js: -------------------------------------------------------------------------------- 1 | Game.init = function () { 2 | this.debug = false; 3 | 4 | var dotGeo = new THREE.SphereGeometry(0.05); 5 | 6 | this.knot = new THREE.Mesh( 7 | new THREE.TorusKnotGeometry(0.5, 0.1), this.materials.solid); 8 | this.knot.position.x = -3; 9 | this.knot.position.z = 1; 10 | this.knot.position.y = 2; 11 | this.knotBoxHelper = new THREE.BoxHelper(this.knot, 0x00ff00); 12 | this.knotBoxHelper.update(); 13 | this.knotBBox = new THREE.Box3(); 14 | this.knotBBox.setFromObject(this.knotBoxHelper); 15 | this.knotBoxHelper.visible = false; 16 | 17 | this.sphere = new THREE.Mesh( 18 | new THREE.SphereGeometry(1), this.materials.solid); 19 | this.sphere.position.x = 2; 20 | this.sphere.position.y = 2; 21 | this.sphereBoxHelper = new THREE.BoxHelper(this.sphere, 0x00ff00); 22 | this.sphereBoxHelper.update(); 23 | this.sphereBBox = new THREE.Box3(); 24 | this.sphereBBox.setFromObject(this.sphereBoxHelper); 25 | this.sphereBoxHelper.visible = false; 26 | 27 | this.point = new THREE.Mesh(dotGeo, this.materials.dot); 28 | this.point.position.x = 0.5; 29 | this.point.position.z = 2; 30 | this.point.position.y = 1; 31 | this.pointShadow = Utils.createShadow(this.point, this.materials.shadow); 32 | 33 | this.scene.add(this.point); 34 | this.scene.add(this.knot); 35 | this.scene.add(this.knotBoxHelper); 36 | this.scene.add(this.sphere); 37 | this.scene.add(this.sphereBoxHelper); 38 | // add fake shadows 39 | this.scene.add(Utils.createShadow(this.sphere, this.materials.shadow)); 40 | this.scene.add(Utils.createShadow(this.knot, this.materials.shadow)); 41 | this.scene.add(this.pointShadow); 42 | 43 | this.controls = new THREE.TransformControls( 44 | this.camera, this.renderer.domElement); 45 | this.controls.space = 'world'; 46 | this.controls.attach(this.point); 47 | this.scene.add(this.controls); 48 | }; 49 | 50 | Game.update = function (delta) { 51 | this.controls.update(); 52 | 53 | this.knot.rotation.x += (Math.PI / 4) * delta; 54 | this.knotBoxHelper.update(); 55 | this.knotBBox.setFromObject(this.knotBoxHelper); 56 | 57 | Utils.updateShadow(this.pointShadow, this.point); 58 | 59 | this.sphere.material = 60 | this.sphereBBox.containsPoint(this.point.position) 61 | ? this.materials.colliding 62 | : this.materials.solid; 63 | 64 | this.knot.material = this.knotBBox.containsPoint(this.point.position) 65 | ? this.materials.colliding 66 | : this.materials.solid; 67 | }; 68 | 69 | Game.toggleDebug = function () { 70 | this.debug = !this.debug; 71 | this.knotBoxHelper.visible = !!this.debug; 72 | this.sphereBoxHelper.visible = !!this.debug; 73 | }; 74 | -------------------------------------------------------------------------------- /js/raw_point.js: -------------------------------------------------------------------------------- 1 | Game.init = function () { 2 | this.debug = false; 3 | 4 | this.knot = new THREE.Mesh( 5 | new THREE.TorusKnotGeometry(0.5, 0.1), this.materials.solid); 6 | this.knot.position.set(-3, 2, 1); 7 | this.knotBBox = new THREE.Box3(new THREE.Vector3(), new THREE.Vector3()); 8 | 9 | this.sphere = new THREE.Mesh( 10 | new THREE.SphereGeometry(1), this.materials.solid); 11 | this.sphere.position.set(2, 2, 0); 12 | // We now need to call this: 13 | this.sphere.geometry.computeBoundingSphere(); 14 | // because while in the past it was done automatically by Three.js since it was needed for 15 | // frustrum culling, now it seems to not work anymore like that. 16 | this.sphereBBox = new THREE.Sphere( 17 | this.sphere.position, 18 | this.sphere.geometry.boundingSphere.radius); 19 | this.sphereShadow = Utils.createShadow(this.sphere, this.materials.shadow); 20 | 21 | this.point = new THREE.Mesh( 22 | new THREE.SphereGeometry(0.05), this.materials.dot); 23 | this.point.position.set(0.5, 2, 1); 24 | this.pointShadow = Utils.createShadow(this.point, this.materials.shadow); 25 | 26 | // add objects to the scene 27 | this.scene.add(this.point); 28 | this.scene.add(this.knot); 29 | this.scene.add(this.sphere); 30 | 31 | // add fake shadows to the scene 32 | this.scene.add(Utils.createShadow(this.knot, this.materials.shadow)); 33 | this.scene.add(this.sphereShadow); 34 | this.scene.add(this.pointShadow); 35 | 36 | this.controls = new THREE.TransformControls( 37 | this.camera, this.renderer.domElement); 38 | this.controls.space = 'world'; 39 | this.controls.attach(this.point); 40 | this.scene.add(this.controls); 41 | 42 | this.timestamp = 0; 43 | }; 44 | 45 | Game.update = function (delta) { 46 | this.timestamp += delta; 47 | 48 | this.controls.update(); 49 | 50 | // rotate the knot 51 | this.knot.rotation.x += (Math.PI / 4) * delta; 52 | this.knotBBox.setFromObject(this.knot); // re-calculate AABB 53 | 54 | // change sphere size 55 | var scale = 0.25 + Math.abs(Math.sin(this.timestamp)); 56 | this.sphere.scale.set(scale, scale, scale); 57 | // re-calculate bounding sphere 58 | this.sphereBBox.radius = this.sphere.geometry.boundingSphere.radius * scale; 59 | // update shadow size 60 | Utils.updateShadow(this.sphereShadow, this.sphere); 61 | 62 | Utils.updateShadow(this.pointShadow, this.point); 63 | 64 | this.sphere.material = 65 | this.sphereBBox.containsPoint(this.point.position) 66 | ? this.materials.colliding 67 | : this.materials.solid; 68 | 69 | this.knot.material = this.knotBBox.containsPoint(this.point.position) 70 | ? this.materials.colliding 71 | : this.materials.solid; 72 | }; 73 | 74 | Game.toggleDebug = function () { 75 | this.debug = !this.debug; 76 | this.knotBBox.visible = !!this.debug; 77 | this.sphereBBox.visible = !!this.debug; 78 | }; 79 | -------------------------------------------------------------------------------- /js/api_box.js: -------------------------------------------------------------------------------- 1 | Game.init = function () { 2 | this.debug = false; 3 | 4 | this.knot = new THREE.Mesh( 5 | new THREE.TorusKnotGeometry(0.5, 0.1), this.materials.solid); 6 | this.knot.position.x = -3; 7 | this.knot.position.z = 1; 8 | this.knot.position.y = 2; 9 | this.knotBoxHelper = new THREE.BoxHelper(this.knot, 0x00ff00); 10 | this.knotBoxHelper.update(); 11 | this.knotBBox = new THREE.Box3(); 12 | this.knotBBox.setFromObject(this.knotBoxHelper); 13 | this.knotBoxHelper.visible = false; 14 | 15 | this.sphere = new THREE.Mesh( 16 | new THREE.SphereGeometry(1), this.materials.solid); 17 | this.sphere.position.x = 2; 18 | this.sphere.position.y = 2; 19 | this.sphereBoxHelper = new THREE.BoxHelper(this.sphere, 0x00ff00); 20 | this.sphereBoxHelper.update(); 21 | this.sphereBBox = new THREE.Box3(); 22 | this.sphereBBox.setFromObject(this.sphereBoxHelper); 23 | this.sphereBoxHelper.visible = false; 24 | 25 | // the object the user can control to check for collisions 26 | this.cube = new THREE.Mesh(new THREE.BoxGeometry(0.75, 0.75, 0.5), 27 | this.materials.solid); 28 | this.cube.position.set(0.5, 1, 2); 29 | this.cubeShadow = Utils.createShadow(this.cube, this.materials.shadow); 30 | this.cubeBoxHelper = new THREE.BoxHelper(this.cube, 0x00ff00); 31 | this.cubeBoxHelper.update(); 32 | this.cubeBBox = new THREE.Box3(); 33 | this.cubeBBox.setFromObject(this.cubeBoxHelper); 34 | this.cubeBoxHelper.visible = false; 35 | 36 | this.scene.add(this.cube); 37 | this.scene.add(this.cubeBoxHelper); 38 | this.scene.add(this.knot); 39 | this.scene.add(this.knotBoxHelper); 40 | this.scene.add(this.sphere); 41 | this.scene.add(this.sphereBoxHelper); 42 | // add fake shadows 43 | this.scene.add(Utils.createShadow(this.sphere, this.materials.shadow)); 44 | this.scene.add(Utils.createShadow(this.knot, this.materials.shadow)); 45 | this.scene.add(this.cubeShadow); 46 | 47 | this.controls = new THREE.TransformControls( 48 | this.camera, this.renderer.domElement); 49 | this.controls.space = 'world'; 50 | this.controls.attach(this.cube); 51 | this.scene.add(this.controls); 52 | }; 53 | 54 | Game.update = function (delta) { 55 | this.controls.update(); 56 | 57 | this.knot.rotation.x += (Math.PI / 4) * delta; 58 | this.knotBoxHelper.update(); 59 | this.knotBBox.setFromObject(this.knotBoxHelper); 60 | 61 | Utils.updateShadow(this.cubeShadow, this.cube); 62 | this.cubeBoxHelper.update(); // update the BoxHelper to match the cube's position 63 | this.cubeBBox.setFromObject(this.cubeBoxHelper); 64 | 65 | this.sphere.material = 66 | this.sphereBBox.intersectsBox(this.cubeBBox) 67 | ? this.materials.colliding 68 | : this.materials.solid; 69 | 70 | this.knot.material = this.knotBBox.intersectsBox(this.cubeBBox) 71 | ? this.materials.colliding 72 | : this.materials.solid; 73 | }; 74 | 75 | Game.toggleDebug = function () { 76 | this.debug = !this.debug; 77 | this.knotBoxHelper.visible = !!this.debug; 78 | this.sphereBoxHelper.visible = !!this.debug; 79 | this.cubeBoxHelper.visible = !!this.debug; 80 | }; 81 | -------------------------------------------------------------------------------- /js/raw_sphere.js: -------------------------------------------------------------------------------- 1 | // expand THREE.js Sphere to support collision tests versus Box3 2 | // we are creating a vector outside the method scope to avoid spawning a new 3 | // instance of Vector3 in every check 4 | THREE.Sphere.__closest = new THREE.Vector3(); 5 | THREE.Sphere.prototype.intersectsBox = function (box) { 6 | // get box closest point to sphere center by clamping 7 | THREE.Sphere.__closest.set(this.center.x, this.center.y, this.center.z); 8 | THREE.Sphere.__closest.clamp(box.min, box.max); 9 | 10 | var distance = this.center.distanceToSquared(THREE.Sphere.__closest); 11 | return distance < (this.radius * this.radius); 12 | }; 13 | 14 | Game.init = function () { 15 | this.debug = false; 16 | 17 | this.knot = new THREE.Mesh( 18 | new THREE.TorusKnotGeometry(0.5, 0.1), this.materials.solid); 19 | this.knot.position.set(-3, 2, 1); 20 | this.knotBBox = new THREE.Box3(new THREE.Vector3(), new THREE.Vector3()); 21 | 22 | this.sphere = new THREE.Mesh( 23 | new THREE.SphereGeometry(1), this.materials.solid); 24 | this.sphere.position.set(2, 2, 0); 25 | // We now need to call this: 26 | this.sphere.geometry.computeBoundingSphere(); 27 | // because while in the past it was done automatically by Three.js since it was needed for 28 | // frustrum culling, now it seems to not work anymore like that. 29 | this.sphereBBox = new THREE.Sphere( 30 | this.sphere.position, 31 | this.sphere.geometry.boundingSphere.radius); 32 | this.sphereShadow = Utils.createShadow(this.sphere, this.materials.shadow); 33 | 34 | // the object the user can control to check for collisions 35 | this.ball = new THREE.Mesh(new THREE.SphereGeometry(0.5), 36 | this.materials.solid); 37 | this.ball.position.set(1, 1, 2); 38 | this.ballShadow = Utils.createShadow(this.ball, this.materials.shadow); 39 | this.ballBBox = new THREE.Sphere( 40 | this.ball.position, this.ball.geometry.boundingSphere.radius); 41 | 42 | // add objects to the scene 43 | this.scene.add(this.ball); 44 | this.scene.add(this.knot); 45 | this.scene.add(this.sphere); 46 | 47 | // add fake shadows to the scene 48 | this.scene.add(Utils.createShadow(this.knot, this.materials.shadow)); 49 | this.scene.add(this.sphereShadow); 50 | this.scene.add(this.ballShadow); 51 | 52 | this.controls = new THREE.TransformControls( 53 | this.camera, this.renderer.domElement); 54 | this.controls.space = 'world'; 55 | this.controls.attach(this.ball); 56 | this.scene.add(this.controls); 57 | 58 | this.timestamp = 0; 59 | }; 60 | 61 | Game.update = function (delta) { 62 | this.timestamp += delta; 63 | 64 | this.controls.update(); 65 | 66 | // rotate the knot 67 | this.knot.rotation.x += (Math.PI / 4) * delta; 68 | this.knotBBox.setFromObject(this.knot); // re-calculate AABB 69 | 70 | // change sphere size 71 | var scale = 0.25 + Math.abs(Math.sin(this.timestamp)); 72 | this.sphere.scale.set(scale, scale, scale); 73 | // re-calculate bounding sphere 74 | this.sphereBBox.radius = this.sphere.geometry.boundingSphere.radius * scale; 75 | // update shadow size 76 | Utils.updateShadow(this.sphereShadow, this.sphere); 77 | 78 | // update the ball AABB position and shadow 79 | this.ballBBox.center.set( 80 | this.ball.position.x, this.ball.position.y, this.ball.position.z); 81 | Utils.updateShadow(this.ballShadow, this.ball); 82 | 83 | this.sphere.material = 84 | this.sphereBBox.intersectsSphere(this.ballBBox) 85 | ? this.materials.colliding 86 | : this.materials.solid; 87 | 88 | this.knot.material = this.ballBBox.intersectsBox(this.knotBBox) 89 | ? this.materials.colliding 90 | : this.materials.solid; 91 | }; 92 | -------------------------------------------------------------------------------- /js/raw_box.js: -------------------------------------------------------------------------------- 1 | // expand THREE.js Sphere to support collision tests versus Box3 2 | // we are creating a vector outside the method scope to avoid spawning a new 3 | // instance of Vector3 in every check 4 | THREE.Sphere.__closest = new THREE.Vector3(); 5 | THREE.Sphere.prototype.intersectsBox = function (box) { 6 | // get box closest point to sphere center by clamping 7 | THREE.Sphere.__closest.set(this.center.x, this.center.y, this.center.z); 8 | THREE.Sphere.__closest.clamp(box.min, box.max); 9 | 10 | var distance = this.center.distanceToSquared(THREE.Sphere.__closest); 11 | return distance < (this.radius * this.radius); 12 | }; 13 | 14 | Game.init = function () { 15 | this.debug = false; 16 | 17 | this.knot = new THREE.Mesh( 18 | new THREE.TorusKnotGeometry(0.5, 0.1), this.materials.solid); 19 | this.knot.position.set(-3, 2, 1); 20 | this.knotBBox = new THREE.Box3(new THREE.Vector3(), new THREE.Vector3()); 21 | 22 | this.sphere = new THREE.Mesh( 23 | new THREE.SphereGeometry(1), this.materials.solid); 24 | this.sphere.position.set(2, 2, 0); 25 | // We now need to call this: 26 | this.sphere.geometry.computeBoundingSphere(); 27 | // because while in the past it was done automatically by Three.js since it was needed for 28 | // frustrum culling, now it seems to not work anymore like that. 29 | this.sphereBBox = new THREE.Sphere( 30 | this.sphere.position, 31 | this.sphere.geometry.boundingSphere.radius); 32 | this.sphereShadow = Utils.createShadow(this.sphere, this.materials.shadow); 33 | 34 | // the object the user can control to check for collisions 35 | this.cube = new THREE.Mesh(new THREE.BoxGeometry(0.75, 0.75, 0.5), 36 | this.materials.solid); 37 | this.cube.position.set(2, 2, 2); 38 | this.cubeShadow = Utils.createShadow(this.cube, this.materials.shadow); 39 | this.cubeBBox = new THREE.Box3(new THREE.Vector3(), new THREE.Vector3()); 40 | 41 | // add objects to the scene 42 | this.scene.add(this.cube); 43 | this.scene.add(this.knot); 44 | this.scene.add(this.sphere); 45 | 46 | // add fake shadows to the scene 47 | this.scene.add(Utils.createShadow(this.knot, this.materials.shadow)); 48 | this.scene.add(this.sphereShadow); 49 | this.scene.add(this.cubeShadow); 50 | 51 | this.controls = new THREE.TransformControls( 52 | this.camera, this.renderer.domElement); 53 | this.controls.space = 'world'; 54 | this.controls.attach(this.cube); 55 | this.scene.add(this.controls); 56 | 57 | this.timestamp = 0; 58 | }; 59 | 60 | Game.update = function (delta) { 61 | this.timestamp += delta; 62 | 63 | this.controls.update(); 64 | 65 | // rotate the knot 66 | this.knot.rotation.x += (Math.PI / 4) * delta; 67 | this.knotBBox.setFromObject(this.knot); // re-calculate AABB 68 | 69 | // change sphere size 70 | var scale = 0.25 + Math.abs(Math.sin(this.timestamp)); 71 | this.sphere.scale.set(scale, scale, scale); 72 | // re-calculate bounding sphere 73 | this.sphereBBox.radius = this.sphere.geometry.boundingSphere.radius * scale; 74 | // update shadow size 75 | Utils.updateShadow(this.sphereShadow, this.sphere); 76 | 77 | // update the cube AABB and shadow 78 | this.cubeBBox.setFromObject(this.cube); 79 | Utils.updateShadow(this.cubeShadow, this.cube); 80 | 81 | this.sphere.material = 82 | this.sphereBBox.intersectsBox(this.cubeBBox) 83 | ? this.materials.colliding 84 | : this.materials.solid; 85 | 86 | this.knot.material = this.knotBBox.intersectsBox(this.cubeBBox) 87 | ? this.materials.colliding 88 | : this.materials.solid; 89 | }; 90 | 91 | Game.toggleDebug = function () { 92 | this.debug = !this.debug; 93 | this.knotBBox.visible = !!this.debug; 94 | this.sphereBBox.visible = !!this.debug; 95 | }; 96 | -------------------------------------------------------------------------------- /js/common.js: -------------------------------------------------------------------------------- 1 | // 2 | // Game singleton 3 | // 4 | 5 | var Game = {}; 6 | 7 | Game.run = function () { 8 | var WIDTH = 512; 9 | var HEIGHT = 512; 10 | 11 | this._previousElapsed = 0; 12 | 13 | // setup a WebGL renderer within an existing canvas 14 | var canvas = document.getElementById('demo'); 15 | this.renderer = new THREE.WebGLRenderer({canvas: canvas}); 16 | canvas.width = WIDTH; 17 | canvas.height = HEIGHT; 18 | this.renderer.setViewport(0, 0, WIDTH, HEIGHT); 19 | 20 | // create the scene 21 | this.scene = new THREE.Scene(); 22 | 23 | // create an isometric camera 24 | this.camera = new THREE.OrthographicCamera( 25 | -5, 5, 5, -5, -1, 100); 26 | this.camera.position.z = 5; 27 | this.camera.position.y = 5; 28 | this.camera.position.x = 5; 29 | this.camera.lookAt(this.scene.position); // point at origin 30 | 31 | // create ground and axis / grid helpers 32 | var ground = new THREE.Mesh(new THREE.PlaneGeometry(10, 10), 33 | new THREE.MeshBasicMaterial({color: 0xcccccc})); 34 | ground.rotation.x = -Math.PI / 2; 35 | ground.position.y = -0.01; // to avoid z-fighting with axis and shadows 36 | this.scene.add(ground); 37 | this.scene.add((new THREE.AxesHelper(8))); 38 | 39 | 40 | document.addEventListener('keyup', function (event) { 41 | if (event.keyCode === 27) { // listen for Esc Key 42 | event.preventDefault(); 43 | this.toggleDebug(); 44 | } 45 | }.bind(this)); 46 | 47 | // start up game 48 | this.init(); 49 | window.requestAnimationFrame(this.tick); 50 | }; 51 | 52 | Game.tick = function (elapsed) { 53 | window.requestAnimationFrame(this.tick); 54 | 55 | // compute delta time in seconds -- also cap it 56 | var delta = (elapsed - this._previousElapsed) / 1000.0; 57 | delta = Math.min(delta, 0.25); // maximum delta of 250 ms 58 | this._previousElapsed = elapsed; 59 | 60 | this.update(delta); 61 | this.renderer.render(this.scene, this.camera); 62 | }.bind(Game); 63 | 64 | // collection of materials used in the demos 65 | Game.materials = { 66 | shadow: new THREE.MeshBasicMaterial({ 67 | color: 0x000000, 68 | transparent: true, 69 | opacity: 0.5 70 | }), 71 | solid: new THREE.MeshNormalMaterial({}), 72 | colliding: new THREE.MeshBasicMaterial({ 73 | color: 0xff0000, 74 | transparent: true, 75 | opacity: 0.5 76 | }), 77 | dot: new THREE.MeshBasicMaterial({ 78 | color: 0x0000ff 79 | }) 80 | }; 81 | 82 | // override these methods to create the demo 83 | Game.init = function () {}; 84 | Game.update = function (delta) {}; 85 | Game.toggleDebug = function () {}; 86 | 87 | // 88 | // Utils 89 | // 90 | 91 | var Utils = {}; 92 | 93 | Utils.createShadow = function (mesh, material) { 94 | var params = mesh.geometry.parameters; 95 | mesh.geometry.computeBoundingSphere(); 96 | var geo = mesh.geometry.type === 'BoxGeometry' 97 | ? new THREE.PlaneGeometry(params.width, params.depth) 98 | : new THREE.CircleGeometry(mesh.geometry.boundingSphere.radius, 24); 99 | 100 | var shadow = new THREE.Mesh(geo, material); 101 | shadow.rotation.x = -Math.PI / 2; 102 | shadow.position.x = mesh.position.x; 103 | shadow.position.z = mesh.position.z; 104 | 105 | return shadow; 106 | }; 107 | 108 | Utils.updateShadow = function (shadow, target) { 109 | shadow.position.x = target.position.x; 110 | shadow.position.z = target.position.z; 111 | shadow.visible = target.position.y >= 0; 112 | 113 | shadow.scale.x = target.scale.x; 114 | shadow.scale.y = target.scale.z; 115 | }; 116 | 117 | 118 | // 119 | // main 120 | // 121 | 122 | window.onload = function () { 123 | Game.run(); 124 | }; 125 | -------------------------------------------------------------------------------- /js/physics.js: -------------------------------------------------------------------------------- 1 | Game.init = function () { 2 | this.knot = new THREE.Mesh( 3 | new THREE.TorusKnotGeometry(0.5, 0.1), this.materials.solid); 4 | this.knot.position.set(-3, 2, 1); 5 | this.knot.geometry.computeBoundingSphere(); 6 | 7 | this.sphere = new THREE.Mesh( 8 | new THREE.SphereGeometry(1), this.materials.solid); 9 | this.sphere.position.set(2, 2, 0); 10 | this.sphereShadow = Utils.createShadow(this.sphere, this.materials.shadow); 11 | 12 | // the object the user can control to check for collisions 13 | this.cube = new THREE.Mesh(new THREE.BoxGeometry(0.75, 0.75, 0.75), 14 | this.materials.solid); 15 | this.cube.position.set(2, 2, 1.74); 16 | this.cubeShadow = Utils.createShadow(this.cube, this.materials.shadow); 17 | 18 | // add objects to the scene 19 | this.scene.add(this.cube); 20 | this.scene.add(this.knot); 21 | this.scene.add(this.sphere); 22 | 23 | // add fake shadows to the scene 24 | this.scene.add(Utils.createShadow(this.knot, this.materials.shadow)); 25 | this.scene.add(this.sphereShadow); 26 | this.scene.add(this.cubeShadow); 27 | 28 | this.controls = new THREE.TransformControls( 29 | this.camera, this.renderer.domElement); 30 | this.controls.space = 'world'; 31 | this.controls.attach(this.cube); 32 | this.scene.add(this.controls); 33 | 34 | this.timestamp = 0; 35 | 36 | // setup physic world 37 | this.initPhysicalWorld(); 38 | }; 39 | 40 | Game.update = function (delta) { 41 | this.timestamp += delta; 42 | 43 | // move the cube body with mouse controls 44 | this.controls.update(); 45 | this.cubeBody.position.copy(this.cube.position); 46 | // update the cube shadow 47 | Utils.updateShadow(this.cubeShadow, this.cube); 48 | 49 | // update knot mesh rotation 50 | this.knot.quaternion.copy(this.knotBody.quaternion); 51 | 52 | // reset materials 53 | this.sphere.material = this.materials.solid; 54 | this.knot.material = this.materials.solid; 55 | 56 | this.updatePhysics(delta); 57 | }; 58 | 59 | Game.updatePhysics = function (delta) { 60 | this.world.step(delta); 61 | 62 | this.world.contacts.forEach(function (contact) { 63 | contact.bi.mesh.material = this.materials.colliding; 64 | contact.bj.mesh.material = this.materials.colliding; 65 | this.cube.material = this.materials.solid; 66 | }.bind(this)); 67 | }; 68 | 69 | Game.initPhysicalWorld = function () { 70 | this.world = new CANNON.World(); 71 | 72 | // add physical bodies 73 | this.knotBody = this.addPhysicalBody(this.knot, {mass: 1}); 74 | this.addPhysicalBody(this.sphere, {mass: 1}); 75 | this.cubeBody = this.addPhysicalBody(this.cube, {mass: 1}); 76 | 77 | // register for collide events 78 | this.cubeBody.addEventListener('collide', function (e) { 79 | console.log('Collision!'); 80 | }.bind(this)); 81 | 82 | // rotate the knot 83 | this.knotBody.angularVelocity.x = Math.PI / 4; 84 | }; 85 | 86 | Game.addPhysicalBody = function (mesh, bodyOptions) { 87 | var shape; 88 | // create a Sphere shape for spheres and thorus knots, 89 | // a Box shape otherwise 90 | if (mesh.geometry.type === 'SphereGeometry' || 91 | mesh.geometry.type === 'ThorusKnotGeometry') { 92 | mesh.geometry.computeBoundingSphere(); 93 | shape = new CANNON.Sphere(mesh.geometry.boundingSphere.radius); 94 | } 95 | else { 96 | mesh.geometry.computeBoundingBox(); 97 | var box = mesh.geometry.boundingBox; 98 | shape = new CANNON.Box(new CANNON.Vec3( 99 | (box.max.x - box.min.x) / 2, 100 | (box.max.y - box.min.y) / 2, 101 | (box.max.z - box.min.z) / 2 102 | )); 103 | } 104 | 105 | var body = new CANNON.Body(bodyOptions); 106 | body.addShape(shape); 107 | body.position.copy(mesh.position); 108 | body.computeAABB(); 109 | // disable collision response so objects don't move when they collide 110 | // against each other 111 | body.collisionResponse = false; 112 | // keep a reference to the mesh so we can update its properties later 113 | body.mesh = mesh; 114 | 115 | this.world.addBody(body); 116 | return body; 117 | }; 118 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Mozilla Public License, version 2.0 2 | 3 | 1. Definitions 4 | 5 | 1.1. "Contributor" 6 | 7 | means each individual or legal entity that creates, contributes to the 8 | creation of, or owns Covered Software. 9 | 10 | 1.2. "Contributor Version" 11 | 12 | means the combination of the Contributions of others (if any) used by a 13 | Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | 17 | means Covered Software of a particular Contributor. 18 | 19 | 1.4. "Covered Software" 20 | 21 | means Source Code Form to which the initial Contributor has attached the 22 | notice in Exhibit A, the Executable Form of such Source Code Form, and 23 | Modifications of such Source Code Form, in each case including portions 24 | thereof. 25 | 26 | 1.5. "Incompatible With Secondary Licenses" 27 | means 28 | 29 | a. that the initial Contributor has attached the notice described in 30 | Exhibit B to the Covered Software; or 31 | 32 | b. that the Covered Software was made available under the terms of 33 | version 1.1 or earlier of the License, but not also under the terms of 34 | a Secondary License. 35 | 36 | 1.6. "Executable Form" 37 | 38 | means any form of the work other than Source Code Form. 39 | 40 | 1.7. "Larger Work" 41 | 42 | means a work that combines Covered Software with other material, in a 43 | separate file or files, that is not Covered Software. 44 | 45 | 1.8. "License" 46 | 47 | means this document. 48 | 49 | 1.9. "Licensable" 50 | 51 | means having the right to grant, to the maximum extent possible, whether 52 | at the time of the initial grant or subsequently, any and all of the 53 | rights conveyed by this License. 54 | 55 | 1.10. "Modifications" 56 | 57 | means any of the following: 58 | 59 | a. any file in Source Code Form that results from an addition to, 60 | deletion from, or modification of the contents of Covered Software; or 61 | 62 | b. any new file in Source Code Form that contains any Covered Software. 63 | 64 | 1.11. "Patent Claims" of a Contributor 65 | 66 | means any patent claim(s), including without limitation, method, 67 | process, and apparatus claims, in any patent Licensable by such 68 | Contributor that would be infringed, but for the grant of the License, 69 | by the making, using, selling, offering for sale, having made, import, 70 | or transfer of either its Contributions or its Contributor Version. 71 | 72 | 1.12. "Secondary License" 73 | 74 | means either the GNU General Public License, Version 2.0, the GNU Lesser 75 | General Public License, Version 2.1, the GNU Affero General Public 76 | License, Version 3.0, or any later versions of those licenses. 77 | 78 | 1.13. "Source Code Form" 79 | 80 | means the form of the work preferred for making modifications. 81 | 82 | 1.14. "You" (or "Your") 83 | 84 | means an individual or a legal entity exercising rights under this 85 | License. For legal entities, "You" includes any entity that controls, is 86 | controlled by, or is under common control with You. For purposes of this 87 | definition, "control" means (a) the power, direct or indirect, to cause 88 | the direction or management of such entity, whether by contract or 89 | otherwise, or (b) ownership of more than fifty percent (50%) of the 90 | outstanding shares or beneficial ownership of such entity. 91 | 92 | 93 | 2. License Grants and Conditions 94 | 95 | 2.1. Grants 96 | 97 | Each Contributor hereby grants You a world-wide, royalty-free, 98 | non-exclusive license: 99 | 100 | a. under intellectual property rights (other than patent or trademark) 101 | Licensable by such Contributor to use, reproduce, make available, 102 | modify, display, perform, distribute, and otherwise exploit its 103 | Contributions, either on an unmodified basis, with Modifications, or 104 | as part of a Larger Work; and 105 | 106 | b. under Patent Claims of such Contributor to make, use, sell, offer for 107 | sale, have made, import, and otherwise transfer either its 108 | Contributions or its Contributor Version. 109 | 110 | 2.2. Effective Date 111 | 112 | The licenses granted in Section 2.1 with respect to any Contribution 113 | become effective for each Contribution on the date the Contributor first 114 | distributes such Contribution. 115 | 116 | 2.3. Limitations on Grant Scope 117 | 118 | The licenses granted in this Section 2 are the only rights granted under 119 | this License. No additional rights or licenses will be implied from the 120 | distribution or licensing of Covered Software under this License. 121 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 122 | Contributor: 123 | 124 | a. for any code that a Contributor has removed from Covered Software; or 125 | 126 | b. for infringements caused by: (i) Your and any other third party's 127 | modifications of Covered Software, or (ii) the combination of its 128 | Contributions with other software (except as part of its Contributor 129 | Version); or 130 | 131 | c. under Patent Claims infringed by Covered Software in the absence of 132 | its Contributions. 133 | 134 | This License does not grant any rights in the trademarks, service marks, 135 | or logos of any Contributor (except as may be necessary to comply with 136 | the notice requirements in Section 3.4). 137 | 138 | 2.4. Subsequent Licenses 139 | 140 | No Contributor makes additional grants as a result of Your choice to 141 | distribute the Covered Software under a subsequent version of this 142 | License (see Section 10.2) or under the terms of a Secondary License (if 143 | permitted under the terms of Section 3.3). 144 | 145 | 2.5. Representation 146 | 147 | Each Contributor represents that the Contributor believes its 148 | Contributions are its original creation(s) or it has sufficient rights to 149 | grant the rights to its Contributions conveyed by this License. 150 | 151 | 2.6. Fair Use 152 | 153 | This License is not intended to limit any rights You have under 154 | applicable copyright doctrines of fair use, fair dealing, or other 155 | equivalents. 156 | 157 | 2.7. Conditions 158 | 159 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in 160 | Section 2.1. 161 | 162 | 163 | 3. Responsibilities 164 | 165 | 3.1. Distribution of Source Form 166 | 167 | All distribution of Covered Software in Source Code Form, including any 168 | Modifications that You create or to which You contribute, must be under 169 | the terms of this License. You must inform recipients that the Source 170 | Code Form of the Covered Software is governed by the terms of this 171 | License, and how they can obtain a copy of this License. You may not 172 | attempt to alter or restrict the recipients' rights in the Source Code 173 | Form. 174 | 175 | 3.2. Distribution of Executable Form 176 | 177 | If You distribute Covered Software in Executable Form then: 178 | 179 | a. such Covered Software must also be made available in Source Code Form, 180 | as described in Section 3.1, and You must inform recipients of the 181 | Executable Form how they can obtain a copy of such Source Code Form by 182 | reasonable means in a timely manner, at a charge no more than the cost 183 | of distribution to the recipient; and 184 | 185 | b. You may distribute such Executable Form under the terms of this 186 | License, or sublicense it under different terms, provided that the 187 | license for the Executable Form does not attempt to limit or alter the 188 | recipients' rights in the Source Code Form under this License. 189 | 190 | 3.3. Distribution of a Larger Work 191 | 192 | You may create and distribute a Larger Work under terms of Your choice, 193 | provided that You also comply with the requirements of this License for 194 | the Covered Software. If the Larger Work is a combination of Covered 195 | Software with a work governed by one or more Secondary Licenses, and the 196 | Covered Software is not Incompatible With Secondary Licenses, this 197 | License permits You to additionally distribute such Covered Software 198 | under the terms of such Secondary License(s), so that the recipient of 199 | the Larger Work may, at their option, further distribute the Covered 200 | Software under the terms of either this License or such Secondary 201 | License(s). 202 | 203 | 3.4. Notices 204 | 205 | You may not remove or alter the substance of any license notices 206 | (including copyright notices, patent notices, disclaimers of warranty, or 207 | limitations of liability) contained within the Source Code Form of the 208 | Covered Software, except that You may alter any license notices to the 209 | extent required to remedy known factual inaccuracies. 210 | 211 | 3.5. Application of Additional Terms 212 | 213 | You may choose to offer, and to charge a fee for, warranty, support, 214 | indemnity or liability obligations to one or more recipients of Covered 215 | Software. However, You may do so only on Your own behalf, and not on 216 | behalf of any Contributor. You must make it absolutely clear that any 217 | such warranty, support, indemnity, or liability obligation is offered by 218 | You alone, and You hereby agree to indemnify every Contributor for any 219 | liability incurred by such Contributor as a result of warranty, support, 220 | indemnity or liability terms You offer. You may include additional 221 | disclaimers of warranty and limitations of liability specific to any 222 | jurisdiction. 223 | 224 | 4. Inability to Comply Due to Statute or Regulation 225 | 226 | If it is impossible for You to comply with any of the terms of this License 227 | with respect to some or all of the Covered Software due to statute, 228 | judicial order, or regulation then You must: (a) comply with the terms of 229 | this License to the maximum extent possible; and (b) describe the 230 | limitations and the code they affect. Such description must be placed in a 231 | text file included with all distributions of the Covered Software under 232 | this License. Except to the extent prohibited by statute or regulation, 233 | such description must be sufficiently detailed for a recipient of ordinary 234 | skill to be able to understand it. 235 | 236 | 5. Termination 237 | 238 | 5.1. The rights granted under this License will terminate automatically if You 239 | fail to comply with any of its terms. However, if You become compliant, 240 | then the rights granted under this License from a particular Contributor 241 | are reinstated (a) provisionally, unless and until such Contributor 242 | explicitly and finally terminates Your grants, and (b) on an ongoing 243 | basis, if such Contributor fails to notify You of the non-compliance by 244 | some reasonable means prior to 60 days after You have come back into 245 | compliance. Moreover, Your grants from a particular Contributor are 246 | reinstated on an ongoing basis if such Contributor notifies You of the 247 | non-compliance by some reasonable means, this is the first time You have 248 | received notice of non-compliance with this License from such 249 | Contributor, and You become compliant prior to 30 days after Your receipt 250 | of the notice. 251 | 252 | 5.2. If You initiate litigation against any entity by asserting a patent 253 | infringement claim (excluding declaratory judgment actions, 254 | counter-claims, and cross-claims) alleging that a Contributor Version 255 | directly or indirectly infringes any patent, then the rights granted to 256 | You by any and all Contributors for the Covered Software under Section 257 | 2.1 of this License shall terminate. 258 | 259 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user 260 | license agreements (excluding distributors and resellers) which have been 261 | validly granted by You or Your distributors under this License prior to 262 | termination shall survive termination. 263 | 264 | 6. Disclaimer of Warranty 265 | 266 | Covered Software is provided under this License on an "as is" basis, 267 | without warranty of any kind, either expressed, implied, or statutory, 268 | including, without limitation, warranties that the Covered Software is free 269 | of defects, merchantable, fit for a particular purpose or non-infringing. 270 | The entire risk as to the quality and performance of the Covered Software 271 | is with You. Should any Covered Software prove defective in any respect, 272 | You (not any Contributor) assume the cost of any necessary servicing, 273 | repair, or correction. This disclaimer of warranty constitutes an essential 274 | part of this License. No use of any Covered Software is authorized under 275 | this License except under this disclaimer. 276 | 277 | 7. Limitation of Liability 278 | 279 | Under no circumstances and under no legal theory, whether tort (including 280 | negligence), contract, or otherwise, shall any Contributor, or anyone who 281 | distributes Covered Software as permitted above, be liable to You for any 282 | direct, indirect, special, incidental, or consequential damages of any 283 | character including, without limitation, damages for lost profits, loss of 284 | goodwill, work stoppage, computer failure or malfunction, or any and all 285 | other commercial damages or losses, even if such party shall have been 286 | informed of the possibility of such damages. This limitation of liability 287 | shall not apply to liability for death or personal injury resulting from 288 | such party's negligence to the extent applicable law prohibits such 289 | limitation. Some jurisdictions do not allow the exclusion or limitation of 290 | incidental or consequential damages, so this exclusion and limitation may 291 | not apply to You. 292 | 293 | 8. Litigation 294 | 295 | Any litigation relating to this License may be brought only in the courts 296 | of a jurisdiction where the defendant maintains its principal place of 297 | business and such litigation shall be governed by laws of that 298 | jurisdiction, without reference to its conflict-of-law provisions. Nothing 299 | in this Section shall prevent a party's ability to bring cross-claims or 300 | counter-claims. 301 | 302 | 9. Miscellaneous 303 | 304 | This License represents the complete agreement concerning the subject 305 | matter hereof. If any provision of this License is held to be 306 | unenforceable, such provision shall be reformed only to the extent 307 | necessary to make it enforceable. Any law or regulation which provides that 308 | the language of a contract shall be construed against the drafter shall not 309 | be used to construe this License against a Contributor. 310 | 311 | 312 | 10. Versions of the License 313 | 314 | 10.1. New Versions 315 | 316 | Mozilla Foundation is the license steward. Except as provided in Section 317 | 10.3, no one other than the license steward has the right to modify or 318 | publish new versions of this License. Each version will be given a 319 | distinguishing version number. 320 | 321 | 10.2. Effect of New Versions 322 | 323 | You may distribute the Covered Software under the terms of the version 324 | of the License under which You originally received the Covered Software, 325 | or under the terms of any subsequent version published by the license 326 | steward. 327 | 328 | 10.3. Modified Versions 329 | 330 | If you create software not governed by this License, and you want to 331 | create a new license for such software, you may create and use a 332 | modified version of this License if you rename the license and remove 333 | any references to the name of the license steward (except to note that 334 | such modified license differs from this License). 335 | 336 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 337 | Licenses If You choose to distribute Source Code Form that is 338 | Incompatible With Secondary Licenses under the terms of this version of 339 | the License, the notice described in Exhibit B of this License must be 340 | attached. 341 | 342 | Exhibit A - Source Code Form License Notice 343 | 344 | This Source Code Form is subject to the 345 | terms of the Mozilla Public License, v. 346 | 2.0. If a copy of the MPL was not 347 | distributed with this file, You can 348 | obtain one at 349 | http://mozilla.org/MPL/2.0/. 350 | 351 | If it is not possible or desirable to put the notice in a particular file, 352 | then You may include the notice in a location (such as a LICENSE file in a 353 | relevant directory) where a recipient would be likely to look for such a 354 | notice. 355 | 356 | You may add additional accurate notices of copyright ownership. 357 | 358 | Exhibit B - "Incompatible With Secondary Licenses" Notice 359 | 360 | This Source Code Form is "Incompatible 361 | With Secondary Licenses", as defined by 362 | the Mozilla Public License, v. 2.0. 363 | 364 | -------------------------------------------------------------------------------- /js/lib/transform-controls.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author arodic / https://github.com/arodic 3 | */ 4 | /*jshint sub:true*/ 5 | 6 | ( function () { 7 | 8 | 'use strict'; 9 | 10 | 11 | var GizmoMaterial = function ( parameters ) { 12 | 13 | THREE.MeshBasicMaterial.call( this ); 14 | 15 | this.depthTest = false; 16 | this.depthWrite = false; 17 | this.side = THREE.FrontSide; 18 | this.transparent = true; 19 | 20 | this.setValues( parameters ); 21 | 22 | this.oldColor = this.color.clone(); 23 | this.oldOpacity = this.opacity; 24 | 25 | this.highlight = function( highlighted ) { 26 | 27 | if ( highlighted ) { 28 | 29 | this.color.setRGB( 1, 1, 0 ); 30 | this.opacity = 1; 31 | 32 | } else { 33 | 34 | this.color.copy( this.oldColor ); 35 | this.opacity = this.oldOpacity; 36 | 37 | } 38 | 39 | }; 40 | 41 | }; 42 | 43 | GizmoMaterial.prototype = Object.create( THREE.MeshBasicMaterial.prototype ); 44 | GizmoMaterial.prototype.constructor = GizmoMaterial; 45 | 46 | 47 | var GizmoLineMaterial = function ( parameters ) { 48 | 49 | THREE.LineBasicMaterial.call( this ); 50 | 51 | this.depthTest = false; 52 | this.depthWrite = false; 53 | this.transparent = true; 54 | this.linewidth = 1; 55 | 56 | this.setValues( parameters ); 57 | 58 | this.oldColor = this.color.clone(); 59 | this.oldOpacity = this.opacity; 60 | 61 | this.highlight = function( highlighted ) { 62 | 63 | if ( highlighted ) { 64 | 65 | this.color.setRGB( 1, 1, 0 ); 66 | this.opacity = 1; 67 | 68 | } else { 69 | 70 | this.color.copy( this.oldColor ); 71 | this.opacity = this.oldOpacity; 72 | 73 | } 74 | 75 | }; 76 | 77 | }; 78 | 79 | GizmoLineMaterial.prototype = Object.create( THREE.LineBasicMaterial.prototype ); 80 | GizmoLineMaterial.prototype.constructor = GizmoLineMaterial; 81 | 82 | 83 | var pickerMaterial = new GizmoMaterial( { visible: false, transparent: false } ); 84 | 85 | 86 | THREE.TransformGizmo = function () { 87 | 88 | var scope = this; 89 | 90 | this.init = function () { 91 | 92 | THREE.Object3D.call( this ); 93 | 94 | this.handles = new THREE.Object3D(); 95 | this.pickers = new THREE.Object3D(); 96 | this.planes = new THREE.Object3D(); 97 | 98 | this.add( this.handles ); 99 | this.add( this.pickers ); 100 | this.add( this.planes ); 101 | 102 | //// PLANES 103 | 104 | var planeGeometry = new THREE.PlaneBufferGeometry( 50, 50, 2, 2 ); 105 | var planeMaterial = new THREE.MeshBasicMaterial( { visible: false, side: THREE.DoubleSide } ); 106 | 107 | var planes = { 108 | "XY": new THREE.Mesh( planeGeometry, planeMaterial ), 109 | "YZ": new THREE.Mesh( planeGeometry, planeMaterial ), 110 | "XZ": new THREE.Mesh( planeGeometry, planeMaterial ), 111 | "XYZE": new THREE.Mesh( planeGeometry, planeMaterial ) 112 | }; 113 | 114 | this.activePlane = planes[ "XYZE" ]; 115 | 116 | planes[ "YZ" ].rotation.set( 0, Math.PI / 2, 0 ); 117 | planes[ "XZ" ].rotation.set( - Math.PI / 2, 0, 0 ); 118 | 119 | for ( var i in planes ) { 120 | 121 | planes[ i ].name = i; 122 | this.planes.add( planes[ i ] ); 123 | this.planes[ i ] = planes[ i ]; 124 | 125 | } 126 | 127 | //// HANDLES AND PICKERS 128 | 129 | var setupGizmos = function( gizmoMap, parent ) { 130 | 131 | for ( var name in gizmoMap ) { 132 | 133 | for ( i = gizmoMap[ name ].length; i --; ) { 134 | 135 | var object = gizmoMap[ name ][ i ][ 0 ]; 136 | var position = gizmoMap[ name ][ i ][ 1 ]; 137 | var rotation = gizmoMap[ name ][ i ][ 2 ]; 138 | 139 | object.name = name; 140 | 141 | if ( position ) object.position.set( position[ 0 ], position[ 1 ], position[ 2 ] ); 142 | if ( rotation ) object.rotation.set( rotation[ 0 ], rotation[ 1 ], rotation[ 2 ] ); 143 | 144 | parent.add( object ); 145 | 146 | } 147 | 148 | } 149 | 150 | }; 151 | 152 | setupGizmos( this.handleGizmos, this.handles ); 153 | setupGizmos( this.pickerGizmos, this.pickers ); 154 | 155 | // reset Transformations 156 | 157 | this.traverse( function ( child ) { 158 | 159 | if ( child instanceof THREE.Mesh ) { 160 | 161 | child.updateMatrix(); 162 | 163 | var tempGeometry = child.geometry.clone(); 164 | tempGeometry.applyMatrix( child.matrix ); 165 | child.geometry = tempGeometry; 166 | 167 | child.position.set( 0, 0, 0 ); 168 | child.rotation.set( 0, 0, 0 ); 169 | child.scale.set( 1, 1, 1 ); 170 | 171 | } 172 | 173 | } ); 174 | 175 | }; 176 | 177 | this.highlight = function ( axis ) { 178 | 179 | this.traverse( function( child ) { 180 | 181 | if ( child.material && child.material.highlight ) { 182 | 183 | if ( child.name === axis ) { 184 | 185 | child.material.highlight( true ); 186 | 187 | } else { 188 | 189 | child.material.highlight( false ); 190 | 191 | } 192 | 193 | } 194 | 195 | } ); 196 | 197 | }; 198 | 199 | }; 200 | 201 | THREE.TransformGizmo.prototype = Object.create( THREE.Object3D.prototype ); 202 | THREE.TransformGizmo.prototype.constructor = THREE.TransformGizmo; 203 | 204 | THREE.TransformGizmo.prototype.update = function ( rotation, eye ) { 205 | 206 | var vec1 = new THREE.Vector3( 0, 0, 0 ); 207 | var vec2 = new THREE.Vector3( 0, 1, 0 ); 208 | var lookAtMatrix = new THREE.Matrix4(); 209 | 210 | this.traverse( function( child ) { 211 | 212 | if ( child.name.search( "E" ) !== - 1 ) { 213 | 214 | child.quaternion.setFromRotationMatrix( lookAtMatrix.lookAt( eye, vec1, vec2 ) ); 215 | 216 | } else if ( child.name.search( "X" ) !== - 1 || child.name.search( "Y" ) !== - 1 || child.name.search( "Z" ) !== - 1 ) { 217 | 218 | child.quaternion.setFromEuler( rotation ); 219 | 220 | } 221 | 222 | } ); 223 | 224 | }; 225 | 226 | THREE.TransformGizmoTranslate = function () { 227 | 228 | THREE.TransformGizmo.call( this ); 229 | 230 | var arrowGeometry = new THREE.Geometry(); 231 | var mesh = new THREE.Mesh( new THREE.CylinderGeometry( 0, 0.05, 0.2, 12, 1, false ) ); 232 | mesh.position.y = 0.5; 233 | mesh.updateMatrix(); 234 | 235 | arrowGeometry.merge( mesh.geometry, mesh.matrix ); 236 | 237 | var lineXGeometry = new THREE.BufferGeometry(); 238 | lineXGeometry.addAttribute( 'position', new THREE.Float32BufferAttribute( [ 0, 0, 0, 1, 0, 0 ], 3 ) ); 239 | 240 | var lineYGeometry = new THREE.BufferGeometry(); 241 | lineYGeometry.addAttribute( 'position', new THREE.Float32BufferAttribute( [ 0, 0, 0, 0, 1, 0 ], 3 ) ); 242 | 243 | var lineZGeometry = new THREE.BufferGeometry(); 244 | lineZGeometry.addAttribute( 'position', new THREE.Float32BufferAttribute( [ 0, 0, 0, 0, 0, 1 ], 3 ) ); 245 | 246 | this.handleGizmos = { 247 | 248 | X: [ 249 | [ new THREE.Mesh( arrowGeometry, new GizmoMaterial( { color: 0xff0000 } ) ), [ 0.5, 0, 0 ], [ 0, 0, - Math.PI / 2 ] ], 250 | [ new THREE.Line( lineXGeometry, new GizmoLineMaterial( { color: 0xff0000 } ) ) ] 251 | ], 252 | 253 | Y: [ 254 | [ new THREE.Mesh( arrowGeometry, new GizmoMaterial( { color: 0x00ff00 } ) ), [ 0, 0.5, 0 ] ], 255 | [ new THREE.Line( lineYGeometry, new GizmoLineMaterial( { color: 0x00ff00 } ) ) ] 256 | ], 257 | 258 | Z: [ 259 | [ new THREE.Mesh( arrowGeometry, new GizmoMaterial( { color: 0x0000ff } ) ), [ 0, 0, 0.5 ], [ Math.PI / 2, 0, 0 ] ], 260 | [ new THREE.Line( lineZGeometry, new GizmoLineMaterial( { color: 0x0000ff } ) ) ] 261 | ], 262 | 263 | XYZ: [ 264 | [ new THREE.Mesh( new THREE.OctahedronGeometry( 0.1, 0 ), new GizmoMaterial( { color: 0xffffff, opacity: 0.25 } ) ), [ 0, 0, 0 ], [ 0, 0, 0 ] ] 265 | ], 266 | 267 | XY: [ 268 | [ new THREE.Mesh( new THREE.PlaneBufferGeometry( 0.29, 0.29 ), new GizmoMaterial( { color: 0xffff00, opacity: 0.25 } ) ), [ 0.15, 0.15, 0 ] ] 269 | ], 270 | 271 | YZ: [ 272 | [ new THREE.Mesh( new THREE.PlaneBufferGeometry( 0.29, 0.29 ), new GizmoMaterial( { color: 0x00ffff, opacity: 0.25 } ) ), [ 0, 0.15, 0.15 ], [ 0, Math.PI / 2, 0 ] ] 273 | ], 274 | 275 | XZ: [ 276 | [ new THREE.Mesh( new THREE.PlaneBufferGeometry( 0.29, 0.29 ), new GizmoMaterial( { color: 0xff00ff, opacity: 0.25 } ) ), [ 0.15, 0, 0.15 ], [ - Math.PI / 2, 0, 0 ] ] 277 | ] 278 | 279 | }; 280 | 281 | this.pickerGizmos = { 282 | 283 | X: [ 284 | [ new THREE.Mesh( new THREE.CylinderGeometry( 0.2, 0, 1, 4, 1, false ), pickerMaterial ), [ 0.6, 0, 0 ], [ 0, 0, - Math.PI / 2 ] ] 285 | ], 286 | 287 | Y: [ 288 | [ new THREE.Mesh( new THREE.CylinderGeometry( 0.2, 0, 1, 4, 1, false ), pickerMaterial ), [ 0, 0.6, 0 ] ] 289 | ], 290 | 291 | Z: [ 292 | [ new THREE.Mesh( new THREE.CylinderGeometry( 0.2, 0, 1, 4, 1, false ), pickerMaterial ), [ 0, 0, 0.6 ], [ Math.PI / 2, 0, 0 ] ] 293 | ], 294 | 295 | XYZ: [ 296 | [ new THREE.Mesh( new THREE.OctahedronGeometry( 0.2, 0 ), pickerMaterial ) ] 297 | ], 298 | 299 | XY: [ 300 | [ new THREE.Mesh( new THREE.PlaneBufferGeometry( 0.4, 0.4 ), pickerMaterial ), [ 0.2, 0.2, 0 ] ] 301 | ], 302 | 303 | YZ: [ 304 | [ new THREE.Mesh( new THREE.PlaneBufferGeometry( 0.4, 0.4 ), pickerMaterial ), [ 0, 0.2, 0.2 ], [ 0, Math.PI / 2, 0 ] ] 305 | ], 306 | 307 | XZ: [ 308 | [ new THREE.Mesh( new THREE.PlaneBufferGeometry( 0.4, 0.4 ), pickerMaterial ), [ 0.2, 0, 0.2 ], [ - Math.PI / 2, 0, 0 ] ] 309 | ] 310 | 311 | }; 312 | 313 | this.setActivePlane = function ( axis, eye ) { 314 | 315 | var tempMatrix = new THREE.Matrix4(); 316 | eye.applyMatrix4( tempMatrix.getInverse( tempMatrix.extractRotation( this.planes[ "XY" ].matrixWorld ) ) ); 317 | 318 | if ( axis === "X" ) { 319 | 320 | this.activePlane = this.planes[ "XY" ]; 321 | 322 | if ( Math.abs( eye.y ) > Math.abs( eye.z ) ) this.activePlane = this.planes[ "XZ" ]; 323 | 324 | } 325 | 326 | if ( axis === "Y" ) { 327 | 328 | this.activePlane = this.planes[ "XY" ]; 329 | 330 | if ( Math.abs( eye.x ) > Math.abs( eye.z ) ) this.activePlane = this.planes[ "YZ" ]; 331 | 332 | } 333 | 334 | if ( axis === "Z" ) { 335 | 336 | this.activePlane = this.planes[ "XZ" ]; 337 | 338 | if ( Math.abs( eye.x ) > Math.abs( eye.y ) ) this.activePlane = this.planes[ "YZ" ]; 339 | 340 | } 341 | 342 | if ( axis === "XYZ" ) this.activePlane = this.planes[ "XYZE" ]; 343 | 344 | if ( axis === "XY" ) this.activePlane = this.planes[ "XY" ]; 345 | 346 | if ( axis === "YZ" ) this.activePlane = this.planes[ "YZ" ]; 347 | 348 | if ( axis === "XZ" ) this.activePlane = this.planes[ "XZ" ]; 349 | 350 | }; 351 | 352 | this.init(); 353 | 354 | }; 355 | 356 | THREE.TransformGizmoTranslate.prototype = Object.create( THREE.TransformGizmo.prototype ); 357 | THREE.TransformGizmoTranslate.prototype.constructor = THREE.TransformGizmoTranslate; 358 | 359 | THREE.TransformGizmoRotate = function () { 360 | 361 | THREE.TransformGizmo.call( this ); 362 | 363 | var CircleGeometry = function ( radius, facing, arc ) { 364 | 365 | var geometry = new THREE.BufferGeometry(); 366 | var vertices = []; 367 | arc = arc ? arc : 1; 368 | 369 | for ( var i = 0; i <= 64 * arc; ++ i ) { 370 | 371 | if ( facing === 'x' ) vertices.push( 0, Math.cos( i / 32 * Math.PI ) * radius, Math.sin( i / 32 * Math.PI ) * radius ); 372 | if ( facing === 'y' ) vertices.push( Math.cos( i / 32 * Math.PI ) * radius, 0, Math.sin( i / 32 * Math.PI ) * radius ); 373 | if ( facing === 'z' ) vertices.push( Math.sin( i / 32 * Math.PI ) * radius, Math.cos( i / 32 * Math.PI ) * radius, 0 ); 374 | 375 | } 376 | 377 | geometry.addAttribute( 'position', new THREE.Float32BufferAttribute( vertices, 3 ) ); 378 | return geometry; 379 | 380 | }; 381 | 382 | this.handleGizmos = { 383 | 384 | X: [ 385 | [ new THREE.Line( new CircleGeometry( 1, 'x', 0.5 ), new GizmoLineMaterial( { color: 0xff0000 } ) ) ] 386 | ], 387 | 388 | Y: [ 389 | [ new THREE.Line( new CircleGeometry( 1, 'y', 0.5 ), new GizmoLineMaterial( { color: 0x00ff00 } ) ) ] 390 | ], 391 | 392 | Z: [ 393 | [ new THREE.Line( new CircleGeometry( 1, 'z', 0.5 ), new GizmoLineMaterial( { color: 0x0000ff } ) ) ] 394 | ], 395 | 396 | E: [ 397 | [ new THREE.Line( new CircleGeometry( 1.25, 'z', 1 ), new GizmoLineMaterial( { color: 0xcccc00 } ) ) ] 398 | ], 399 | 400 | XYZE: [ 401 | [ new THREE.Line( new CircleGeometry( 1, 'z', 1 ), new GizmoLineMaterial( { color: 0x787878 } ) ) ] 402 | ] 403 | 404 | }; 405 | 406 | this.pickerGizmos = { 407 | 408 | X: [ 409 | [ new THREE.Mesh( new THREE.TorusGeometry( 1, 0.12, 4, 12, Math.PI ), pickerMaterial ), [ 0, 0, 0 ], [ 0, - Math.PI / 2, - Math.PI / 2 ] ] 410 | ], 411 | 412 | Y: [ 413 | [ new THREE.Mesh( new THREE.TorusGeometry( 1, 0.12, 4, 12, Math.PI ), pickerMaterial ), [ 0, 0, 0 ], [ Math.PI / 2, 0, 0 ] ] 414 | ], 415 | 416 | Z: [ 417 | [ new THREE.Mesh( new THREE.TorusGeometry( 1, 0.12, 4, 12, Math.PI ), pickerMaterial ), [ 0, 0, 0 ], [ 0, 0, - Math.PI / 2 ] ] 418 | ], 419 | 420 | E: [ 421 | [ new THREE.Mesh( new THREE.TorusGeometry( 1.25, 0.12, 2, 24 ), pickerMaterial ) ] 422 | ], 423 | 424 | XYZE: [ 425 | [ new THREE.Mesh( new THREE.Geometry() ) ]// TODO 426 | ] 427 | 428 | }; 429 | 430 | this.setActivePlane = function ( axis ) { 431 | 432 | if ( axis === "E" ) this.activePlane = this.planes[ "XYZE" ]; 433 | 434 | if ( axis === "X" ) this.activePlane = this.planes[ "YZ" ]; 435 | 436 | if ( axis === "Y" ) this.activePlane = this.planes[ "XZ" ]; 437 | 438 | if ( axis === "Z" ) this.activePlane = this.planes[ "XY" ]; 439 | 440 | }; 441 | 442 | this.update = function ( rotation, eye2 ) { 443 | 444 | THREE.TransformGizmo.prototype.update.apply( this, arguments ); 445 | 446 | var group = { 447 | 448 | handles: this[ "handles" ], 449 | pickers: this[ "pickers" ], 450 | 451 | }; 452 | 453 | var tempMatrix = new THREE.Matrix4(); 454 | var worldRotation = new THREE.Euler( 0, 0, 1 ); 455 | var tempQuaternion = new THREE.Quaternion(); 456 | var unitX = new THREE.Vector3( 1, 0, 0 ); 457 | var unitY = new THREE.Vector3( 0, 1, 0 ); 458 | var unitZ = new THREE.Vector3( 0, 0, 1 ); 459 | var quaternionX = new THREE.Quaternion(); 460 | var quaternionY = new THREE.Quaternion(); 461 | var quaternionZ = new THREE.Quaternion(); 462 | var eye = eye2.clone(); 463 | 464 | worldRotation.copy( this.planes[ "XY" ].rotation ); 465 | tempQuaternion.setFromEuler( worldRotation ); 466 | 467 | tempMatrix.makeRotationFromQuaternion( tempQuaternion ).getInverse( tempMatrix ); 468 | eye.applyMatrix4( tempMatrix ); 469 | 470 | this.traverse( function( child ) { 471 | 472 | tempQuaternion.setFromEuler( worldRotation ); 473 | 474 | if ( child.name === "X" ) { 475 | 476 | quaternionX.setFromAxisAngle( unitX, Math.atan2( - eye.y, eye.z ) ); 477 | tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionX ); 478 | child.quaternion.copy( tempQuaternion ); 479 | 480 | } 481 | 482 | if ( child.name === "Y" ) { 483 | 484 | quaternionY.setFromAxisAngle( unitY, Math.atan2( eye.x, eye.z ) ); 485 | tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionY ); 486 | child.quaternion.copy( tempQuaternion ); 487 | 488 | } 489 | 490 | if ( child.name === "Z" ) { 491 | 492 | quaternionZ.setFromAxisAngle( unitZ, Math.atan2( eye.y, eye.x ) ); 493 | tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionZ ); 494 | child.quaternion.copy( tempQuaternion ); 495 | 496 | } 497 | 498 | } ); 499 | 500 | }; 501 | 502 | this.init(); 503 | 504 | }; 505 | 506 | THREE.TransformGizmoRotate.prototype = Object.create( THREE.TransformGizmo.prototype ); 507 | THREE.TransformGizmoRotate.prototype.constructor = THREE.TransformGizmoRotate; 508 | 509 | THREE.TransformGizmoScale = function () { 510 | 511 | THREE.TransformGizmo.call( this ); 512 | 513 | var arrowGeometry = new THREE.Geometry(); 514 | var mesh = new THREE.Mesh( new THREE.BoxGeometry( 0.125, 0.125, 0.125 ) ); 515 | mesh.position.y = 0.5; 516 | mesh.updateMatrix(); 517 | 518 | arrowGeometry.merge( mesh.geometry, mesh.matrix ); 519 | 520 | var lineXGeometry = new THREE.BufferGeometry(); 521 | lineXGeometry.addAttribute( 'position', new THREE.Float32BufferAttribute( [ 0, 0, 0, 1, 0, 0 ], 3 ) ); 522 | 523 | var lineYGeometry = new THREE.BufferGeometry(); 524 | lineYGeometry.addAttribute( 'position', new THREE.Float32BufferAttribute( [ 0, 0, 0, 0, 1, 0 ], 3 ) ); 525 | 526 | var lineZGeometry = new THREE.BufferGeometry(); 527 | lineZGeometry.addAttribute( 'position', new THREE.Float32BufferAttribute( [ 0, 0, 0, 0, 0, 1 ], 3 ) ); 528 | 529 | this.handleGizmos = { 530 | 531 | X: [ 532 | [ new THREE.Mesh( arrowGeometry, new GizmoMaterial( { color: 0xff0000 } ) ), [ 0.5, 0, 0 ], [ 0, 0, - Math.PI / 2 ] ], 533 | [ new THREE.Line( lineXGeometry, new GizmoLineMaterial( { color: 0xff0000 } ) ) ] 534 | ], 535 | 536 | Y: [ 537 | [ new THREE.Mesh( arrowGeometry, new GizmoMaterial( { color: 0x00ff00 } ) ), [ 0, 0.5, 0 ] ], 538 | [ new THREE.Line( lineYGeometry, new GizmoLineMaterial( { color: 0x00ff00 } ) ) ] 539 | ], 540 | 541 | Z: [ 542 | [ new THREE.Mesh( arrowGeometry, new GizmoMaterial( { color: 0x0000ff } ) ), [ 0, 0, 0.5 ], [ Math.PI / 2, 0, 0 ] ], 543 | [ new THREE.Line( lineZGeometry, new GizmoLineMaterial( { color: 0x0000ff } ) ) ] 544 | ], 545 | 546 | XYZ: [ 547 | [ new THREE.Mesh( new THREE.BoxGeometry( 0.125, 0.125, 0.125 ), new GizmoMaterial( { color: 0xffffff, opacity: 0.25 } ) ) ] 548 | ] 549 | 550 | }; 551 | 552 | this.pickerGizmos = { 553 | 554 | X: [ 555 | [ new THREE.Mesh( new THREE.CylinderGeometry( 0.2, 0, 1, 4, 1, false ), pickerMaterial ), [ 0.6, 0, 0 ], [ 0, 0, - Math.PI / 2 ] ] 556 | ], 557 | 558 | Y: [ 559 | [ new THREE.Mesh( new THREE.CylinderGeometry( 0.2, 0, 1, 4, 1, false ), pickerMaterial ), [ 0, 0.6, 0 ] ] 560 | ], 561 | 562 | Z: [ 563 | [ new THREE.Mesh( new THREE.CylinderGeometry( 0.2, 0, 1, 4, 1, false ), pickerMaterial ), [ 0, 0, 0.6 ], [ Math.PI / 2, 0, 0 ] ] 564 | ], 565 | 566 | XYZ: [ 567 | [ new THREE.Mesh( new THREE.BoxGeometry( 0.4, 0.4, 0.4 ), pickerMaterial ) ] 568 | ] 569 | 570 | }; 571 | 572 | this.setActivePlane = function ( axis, eye ) { 573 | 574 | var tempMatrix = new THREE.Matrix4(); 575 | eye.applyMatrix4( tempMatrix.getInverse( tempMatrix.extractRotation( this.planes[ "XY" ].matrixWorld ) ) ); 576 | 577 | if ( axis === "X" ) { 578 | 579 | this.activePlane = this.planes[ "XY" ]; 580 | if ( Math.abs( eye.y ) > Math.abs( eye.z ) ) this.activePlane = this.planes[ "XZ" ]; 581 | 582 | } 583 | 584 | if ( axis === "Y" ) { 585 | 586 | this.activePlane = this.planes[ "XY" ]; 587 | if ( Math.abs( eye.x ) > Math.abs( eye.z ) ) this.activePlane = this.planes[ "YZ" ]; 588 | 589 | } 590 | 591 | if ( axis === "Z" ) { 592 | 593 | this.activePlane = this.planes[ "XZ" ]; 594 | if ( Math.abs( eye.x ) > Math.abs( eye.y ) ) this.activePlane = this.planes[ "YZ" ]; 595 | 596 | } 597 | 598 | if ( axis === "XYZ" ) this.activePlane = this.planes[ "XYZE" ]; 599 | 600 | }; 601 | 602 | this.init(); 603 | 604 | }; 605 | 606 | THREE.TransformGizmoScale.prototype = Object.create( THREE.TransformGizmo.prototype ); 607 | THREE.TransformGizmoScale.prototype.constructor = THREE.TransformGizmoScale; 608 | 609 | THREE.TransformControls = function ( camera, domElement ) { 610 | 611 | // TODO: Make non-uniform scale and rotate play nice in hierarchies 612 | // TODO: ADD RXYZ contol 613 | 614 | THREE.Object3D.call( this ); 615 | 616 | domElement = ( domElement !== undefined ) ? domElement : document; 617 | 618 | this.object = undefined; 619 | this.visible = false; 620 | this.snap = null; 621 | this.space = "world"; 622 | this.size = 1; 623 | this.axis = null; 624 | 625 | var scope = this; 626 | 627 | var _mode = "translate"; 628 | var _dragging = false; 629 | var _plane = "XY"; 630 | var _gizmo = { 631 | 632 | "translate": new THREE.TransformGizmoTranslate(), 633 | "rotate": new THREE.TransformGizmoRotate(), 634 | "scale": new THREE.TransformGizmoScale() 635 | }; 636 | 637 | for ( var type in _gizmo ) { 638 | 639 | var gizmoObj = _gizmo[ type ]; 640 | 641 | gizmoObj.visible = ( type === _mode ); 642 | this.add( gizmoObj ); 643 | 644 | } 645 | 646 | var changeEvent = { type: "change" }; 647 | var mouseDownEvent = { type: "mouseDown" }; 648 | var mouseUpEvent = { type: "mouseUp", mode: _mode }; 649 | var objectChangeEvent = { type: "objectChange" }; 650 | 651 | var ray = new THREE.Raycaster(); 652 | var pointerVector = new THREE.Vector2(); 653 | 654 | var point = new THREE.Vector3(); 655 | var offset = new THREE.Vector3(); 656 | 657 | var rotation = new THREE.Vector3(); 658 | var offsetRotation = new THREE.Vector3(); 659 | var scale = 1; 660 | 661 | var lookAtMatrix = new THREE.Matrix4(); 662 | var eye = new THREE.Vector3(); 663 | 664 | var tempMatrix = new THREE.Matrix4(); 665 | var tempVector = new THREE.Vector3(); 666 | var tempQuaternion = new THREE.Quaternion(); 667 | var unitX = new THREE.Vector3( 1, 0, 0 ); 668 | var unitY = new THREE.Vector3( 0, 1, 0 ); 669 | var unitZ = new THREE.Vector3( 0, 0, 1 ); 670 | 671 | var quaternionXYZ = new THREE.Quaternion(); 672 | var quaternionX = new THREE.Quaternion(); 673 | var quaternionY = new THREE.Quaternion(); 674 | var quaternionZ = new THREE.Quaternion(); 675 | var quaternionE = new THREE.Quaternion(); 676 | 677 | var oldPosition = new THREE.Vector3(); 678 | var oldScale = new THREE.Vector3(); 679 | var oldRotationMatrix = new THREE.Matrix4(); 680 | 681 | var parentRotationMatrix = new THREE.Matrix4(); 682 | var parentScale = new THREE.Vector3(); 683 | 684 | var worldPosition = new THREE.Vector3(); 685 | var worldRotation = new THREE.Euler(); 686 | var worldRotationMatrix = new THREE.Matrix4(); 687 | var camPosition = new THREE.Vector3(); 688 | var camRotation = new THREE.Euler(); 689 | 690 | domElement.addEventListener( "mousedown", onPointerDown, false ); 691 | domElement.addEventListener( "touchstart", onPointerDown, false ); 692 | 693 | domElement.addEventListener( "mousemove", onPointerHover, false ); 694 | domElement.addEventListener( "touchmove", onPointerHover, false ); 695 | 696 | domElement.addEventListener( "mousemove", onPointerMove, false ); 697 | domElement.addEventListener( "touchmove", onPointerMove, false ); 698 | 699 | domElement.addEventListener( "mouseup", onPointerUp, false ); 700 | domElement.addEventListener( "mouseout", onPointerUp, false ); 701 | domElement.addEventListener( "touchend", onPointerUp, false ); 702 | domElement.addEventListener( "touchcancel", onPointerUp, false ); 703 | domElement.addEventListener( "touchleave", onPointerUp, false ); 704 | 705 | this.dispose = function () { 706 | 707 | domElement.removeEventListener( "mousedown", onPointerDown ); 708 | domElement.removeEventListener( "touchstart", onPointerDown ); 709 | 710 | domElement.removeEventListener( "mousemove", onPointerHover ); 711 | domElement.removeEventListener( "touchmove", onPointerHover ); 712 | 713 | domElement.removeEventListener( "mousemove", onPointerMove ); 714 | domElement.removeEventListener( "touchmove", onPointerMove ); 715 | 716 | domElement.removeEventListener( "mouseup", onPointerUp ); 717 | domElement.removeEventListener( "mouseout", onPointerUp ); 718 | domElement.removeEventListener( "touchend", onPointerUp ); 719 | domElement.removeEventListener( "touchcancel", onPointerUp ); 720 | domElement.removeEventListener( "touchleave", onPointerUp ); 721 | 722 | }; 723 | 724 | this.attach = function ( object ) { 725 | 726 | this.object = object; 727 | this.visible = true; 728 | this.update(); 729 | 730 | }; 731 | 732 | this.detach = function () { 733 | 734 | this.object = undefined; 735 | this.visible = false; 736 | this.axis = null; 737 | 738 | }; 739 | 740 | this.setMode = function ( mode ) { 741 | 742 | _mode = mode ? mode : _mode; 743 | 744 | if ( _mode === "scale" ) scope.space = "local"; 745 | 746 | for ( var type in _gizmo ) _gizmo[ type ].visible = ( type === _mode ); 747 | 748 | this.update(); 749 | scope.dispatchEvent( changeEvent ); 750 | 751 | }; 752 | 753 | this.setSnap = function ( snap ) { 754 | 755 | scope.snap = snap; 756 | 757 | }; 758 | 759 | this.setSize = function ( size ) { 760 | 761 | scope.size = size; 762 | this.update(); 763 | scope.dispatchEvent( changeEvent ); 764 | 765 | }; 766 | 767 | this.setSpace = function ( space ) { 768 | 769 | scope.space = space; 770 | this.update(); 771 | scope.dispatchEvent( changeEvent ); 772 | 773 | }; 774 | 775 | this.update = function () { 776 | 777 | if ( scope.object === undefined ) return; 778 | 779 | scope.object.updateMatrixWorld(); 780 | worldPosition.setFromMatrixPosition( scope.object.matrixWorld ); 781 | worldRotation.setFromRotationMatrix( tempMatrix.extractRotation( scope.object.matrixWorld ) ); 782 | 783 | camera.updateMatrixWorld(); 784 | camPosition.setFromMatrixPosition( camera.matrixWorld ); 785 | camRotation.setFromRotationMatrix( tempMatrix.extractRotation( camera.matrixWorld ) ); 786 | 787 | scale = worldPosition.distanceTo( camPosition ) / 6 * scope.size; 788 | this.position.copy( worldPosition ); 789 | // NOTE: we are commenting this line because this transformation looks 790 | // confusing when using an ortographic camera 791 | // this.scale.set( scale, scale, scale ); 792 | 793 | eye.copy( camPosition ).sub( worldPosition ).normalize(); 794 | 795 | if ( scope.space === "local" ) { 796 | 797 | _gizmo[ _mode ].update( worldRotation, eye ); 798 | 799 | } else if ( scope.space === "world" ) { 800 | 801 | _gizmo[ _mode ].update( new THREE.Euler(), eye ); 802 | 803 | } 804 | 805 | _gizmo[ _mode ].highlight( scope.axis ); 806 | 807 | }; 808 | 809 | function onPointerHover( event ) { 810 | 811 | if ( scope.object === undefined || _dragging === true || ( event.button !== undefined && event.button !== 0 ) ) return; 812 | 813 | var pointer = event.changedTouches ? event.changedTouches[ 0 ] : event; 814 | 815 | var intersect = intersectObjects( pointer, _gizmo[ _mode ].pickers.children ); 816 | 817 | var axis = null; 818 | 819 | if ( intersect ) { 820 | 821 | axis = intersect.object.name; 822 | 823 | event.preventDefault(); 824 | 825 | } 826 | 827 | if ( scope.axis !== axis ) { 828 | 829 | scope.axis = axis; 830 | scope.update(); 831 | scope.dispatchEvent( changeEvent ); 832 | 833 | } 834 | 835 | } 836 | 837 | function onPointerDown( event ) { 838 | 839 | if ( scope.object === undefined || _dragging === true || ( event.button !== undefined && event.button !== 0 ) ) return; 840 | 841 | var pointer = event.changedTouches ? event.changedTouches[ 0 ] : event; 842 | 843 | if ( pointer.button === 0 || pointer.button === undefined ) { 844 | 845 | var intersect = intersectObjects( pointer, _gizmo[ _mode ].pickers.children ); 846 | 847 | if ( intersect ) { 848 | 849 | event.preventDefault(); 850 | event.stopPropagation(); 851 | 852 | scope.dispatchEvent( mouseDownEvent ); 853 | 854 | scope.axis = intersect.object.name; 855 | 856 | scope.update(); 857 | 858 | eye.copy( camPosition ).sub( worldPosition ).normalize(); 859 | 860 | _gizmo[ _mode ].setActivePlane( scope.axis, eye ); 861 | 862 | var planeIntersect = intersectObjects( pointer, [ _gizmo[ _mode ].activePlane ] ); 863 | 864 | if ( planeIntersect ) { 865 | 866 | oldPosition.copy( scope.object.position ); 867 | oldScale.copy( scope.object.scale ); 868 | 869 | oldRotationMatrix.extractRotation( scope.object.matrix ); 870 | worldRotationMatrix.extractRotation( scope.object.matrixWorld ); 871 | 872 | parentRotationMatrix.extractRotation( scope.object.parent.matrixWorld ); 873 | parentScale.setFromMatrixScale( tempMatrix.getInverse( scope.object.parent.matrixWorld ) ); 874 | 875 | offset.copy( planeIntersect.point ); 876 | 877 | } 878 | 879 | } 880 | 881 | } 882 | 883 | _dragging = true; 884 | 885 | } 886 | 887 | function onPointerMove( event ) { 888 | 889 | if ( scope.object === undefined || scope.axis === null || _dragging === false || ( event.button !== undefined && event.button !== 0 ) ) return; 890 | 891 | var pointer = event.changedTouches ? event.changedTouches[ 0 ] : event; 892 | 893 | var planeIntersect = intersectObjects( pointer, [ _gizmo[ _mode ].activePlane ] ); 894 | 895 | if ( planeIntersect === false ) return; 896 | 897 | event.preventDefault(); 898 | event.stopPropagation(); 899 | 900 | point.copy( planeIntersect.point ); 901 | 902 | if ( _mode === "translate" ) { 903 | 904 | point.sub( offset ); 905 | point.multiply( parentScale ); 906 | 907 | if ( scope.space === "local" ) { 908 | 909 | point.applyMatrix4( tempMatrix.getInverse( worldRotationMatrix ) ); 910 | 911 | if ( scope.axis.search( "X" ) === - 1 ) point.x = 0; 912 | if ( scope.axis.search( "Y" ) === - 1 ) point.y = 0; 913 | if ( scope.axis.search( "Z" ) === - 1 ) point.z = 0; 914 | 915 | point.applyMatrix4( oldRotationMatrix ); 916 | 917 | scope.object.position.copy( oldPosition ); 918 | scope.object.position.add( point ); 919 | 920 | } 921 | 922 | if ( scope.space === "world" || scope.axis.search( "XYZ" ) !== - 1 ) { 923 | 924 | if ( scope.axis.search( "X" ) === - 1 ) point.x = 0; 925 | if ( scope.axis.search( "Y" ) === - 1 ) point.y = 0; 926 | if ( scope.axis.search( "Z" ) === - 1 ) point.z = 0; 927 | 928 | point.applyMatrix4( tempMatrix.getInverse( parentRotationMatrix ) ); 929 | 930 | scope.object.position.copy( oldPosition ); 931 | scope.object.position.add( point ); 932 | 933 | } 934 | 935 | if ( scope.snap !== null ) { 936 | 937 | if ( scope.axis.search( "X" ) !== - 1 ) scope.object.position.x = Math.round( scope.object.position.x / scope.snap ) * scope.snap; 938 | if ( scope.axis.search( "Y" ) !== - 1 ) scope.object.position.y = Math.round( scope.object.position.y / scope.snap ) * scope.snap; 939 | if ( scope.axis.search( "Z" ) !== - 1 ) scope.object.position.z = Math.round( scope.object.position.z / scope.snap ) * scope.snap; 940 | 941 | } 942 | 943 | } else if ( _mode === "scale" ) { 944 | 945 | point.sub( offset ); 946 | point.multiply( parentScale ); 947 | 948 | if ( scope.space === "local" ) { 949 | 950 | if ( scope.axis === "XYZ" ) { 951 | 952 | scale = 1 + ( ( point.y ) / 50 ); 953 | 954 | scope.object.scale.x = oldScale.x * scale; 955 | scope.object.scale.y = oldScale.y * scale; 956 | scope.object.scale.z = oldScale.z * scale; 957 | 958 | } else { 959 | 960 | point.applyMatrix4( tempMatrix.getInverse( worldRotationMatrix ) ); 961 | 962 | if ( scope.axis === "X" ) scope.object.scale.x = oldScale.x * ( 1 + point.x / 50 ); 963 | if ( scope.axis === "Y" ) scope.object.scale.y = oldScale.y * ( 1 + point.y / 50 ); 964 | if ( scope.axis === "Z" ) scope.object.scale.z = oldScale.z * ( 1 + point.z / 50 ); 965 | 966 | } 967 | 968 | } 969 | 970 | } else if ( _mode === "rotate" ) { 971 | 972 | point.sub( worldPosition ); 973 | point.multiply( parentScale ); 974 | tempVector.copy( offset ).sub( worldPosition ); 975 | tempVector.multiply( parentScale ); 976 | 977 | if ( scope.axis === "E" ) { 978 | 979 | point.applyMatrix4( tempMatrix.getInverse( lookAtMatrix ) ); 980 | tempVector.applyMatrix4( tempMatrix.getInverse( lookAtMatrix ) ); 981 | 982 | rotation.set( Math.atan2( point.z, point.y ), Math.atan2( point.x, point.z ), Math.atan2( point.y, point.x ) ); 983 | offsetRotation.set( Math.atan2( tempVector.z, tempVector.y ), Math.atan2( tempVector.x, tempVector.z ), Math.atan2( tempVector.y, tempVector.x ) ); 984 | 985 | tempQuaternion.setFromRotationMatrix( tempMatrix.getInverse( parentRotationMatrix ) ); 986 | 987 | quaternionE.setFromAxisAngle( eye, rotation.z - offsetRotation.z ); 988 | quaternionXYZ.setFromRotationMatrix( worldRotationMatrix ); 989 | 990 | tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionE ); 991 | tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionXYZ ); 992 | 993 | scope.object.quaternion.copy( tempQuaternion ); 994 | 995 | } else if ( scope.axis === "XYZE" ) { 996 | 997 | quaternionE.setFromEuler( point.clone().cross( tempVector ).normalize() ); // rotation axis 998 | 999 | tempQuaternion.setFromRotationMatrix( tempMatrix.getInverse( parentRotationMatrix ) ); 1000 | quaternionX.setFromAxisAngle( quaternionE, - point.clone().angleTo( tempVector ) ); 1001 | quaternionXYZ.setFromRotationMatrix( worldRotationMatrix ); 1002 | 1003 | tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionX ); 1004 | tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionXYZ ); 1005 | 1006 | scope.object.quaternion.copy( tempQuaternion ); 1007 | 1008 | } else if ( scope.space === "local" ) { 1009 | 1010 | point.applyMatrix4( tempMatrix.getInverse( worldRotationMatrix ) ); 1011 | 1012 | tempVector.applyMatrix4( tempMatrix.getInverse( worldRotationMatrix ) ); 1013 | 1014 | rotation.set( Math.atan2( point.z, point.y ), Math.atan2( point.x, point.z ), Math.atan2( point.y, point.x ) ); 1015 | offsetRotation.set( Math.atan2( tempVector.z, tempVector.y ), Math.atan2( tempVector.x, tempVector.z ), Math.atan2( tempVector.y, tempVector.x ) ); 1016 | 1017 | quaternionXYZ.setFromRotationMatrix( oldRotationMatrix ); 1018 | quaternionX.setFromAxisAngle( unitX, rotation.x - offsetRotation.x ); 1019 | quaternionY.setFromAxisAngle( unitY, rotation.y - offsetRotation.y ); 1020 | quaternionZ.setFromAxisAngle( unitZ, rotation.z - offsetRotation.z ); 1021 | 1022 | if ( scope.axis === "X" ) quaternionXYZ.multiplyQuaternions( quaternionXYZ, quaternionX ); 1023 | if ( scope.axis === "Y" ) quaternionXYZ.multiplyQuaternions( quaternionXYZ, quaternionY ); 1024 | if ( scope.axis === "Z" ) quaternionXYZ.multiplyQuaternions( quaternionXYZ, quaternionZ ); 1025 | 1026 | scope.object.quaternion.copy( quaternionXYZ ); 1027 | 1028 | } else if ( scope.space === "world" ) { 1029 | 1030 | rotation.set( Math.atan2( point.z, point.y ), Math.atan2( point.x, point.z ), Math.atan2( point.y, point.x ) ); 1031 | offsetRotation.set( Math.atan2( tempVector.z, tempVector.y ), Math.atan2( tempVector.x, tempVector.z ), Math.atan2( tempVector.y, tempVector.x ) ); 1032 | 1033 | tempQuaternion.setFromRotationMatrix( tempMatrix.getInverse( parentRotationMatrix ) ); 1034 | 1035 | quaternionX.setFromAxisAngle( unitX, rotation.x - offsetRotation.x ); 1036 | quaternionY.setFromAxisAngle( unitY, rotation.y - offsetRotation.y ); 1037 | quaternionZ.setFromAxisAngle( unitZ, rotation.z - offsetRotation.z ); 1038 | quaternionXYZ.setFromRotationMatrix( worldRotationMatrix ); 1039 | 1040 | if ( scope.axis === "X" ) tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionX ); 1041 | if ( scope.axis === "Y" ) tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionY ); 1042 | if ( scope.axis === "Z" ) tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionZ ); 1043 | 1044 | tempQuaternion.multiplyQuaternions( tempQuaternion, quaternionXYZ ); 1045 | 1046 | scope.object.quaternion.copy( tempQuaternion ); 1047 | 1048 | } 1049 | 1050 | } 1051 | 1052 | scope.update(); 1053 | scope.dispatchEvent( changeEvent ); 1054 | scope.dispatchEvent( objectChangeEvent ); 1055 | 1056 | } 1057 | 1058 | function onPointerUp( event ) { 1059 | 1060 | if ( event.button !== undefined && event.button !== 0 ) return; 1061 | 1062 | if ( _dragging && ( scope.axis !== null ) ) { 1063 | 1064 | mouseUpEvent.mode = _mode; 1065 | scope.dispatchEvent( mouseUpEvent ) 1066 | 1067 | } 1068 | 1069 | _dragging = false; 1070 | onPointerHover( event ); 1071 | 1072 | } 1073 | 1074 | function intersectObjects( pointer, objects ) { 1075 | 1076 | var rect = domElement.getBoundingClientRect(); 1077 | var x = ( pointer.clientX - rect.left ) / rect.width; 1078 | var y = ( pointer.clientY - rect.top ) / rect.height; 1079 | 1080 | pointerVector.set( ( x * 2 ) - 1, - ( y * 2 ) + 1 ); 1081 | ray.setFromCamera( pointerVector, camera ); 1082 | 1083 | var intersections = ray.intersectObjects( objects, true ); 1084 | return intersections[ 0 ] ? intersections[ 0 ] : false; 1085 | 1086 | } 1087 | 1088 | }; 1089 | 1090 | THREE.TransformControls.prototype = Object.create( THREE.Object3D.prototype ); 1091 | THREE.TransformControls.prototype.constructor = THREE.TransformControls; 1092 | 1093 | }() ); 1094 | -------------------------------------------------------------------------------- /js/lib/cannon.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 cannon.js Authors 3 | * 4 | * Permission is hereby granted, free of charge, to any person 5 | * obtaining a copy of this software and associated documentation 6 | * files (the "Software"), to deal in the Software without 7 | * restriction, including without limitation the rights to use, copy, 8 | * modify, merge, publish, distribute, sublicense, and/or sell copies 9 | * of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&false)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.CANNON=e()}}(function(){return function e(f,n,o){function d(t,l){if(!n[t]){if(!f[t]){var u="function"==typeof require&&require;if(!l&&u)return u(t,!0);if(i)return i(t,!0);throw new Error("Cannot find module '"+t+"'")}var p=n[t]={exports:{}};f[t][0].call(p.exports,function(e){var n=f[t][1][e];return d(n?n:e)},p,p.exports,e,f,n,o)}return n[t].exports}for(var i="function"==typeof require&&require,t=0;t (http://steffe.se)",keywords:["cannon.js","cannon","physics","engine","3d"],main:"./build/cannon.js",engines:{node:"*"},repository:{type:"git",url:"https://github.com/schteppe/cannon.js.git"},bugs:{url:"https://github.com/schteppe/cannon.js/issues"},licenses:[{type:"MIT"}],devDependencies:{jshint:"latest","uglify-js":"latest",nodeunit:"^0.9.0",grunt:"~0.4.0","grunt-contrib-jshint":"~0.1.1","grunt-contrib-nodeunit":"^0.4.1","grunt-contrib-concat":"~0.1.3","grunt-contrib-uglify":"^0.5.1","grunt-browserify":"^2.1.4","grunt-contrib-yuidoc":"^0.5.2",browserify:"*"},dependencies:{}}},{}],2:[function(e,f){f.exports={version:e("../package.json").version,AABB:e("./collision/AABB"),ArrayCollisionMatrix:e("./collision/ArrayCollisionMatrix"),Body:e("./objects/Body"),Box:e("./shapes/Box"),Broadphase:e("./collision/Broadphase"),Constraint:e("./constraints/Constraint"),ContactEquation:e("./equations/ContactEquation"),Narrowphase:e("./world/Narrowphase"),ConeTwistConstraint:e("./constraints/ConeTwistConstraint"),ContactMaterial:e("./material/ContactMaterial"),ConvexPolyhedron:e("./shapes/ConvexPolyhedron"),Cylinder:e("./shapes/Cylinder"),DistanceConstraint:e("./constraints/DistanceConstraint"),Equation:e("./equations/Equation"),EventTarget:e("./utils/EventTarget"),FrictionEquation:e("./equations/FrictionEquation"),GSSolver:e("./solver/GSSolver"),GridBroadphase:e("./collision/GridBroadphase"),Heightfield:e("./shapes/Heightfield"),HingeConstraint:e("./constraints/HingeConstraint"),LockConstraint:e("./constraints/LockConstraint"),Mat3:e("./math/Mat3"),Material:e("./material/Material"),NaiveBroadphase:e("./collision/NaiveBroadphase"),ObjectCollisionMatrix:e("./collision/ObjectCollisionMatrix"),Pool:e("./utils/Pool"),Particle:e("./shapes/Particle"),Plane:e("./shapes/Plane"),PointToPointConstraint:e("./constraints/PointToPointConstraint"),Quaternion:e("./math/Quaternion"),Ray:e("./collision/Ray"),RaycastVehicle:e("./objects/RaycastVehicle"),RaycastResult:e("./collision/RaycastResult"),RigidVehicle:e("./objects/RigidVehicle"),RotationalEquation:e("./equations/RotationalEquation"),RotationalMotorEquation:e("./equations/RotationalMotorEquation"),SAPBroadphase:e("./collision/SAPBroadphase"),SPHSystem:e("./objects/SPHSystem"),Shape:e("./shapes/Shape"),Solver:e("./solver/Solver"),Sphere:e("./shapes/Sphere"),SplitSolver:e("./solver/SplitSolver"),Spring:e("./objects/Spring"),Trimesh:e("./shapes/Trimesh"),Vec3:e("./math/Vec3"),Vec3Pool:e("./utils/Vec3Pool"),World:e("./world/World")}},{"../package.json":1,"./collision/AABB":3,"./collision/ArrayCollisionMatrix":4,"./collision/Broadphase":5,"./collision/GridBroadphase":6,"./collision/NaiveBroadphase":7,"./collision/ObjectCollisionMatrix":8,"./collision/Ray":9,"./collision/RaycastResult":10,"./collision/SAPBroadphase":11,"./constraints/ConeTwistConstraint":12,"./constraints/Constraint":13,"./constraints/DistanceConstraint":14,"./constraints/HingeConstraint":15,"./constraints/LockConstraint":16,"./constraints/PointToPointConstraint":17,"./equations/ContactEquation":19,"./equations/Equation":20,"./equations/FrictionEquation":21,"./equations/RotationalEquation":22,"./equations/RotationalMotorEquation":23,"./material/ContactMaterial":24,"./material/Material":25,"./math/Mat3":27,"./math/Quaternion":28,"./math/Vec3":30,"./objects/Body":31,"./objects/RaycastVehicle":32,"./objects/RigidVehicle":33,"./objects/SPHSystem":34,"./objects/Spring":35,"./shapes/Box":37,"./shapes/ConvexPolyhedron":38,"./shapes/Cylinder":39,"./shapes/Heightfield":40,"./shapes/Particle":41,"./shapes/Plane":42,"./shapes/Shape":43,"./shapes/Sphere":44,"./shapes/Trimesh":45,"./solver/GSSolver":46,"./solver/Solver":47,"./solver/SplitSolver":48,"./utils/EventTarget":49,"./utils/Pool":51,"./utils/Vec3Pool":54,"./world/Narrowphase":55,"./world/World":56}],3:[function(e,f){function n(e){e=e||{},this.lowerBound=new o,e.lowerBound&&this.lowerBound.copy(e.lowerBound),this.upperBound=new o,e.upperBound&&this.upperBound.copy(e.upperBound)}{var o=e("../math/Vec3");e("../utils/Utils")}f.exports=n;var d=new o;n.prototype.setFromPoints=function(e,f,n,o){var i=this.lowerBound,t=this.upperBound,l=n;i.copy(e[0]),l&&l.vmult(i,i),t.copy(i);for(var u=1;ut.x&&(t.x=p.x),p.xt.y&&(t.y=p.y),p.yt.z&&(t.z=p.z),p.zf&&(this.lowerBound.x=f);var n=e.upperBound.x;this.upperBound.xf&&(this.lowerBound.y=f);var n=e.upperBound.y;this.upperBound.yf&&(this.lowerBound.z=f);var n=e.upperBound.z;this.upperBound.z=d.x&&f.y<=o.y&&n.y>=d.y&&f.z<=o.z&&n.z>=d.z},n.prototype.getCorners=function(e,f,n,o,d,i,t,l){var u=this.lowerBound,p=this.upperBound;e.copy(u),f.set(p.x,u.y,u.z),n.set(p.x,p.y,u.z),o.set(u.x,p.y,p.z),d.set(p.x,u.y,u.z),i.set(u.x,p.y,u.z),t.set(u.x,u.y,p.z),l.copy(p)};var i=[new o,new o,new o,new o,new o,new o,new o,new o];n.prototype.toLocalFrame=function(e,f){var n=i,o=n[0],d=n[1],t=n[2],l=n[3],u=n[4],p=n[5],s=n[6],y=n[7];this.getCorners(o,d,t,l,u,p,s,y);for(var c=0;8!==c;c++){var a=n[c];e.pointToLocal(a,a)}return f.setFromPoints(n)},n.prototype.toWorldFrame=function(e,f){var n=i,o=n[0],d=n[1],t=n[2],l=n[3],u=n[4],p=n[5],s=n[6],y=n[7];this.getCorners(o,d,t,l,u,p,s,y);for(var c=0;8!==c;c++){var a=n[c];e.pointToWorld(a,a)}return f.setFromPoints(n)}},{"../math/Vec3":30,"../utils/Utils":53}],4:[function(e,f){function n(){this.matrix=[]}f.exports=n,n.prototype.get=function(e,f){if(e=e.index,f=f.index,f>e){var n=f;f=e,e=n}return this.matrix[(e*(e+1)>>1)+f-1]},n.prototype.set=function(e,f,n){if(e=e.index,f=f.index,f>e){var o=f;f=e,e=o}this.matrix[(e*(e+1)>>1)+f-1]=n?1:0},n.prototype.reset=function(){for(var e=0,f=this.matrix.length;e!==f;e++)this.matrix[e]=0},n.prototype.setNumObjects=function(e){this.matrix.length=e*(e-1)>>1}},{}],5:[function(e,f){function n(){this.world=null,this.useBoundingBoxes=!1,this.dirty=!0}{var o=e("../objects/Body"),d=e("../math/Vec3"),i=e("../math/Quaternion");e("../shapes/Shape"),e("../shapes/Plane")}f.exports=n,n.prototype.collisionPairs=function(){throw new Error("collisionPairs not implemented for this BroadPhase class!")};var t=o.STATIC|o.KINEMATIC;n.prototype.needBroadphaseCollision=function(e,f){return 0===(e.collisionFilterGroup&f.collisionFilterMask)||0===(f.collisionFilterGroup&e.collisionFilterMask)?!1:0===(e.type&t)&&e.sleepState!==o.SLEEPING||0===(f.type&t)&&f.sleepState!==o.SLEEPING?!0:!1},n.prototype.intersectionTest=function(e,f,n,o){this.useBoundingBoxes?this.doBoundingBoxBroadphase(e,f,n,o):this.doBoundingSphereBroadphase(e,f,n,o)};{var l=new d;new d,new i,new d}n.prototype.doBoundingSphereBroadphase=function(e,f,n,o){var d=l;f.position.vsub(e.position,d);var i=Math.pow(e.boundingRadius+f.boundingRadius,2),t=d.norm2();i>t&&(n.push(e),o.push(f))},n.prototype.doBoundingBoxBroadphase=function(e,f,n,o){e.aabbNeedsUpdate&&e.computeAABB(),f.aabbNeedsUpdate&&f.computeAABB(),e.aabb.overlaps(f.aabb)&&(n.push(e),o.push(f))};var u={keys:[]},p=[],s=[];n.prototype.makePairsUnique=function(e,f){for(var n=u,o=p,d=s,i=e.length,t=0;t!==i;t++)o[t]=e[t],d[t]=f[t];e.length=0,f.length=0;for(var t=0;t!==i;t++){var l=o[t].id,y=d[t].id,c=y>l?l+","+y:y+","+l;n[c]=t,n.keys.push(c)}for(var t=0;t!==n.keys.length;t++){var c=n.keys.pop(),a=n[c];e.push(o[a]),f.push(d[a]),delete n[c]}},n.prototype.setWorld=function(){};var y=new d;n.boundingSphereCheck=function(e,f){var n=y;return e.position.vsub(f.position,n),Math.pow(e.shape.boundingSphereRadius+f.shape.boundingSphereRadius,2)>n.norm2()},n.prototype.aabbQuery=function(){return console.warn(".aabbQuery is not implemented in this Broadphase subclass."),[]}},{"../math/Quaternion":28,"../math/Vec3":30,"../objects/Body":31,"../shapes/Plane":42,"../shapes/Shape":43}],6:[function(e,f){function n(e,f,n,i,t){o.apply(this),this.nx=n||10,this.ny=i||10,this.nz=t||10,this.aabbMin=e||new d(100,100,100),this.aabbMax=f||new d(-100,-100,-100);var l=this.nx*this.ny*this.nz;if(0>=l)throw"GridBroadphase: Each dimension's n must be >0";this.bins=[],this.binLengths=[],this.bins.length=l,this.binLengths.length=l;for(var u=0;l>u;u++)this.bins[u]=[],this.binLengths[u]=0}f.exports=n;var o=e("./Broadphase"),d=e("../math/Vec3"),i=e("../shapes/Shape");n.prototype=new o,n.prototype.constructor=n;{var t=new d;new d}n.prototype.collisionPairs=function(e,f,n){function o(e,f,n,o,d,i,t){var l=(e-g)*v|0,u=(f-x)*A|0,p=(n-j)*C|0,b=I((o-g)*v),m=I((d-x)*A),N=I((i-j)*C);0>l?l=0:l>=s&&(l=s-1),0>u?u=0:u>=y&&(u=y-1),0>p?p=0:p>=c&&(p=c-1),0>b?b=0:b>=s&&(b=s-1),0>m?m=0:m>=y&&(m=y-1),0>N?N=0:N>=c&&(N=c-1),l*=a,u*=r,p*=w,b*=a,m*=r,N*=w;for(var O=l;b>=O;O+=a)for(var h=u;m>=h;h+=r)for(var k=p;N>=k;k+=w){var q=O+h+k;E[q][F[q]++]=t}}for(var d=e.numObjects(),l=e.bodies,u=this.aabbMax,p=this.aabbMin,s=this.nx,y=this.ny,c=this.nz,a=y*c,r=c,w=1,b=u.x,m=u.y,N=u.z,g=p.x,x=p.y,j=p.z,v=s/(b-g),A=y/(m-x),C=c/(N-j),O=(b-g)/s,h=(m-x)/y,k=(N-j)/c,q=.5*Math.sqrt(O*O+h*h+k*k),z=i.types,B=z.SPHERE,D=z.PLANE,E=(z.BOX,z.COMPOUND,z.CONVEXPOLYHEDRON,this.bins),F=this.binLengths,G=this.bins.length,H=0;H!==G;H++)F[H]=0;for(var I=Math.ceil,p=Math.min,u=Math.max,H=0;H!==d;H++){var J=l[H],K=J.shape;switch(K.type){case B:var L=J.position.x,M=J.position.y,P=J.position.z,Q=K.radius;o(L-Q,M-Q,P-Q,L+Q,M+Q,P+Q,J);break;case D:K.worldNormalNeedsUpdate&&K.computeWorldNormal(J.quaternion);var R=K.worldNormal,S=g+.5*O-J.position.x,T=x+.5*h-J.position.y,U=j+.5*k-J.position.z,V=t;V.set(S,T,U);for(var W=0,X=0;W!==s;W++,X+=a,V.y=T,V.x+=O)for(var Y=0,Z=0;Y!==y;Y++,Z+=r,V.z=U,V.y+=h)for(var $=0,_=0;$!==c;$++,_+=w,V.z+=k)if(V.dot(R)1)for(var nf=E[H],W=0;W!==ff;W++)for(var J=nf[W],Y=0;Y!==W;Y++){var of=nf[Y];this.needBroadphaseCollision(J,of)&&this.intersectionTest(J,of,f,n)}}this.makePairsUnique(f,n)}},{"../math/Vec3":30,"../shapes/Shape":43,"./Broadphase":5}],7:[function(e,f){function n(){o.apply(this)}f.exports=n;var o=e("./Broadphase"),d=e("./AABB");n.prototype=new o,n.prototype.constructor=n,n.prototype.collisionPairs=function(e,f,n){var o,d,i,t,l=e.bodies,u=l.length;for(o=0;o!==u;o++)for(d=0;d!==o;d++)i=l[o],t=l[d],this.needBroadphaseCollision(i,t)&&this.intersectionTest(i,t,f,n)};new d;n.prototype.aabbQuery=function(e,f,n){n=n||[];for(var o=0;oe){var n=f;f=e,e=n}return e+"-"+f in this.matrix},n.prototype.set=function(e,f,n){if(e=e.id,f=f.id,f>e){var o=f;f=e,e=o}n?this.matrix[e+"-"+f]=!0:delete this.matrix[e+"-"+f]},n.prototype.reset=function(){this.matrix={}},n.prototype.setNumObjects=function(){}},{}],9:[function(e,f){function n(e,f){this.from=e?e.clone():new i,this.to=f?f.clone():new i,this._direction=new i,this.precision=1e-4,this.checkCollisionResponse=!0,this.skipBackfaces=!1,this.collisionFilterMask=-1,this.collisionFilterGroup=-1,this.mode=n.ANY,this.result=new u,this.hasHit=!1,this.callback=function(){}}function o(e,f,n,o){o.vsub(f,G),n.vsub(f,a),e.vsub(f,r);var d,i,t=G.dot(G),l=G.dot(a),u=G.dot(r),p=a.dot(a),s=a.dot(r);return(d=p*u-l*s)>=0&&(i=t*s-l*u)>=0&&t*p-l*l>d+i}function d(e,f,n){n.vsub(e,G);var o=G.dot(f);f.mult(o,H),H.vadd(e,H);var d=n.distanceTo(H);return d}f.exports=n;var i=e("../math/Vec3"),t=e("../math/Quaternion"),l=e("../math/Transform"),u=(e("../shapes/ConvexPolyhedron"),e("../shapes/Box"),e("../collision/RaycastResult")),p=e("../shapes/Shape"),s=e("../collision/AABB");n.prototype.constructor=n,n.CLOSEST=1,n.ANY=2,n.ALL=4;var y=new s,c=[];n.prototype.intersectWorld=function(e,f){return this.mode=f.mode||n.ANY,this.result=f.result||new u,this.skipBackfaces=!!f.skipBackfaces,this.collisionFilterMask="undefined"!=typeof f.collisionFilterMask?f.collisionFilterMask:-1,this.collisionFilterGroup="undefined"!=typeof f.collisionFilterGroup?f.collisionFilterGroup:-1,f.from&&this.from.copy(f.from),f.to&&this.to.copy(f.to),this.callback=f.callback||function(){},this.hasHit=!1,this.result.reset(),this._updateDirection(),this.getAABB(y),c.length=0,e.broadphase.aabbQuery(e,y,c),this.intersectBodies(c),this.hasHit};var a=new i,r=new i;n.pointInTriangle=o;var w=new i,b=new t;n.prototype.intersectBody=function(e,f){f&&(this.result=f,this._updateDirection());var n=this.checkCollisionResponse;if((!n||e.collisionResponse)&&0!==(this.collisionFilterGroup&e.collisionFilterMask)&&0!==(e.collisionFilterGroup&this.collisionFilterMask))for(var o=w,d=b,i=0,t=e.shapes.length;t>i;i++){var l=e.shapes[i];if((!n||l.collisionResponse)&&(e.quaternion.mult(e.shapeOrientations[i],d),e.quaternion.vmult(e.shapeOffsets[i],o),o.vadd(e.position,o),this.intersectShape(l,d,o,e),this.result._shouldStop))break}},n.prototype.intersectBodies=function(e,f){f&&(this.result=f,this._updateDirection());for(var n=0,o=e.length;!this.result._shouldStop&&o>n;n++)this.intersectBody(e[n])},n.prototype._updateDirection=function(){this.to.vsub(this.from,this._direction),this._direction.normalize()},n.prototype.intersectShape=function(e,f,n,o){var i=this.from,t=d(i,this._direction,n);if(!(t>e.boundingSphereRadius)){var l=this[e.type];l&&l.call(this,e,f,n,o)}};{var m=(new i,new i,new i),N=new i,g=new i,x=new i;new i,new u}n.prototype.intersectBox=function(e,f,n,o){return this.intersectConvex(e.convexPolyhedronRepresentation,f,n,o)},n.prototype[p.types.BOX]=n.prototype.intersectBox,n.prototype.intersectPlane=function(e,f,n,o){var d=this.from,t=this.to,l=this._direction,u=new i(0,0,1);f.vmult(u,u);var p=new i;d.vsub(n,p);var s=p.dot(u);t.vsub(n,p);var y=p.dot(u);if(!(s*y>0||d.distanceTo(t)c)&&(c=p[0]),(null===y||p[1]a)&&(a=p[1])),null!==s){var w=[];e.getRectMinMax(s,y,c,a,w);for(var b=(w[0],w[1],s);c>=b;b++)for(var m=y;a>=m;m++){if(this.result._shouldStop)return;if(e.getConvexTrianglePillar(b,m,!1),l.pointToWorldFrame(o,f,e.pillarOffset,t),this.intersectConvex(e.pillarConvex,f,t,d,j),this.result._shouldStop)return;e.getConvexTrianglePillar(b,m,!0),l.pointToWorldFrame(o,f,e.pillarOffset,t),this.intersectConvex(e.pillarConvex,f,t,d,j)}}},n.prototype[p.types.HEIGHTFIELD]=n.prototype.intersectHeightfield;var v=new i,A=new i;n.prototype.intersectSphere=function(e,f,n,o){var d=this.from,i=this.to,t=e.radius,l=Math.pow(i.x-d.x,2)+Math.pow(i.y-d.y,2)+Math.pow(i.z-d.z,2),u=2*((i.x-d.x)*(d.x-n.x)+(i.y-d.y)*(d.y-n.y)+(i.z-d.z)*(d.z-n.z)),p=Math.pow(d.x-n.x,2)+Math.pow(d.y-n.y,2)+Math.pow(d.z-n.z,2)-Math.pow(t,2),s=Math.pow(u,2)-4*l*p,y=v,c=A;if(!(0>s))if(0===s)d.lerp(i,s,y),y.vsub(n,c),c.normalize(),this.reportIntersection(c,y,e,o,-1);else{var a=(-u-Math.sqrt(s))/(2*l),r=(-u+Math.sqrt(s))/(2*l);if(a>=0&&1>=a&&(d.lerp(i,a,y),y.vsub(n,c),c.normalize(),this.reportIntersection(c,y,e,o,-1)),this.result._shouldStop)return;r>=0&&1>=r&&(d.lerp(i,r,y),y.vsub(n,c),c.normalize(),this.reportIntersection(c,y,e,o,-1))}},n.prototype[p.types.SPHERE]=n.prototype.intersectSphere;var C=new i,O=(new i,new i,new i);n.prototype.intersectConvex=function(e,f,n,d,i){for(var t=C,l=O,u=i&&i.faceList||null,p=e.faces,s=e.vertices,y=e.faceNormals,c=this._direction,a=this.from,r=this.to,w=a.distanceTo(r),b=u?u.length:p.length,j=this.result,v=0;!j._shouldStop&&b>v;v++){var A=u?u[v]:v,h=p[A],k=y[A],q=f,z=n;l.copy(s[h[0]]),q.vmult(l,l),l.vadd(z,l),l.vsub(a,l),q.vmult(k,t);var B=c.dot(t);if(!(Math.abs(B)D)){c.mult(D,m),m.vadd(a,m),N.copy(s[h[0]]),q.vmult(N,N),z.vadd(N,N);for(var E=1;!j._shouldStop&&Ew||this.reportIntersection(t,m,e,d,A)}}}}},n.prototype[p.types.CONVEXPOLYHEDRON]=n.prototype.intersectConvex;var h=new i,k=new i,q=new i,z=new i,B=new i,D=new i,E=(new s,[]),F=new l;n.prototype.intersectTrimesh=function(e,f,n,d,i){var t=h,u=E,p=F,s=O,y=k,c=q,a=z,r=D,w=B,b=(i&&i.faceList||null,e.indices),j=(e.vertices,e.faceNormals,this.from),v=this.to,A=this._direction;p.position.copy(n),p.quaternion.copy(f),l.vectorToLocalFrame(n,f,A,y),l.pointToLocalFrame(n,f,j,c),l.pointToLocalFrame(n,f,v,a);var C=c.distanceSquared(a);e.tree.rayQuery(this,p,u);for(var G=0,H=u.length;!this.result._shouldStop&&G!==H;G++){var I=u[G];e.getNormal(I,t),e.getVertex(b[3*I],N),N.vsub(c,s);var J=y.dot(t),K=t.dot(s)/J;if(!(0>K)){y.scale(K,m),m.vadd(c,m),e.getVertex(b[3*I+1],g),e.getVertex(b[3*I+2],x);var L=m.distanceSquared(c);!o(m,g,N,x)&&!o(m,N,g,x)||L>C||(l.vectorToWorldFrame(f,t,w),l.pointToWorldFrame(n,f,m,r),this.reportIntersection(w,r,e,d,I))}}u.length=0},n.prototype[p.types.TRIMESH]=n.prototype.intersectTrimesh,n.prototype.reportIntersection=function(e,f,o,d,i){var t=this.from,l=this.to,u=t.distanceTo(f),p=this.result;if(!(this.skipBackfaces&&e.dot(this._direction)>0))switch(p.hitFaceIndex="undefined"!=typeof i?i:-1,this.mode){case n.ALL:this.hasHit=!0,p.set(t,l,e,f,o,d,u),p.hasHit=!0,this.callback(p);break;case n.CLOSEST:(uf;f++){for(var o=e[f],d=f-1;d>=0&&!(e[d].aabb.lowerBound.x<=o.aabb.lowerBound.x);d--)e[d+1]=e[d];e[d+1]=o}return e},n.insertionSortY=function(e){for(var f=1,n=e.length;n>f;f++){for(var o=e[f],d=f-1;d>=0&&!(e[d].aabb.lowerBound.y<=o.aabb.lowerBound.y);d--)e[d+1]=e[d];e[d+1]=o}return e},n.insertionSortZ=function(e){for(var f=1,n=e.length;n>f;f++){for(var o=e[f],d=f-1;d>=0&&!(e[d].aabb.lowerBound.z<=o.aabb.lowerBound.z);d--)e[d+1]=e[d];e[d+1]=o}return e},n.prototype.collisionPairs=function(e,f,o){var d,i,t=this.axisList,l=t.length,u=this.axisIndex;for(this.dirty&&(this.sortList(),this.dirty=!1),d=0;d!==l;d++){var p=t[d];for(i=d+1;l>i;i++){var s=t[i];if(this.needBroadphaseCollision(p,s)){if(!n.checkBounds(p,s,u))break;this.intersectionTest(p,s,f,o)}}}},n.prototype.sortList=function(){for(var e=this.axisList,f=this.axisIndex,o=e.length,d=0;d!==o;d++){var i=e[d];i.aabbNeedsUpdate&&i.computeAABB()}0===f?n.insertionSortX(e):1===f?n.insertionSortY(e):2===f&&n.insertionSortZ(e)},n.checkBounds=function(e,f,n){var o,d;0===n?(o=e.position.x,d=f.position.x):1===n?(o=e.position.y,d=f.position.y):2===n&&(o=e.position.z,d=f.position.z);var i=e.boundingRadius,t=f.boundingRadius,l=o+i,u=d-t;return l>u},n.prototype.autoDetectAxis=function(){for(var e=0,f=0,n=0,o=0,d=0,i=0,t=this.axisList,l=t.length,u=1/l,p=0;p!==l;p++){var s=t[p],y=s.position.x;e+=y,f+=y*y;var c=s.position.y;n+=c,o+=c*c;var a=s.position.z;d+=a,i+=a*a}var r=f-e*e*u,w=o-n*n*u,b=i-d*d*u;this.axisIndex=r>w?r>b?0:2:w>b?1:2},n.prototype.aabbQuery=function(e,f,n){n=n||[],this.dirty&&(this.sortList(),this.dirty=!1);var o=this.axisIndex,d="x";1===o&&(d="y"),2===o&&(d="z");for(var i=this.axisList,t=(f.lowerBound[d],f.upperBound[d],0);td;d++)for(var i=0;3>i;i++){for(var t=0,l=0;3>l;l++)t+=e.elements[d+3*l]*this.elements[l+3*i];o.elements[d+3*i]=t}return o},n.prototype.scale=function(e,f){f=f||new n;for(var o=this.elements,d=f.elements,i=0;3!==i;i++)d[3*i+0]=e.x*o[3*i+0],d[3*i+1]=e.y*o[3*i+1],d[3*i+2]=e.z*o[3*i+2];return f},n.prototype.solve=function(e,f){f=f||new o;for(var n=3,d=4,i=[],t=0;n*d>t;t++)i.push(0);var t,l;for(t=0;3>t;t++)for(l=0;3>l;l++)i[t+d*l]=this.elements[t+3*l];i[3]=e.x,i[7]=e.y,i[11]=e.z;var u,p,s=3,y=s,c=4;do{if(t=y-s,0===i[t+d*t])for(l=t+1;y>l;l++)if(0!==i[t+d*l]){u=c;do p=c-u,i[p+d*t]+=i[p+d*l];while(--u);break}if(0!==i[t+d*t])for(l=t+1;y>l;l++){var a=i[t+d*l]/i[t+d*t];u=c;do p=c-u,i[p+d*l]=t>=p?0:i[p+d*l]-i[p+d*t]*a;while(--u)}}while(--s);if(f.z=i[2*d+3]/i[2*d+2],f.y=(i[1*d+3]-i[1*d+2]*f.z)/i[1*d+1],f.x=(i[0*d+3]-i[0*d+2]*f.z-i[0*d+1]*f.y)/i[0*d+0],isNaN(f.x)||isNaN(f.y)||isNaN(f.z)||1/0===f.x||1/0===f.y||1/0===f.z)throw"Could not solve equation! Got x=["+f.toString()+"], b=["+e.toString()+"], A=["+this.toString()+"]";return f},n.prototype.e=function(e,f,n){return void 0===n?this.elements[f+3*e]:void(this.elements[f+3*e]=n)},n.prototype.copy=function(e){for(var f=0;fn;n++)e+=this.elements[n]+f;return e},n.prototype.reverse=function(e){e=e||new n;for(var f=3,o=6,d=[],i=0;f*o>i;i++)d.push(0);var i,t;for(i=0;3>i;i++)for(t=0;3>t;t++)d[i+o*t]=this.elements[i+3*t];d[3]=1,d[9]=0,d[15]=0,d[4]=0,d[10]=1,d[16]=0,d[5]=0,d[11]=0,d[17]=1;var l,u,p=3,s=p,y=o;do{if(i=s-p,0===d[i+o*i])for(t=i+1;s>t;t++)if(0!==d[i+o*t]){l=y;do u=y-l,d[u+o*i]+=d[u+o*t];while(--l);break}if(0!==d[i+o*i])for(t=i+1;s>t;t++){var c=d[i+o*t]/d[i+o*i];l=y;do u=y-l,d[u+o*t]=i>=u?0:d[u+o*t]-d[u+o*i]*c;while(--l)}}while(--p);i=2;do{t=i-1;do{var c=d[i+o*t]/d[i+o*i];l=o;do u=o-l,d[u+o*t]=d[u+o*t]-d[u+o*i]*c;while(--l)}while(t--)}while(--i);i=2;do{var c=1/d[i+o*i];l=o;do u=o-l,d[u+o*i]=d[u+o*i]*c;while(--l)}while(i--);i=2;do{t=2;do{if(u=d[f+t+o*i],isNaN(u)||1/0===u)throw"Could not reverse! A=["+this.toString()+"]";e.e(i,t,u)}while(t--)}while(i--);return e},n.prototype.setRotationFromQuaternion=function(e){var f=e.x,n=e.y,o=e.z,d=e.w,i=f+f,t=n+n,l=o+o,u=f*i,p=f*t,s=f*l,y=n*t,c=n*l,a=o*l,r=d*i,w=d*t,b=d*l,m=this.elements;return m[0]=1-(y+a),m[1]=p-b,m[2]=s+w,m[3]=p+b,m[4]=1-(u+a),m[5]=c-r,m[6]=s-w,m[7]=c+r,m[8]=1-(u+y),this},n.prototype.transpose=function(e){e=e||new n;for(var f=e.elements,o=this.elements,d=0;3!==d;d++)for(var i=0;3!==i;i++)f[3*d+i]=o[3*i+d];return e}},{"./Vec3":30}],28:[function(e,f){function n(e,f,n,o){this.x=void 0!==e?e:0,this.y=void 0!==f?f:0,this.z=void 0!==n?n:0,this.w=void 0!==o?o:1}f.exports=n;var o=e("./Vec3");n.prototype.set=function(e,f,n,o){this.x=e,this.y=f,this.z=n,this.w=o},n.prototype.toString=function(){return this.x+","+this.y+","+this.z+","+this.w},n.prototype.toArray=function(){return[this.x,this.y,this.z,this.w]},n.prototype.setFromAxisAngle=function(e,f){var n=Math.sin(.5*f);this.x=e.x*n,this.y=e.y*n,this.z=e.z*n,this.w=Math.cos(.5*f)},n.prototype.toAxisAngle=function(e){e=e||new o,this.normalize();var f=2*Math.acos(this.w),n=Math.sqrt(1-this.w*this.w);return.001>n?(e.x=this.x,e.y=this.y,e.z=this.z):(e.x=this.x/n,e.y=this.y/n,e.z=this.z/n),[e,f]};var d=new o,i=new o;n.prototype.setFromVectors=function(e,f){if(e.isAntiparallelTo(f)){var n=d,o=i;e.tangents(n,o),this.setFromAxisAngle(n,Math.PI)}else{var t=e.cross(f);this.x=t.x,this.y=t.y,this.z=t.z,this.w=Math.sqrt(Math.pow(e.norm(),2)*Math.pow(f.norm(),2))+e.dot(f),this.normalize()}};var t=new o,l=new o,u=new o;n.prototype.mult=function(e,f){f=f||new n;var o=this.w,d=t,i=l,p=u;return d.set(this.x,this.y,this.z),i.set(e.x,e.y,e.z),f.w=o*e.w-d.dot(i),d.cross(i,p),f.x=o*i.x+e.w*d.x+p.x,f.y=o*i.y+e.w*d.y+p.y,f.z=o*i.z+e.w*d.z+p.z,f},n.prototype.inverse=function(e){var f=this.x,o=this.y,d=this.z,i=this.w;e=e||new n,this.conjugate(e);var t=1/(f*f+o*o+d*d+i*i);return e.x*=t,e.y*=t,e.z*=t,e.w*=t,e},n.prototype.conjugate=function(e){return e=e||new n,e.x=-this.x,e.y=-this.y,e.z=-this.z,e.w=this.w,e},n.prototype.normalize=function(){var e=Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w);0===e?(this.x=0,this.y=0,this.z=0,this.w=0):(e=1/e,this.x*=e,this.y*=e,this.z*=e,this.w*=e)},n.prototype.normalizeFast=function(){var e=(3-(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w))/2;0===e?(this.x=0,this.y=0,this.z=0,this.w=0):(this.x*=e,this.y*=e,this.z*=e,this.w*=e)},n.prototype.vmult=function(e,f){f=f||new o;var n=e.x,d=e.y,i=e.z,t=this.x,l=this.y,u=this.z,p=this.w,s=p*n+l*i-u*d,y=p*d+u*n-t*i,c=p*i+t*d-l*n,a=-t*n-l*d-u*i;return f.x=s*p+a*-t+y*-u-c*-l,f.y=y*p+a*-l+c*-t-s*-u,f.z=c*p+a*-u+s*-l-y*-t,f},n.prototype.copy=function(e){return this.x=e.x,this.y=e.y,this.z=e.z,this.w=e.w,this},n.prototype.toEuler=function(e,f){f=f||"YZX";var n,o,d,i=this.x,t=this.y,l=this.z,u=this.w;switch(f){case"YZX":var p=i*t+l*u;if(p>.499&&(n=2*Math.atan2(i,u),o=Math.PI/2,d=0),-.499>p&&(n=-2*Math.atan2(i,u),o=-Math.PI/2,d=0),isNaN(n)){var s=i*i,y=t*t,c=l*l;n=Math.atan2(2*t*u-2*i*l,1-2*y-2*c),o=Math.asin(2*p),d=Math.atan2(2*i*u-2*t*l,1-2*s-2*c)}break;default:throw new Error("Euler order "+f+" not supported yet.")}e.y=n,e.z=o,e.x=d},n.prototype.setFromEuler=function(e,f,n,o){o=o||"XYZ";var d=Math.cos(e/2),i=Math.cos(f/2),t=Math.cos(n/2),l=Math.sin(e/2),u=Math.sin(f/2),p=Math.sin(n/2);return"XYZ"===o?(this.x=l*i*t+d*u*p,this.y=d*u*t-l*i*p,this.z=d*i*p+l*u*t,this.w=d*i*t-l*u*p):"YXZ"===o?(this.x=l*i*t+d*u*p,this.y=d*u*t-l*i*p,this.z=d*i*p-l*u*t,this.w=d*i*t+l*u*p):"ZXY"===o?(this.x=l*i*t-d*u*p,this.y=d*u*t+l*i*p,this.z=d*i*p+l*u*t,this.w=d*i*t-l*u*p):"ZYX"===o?(this.x=l*i*t-d*u*p,this.y=d*u*t+l*i*p,this.z=d*i*p-l*u*t,this.w=d*i*t+l*u*p):"YZX"===o?(this.x=l*i*t+d*u*p,this.y=d*u*t+l*i*p,this.z=d*i*p-l*u*t,this.w=d*i*t-l*u*p):"XZY"===o&&(this.x=l*i*t-d*u*p,this.y=d*u*t-l*i*p,this.z=d*i*p+l*u*t,this.w=d*i*t+l*u*p),this},n.prototype.clone=function(){return new n(this.x,this.y,this.z,this.w)}},{"./Vec3":30}],29:[function(e,f){function n(e){e=e||{},this.position=new o,e.position&&this.position.copy(e.position),this.quaternion=new d,e.quaternion&&this.quaternion.copy(e.quaternion)}var o=e("./Vec3"),d=e("./Quaternion");f.exports=n;var i=new d;n.pointToLocalFrame=function(e,f,n,d){var d=d||new o;return n.vsub(e,d),f.conjugate(i),i.vmult(d,d),d},n.prototype.pointToLocal=function(e,f){return n.pointToLocalFrame(this.position,this.quaternion,e,f)},n.pointToWorldFrame=function(e,f,n,d){var d=d||new o;return f.vmult(n,d),d.vadd(e,d),d},n.prototype.pointToWorld=function(e,f){return n.pointToWorldFrame(this.position,this.quaternion,e,f)},n.prototype.vectorToWorldFrame=function(e,f){var f=f||new o;return this.quaternion.vmult(e,f),f},n.vectorToWorldFrame=function(e,f,n){return e.vmult(f,n),n},n.vectorToLocalFrame=function(e,f,n,d){var d=d||new o;return f.w*=-1,f.vmult(n,d),f.w*=-1,d}},{"./Quaternion":28,"./Vec3":30}],30:[function(e,f){function n(e,f,n){this.x=e||0,this.y=f||0,this.z=n||0}f.exports=n;var o=e("./Mat3");n.ZERO=new n(0,0,0),n.UNIT_X=new n(1,0,0),n.UNIT_Y=new n(0,1,0),n.UNIT_Z=new n(0,0,1),n.prototype.cross=function(e,f){var o=e.x,d=e.y,i=e.z,t=this.x,l=this.y,u=this.z;return f=f||new n,f.x=l*i-u*d,f.y=u*o-t*i,f.z=t*d-l*o,f},n.prototype.set=function(e,f,n){return this.x=e,this.y=f,this.z=n,this},n.prototype.setZero=function(){this.x=this.y=this.z=0},n.prototype.vadd=function(e,f){return f?(f.x=e.x+this.x,f.y=e.y+this.y,f.z=e.z+this.z,void 0):new n(this.x+e.x,this.y+e.y,this.z+e.z)},n.prototype.vsub=function(e,f){return f?(f.x=this.x-e.x,f.y=this.y-e.y,f.z=this.z-e.z,void 0):new n(this.x-e.x,this.y-e.y,this.z-e.z)},n.prototype.crossmat=function(){return new o([0,-this.z,this.y,this.z,0,-this.x,-this.y,this.x,0])},n.prototype.normalize=function(){var e=this.x,f=this.y,n=this.z,o=Math.sqrt(e*e+f*f+n*n);if(o>0){var d=1/o;this.x*=d,this.y*=d,this.z*=d}else this.x=0,this.y=0,this.z=0;return o},n.prototype.unit=function(e){e=e||new n;var f=this.x,o=this.y,d=this.z,i=Math.sqrt(f*f+o*o+d*d);return i>0?(i=1/i,e.x=f*i,e.y=o*i,e.z=d*i):(e.x=1,e.y=0,e.z=0),e},n.prototype.norm=function(){var e=this.x,f=this.y,n=this.z;return Math.sqrt(e*e+f*f+n*n)},n.prototype.length=n.prototype.norm,n.prototype.norm2=function(){return this.dot(this)},n.prototype.lengthSquared=n.prototype.norm2,n.prototype.distanceTo=function(e){var f=this.x,n=this.y,o=this.z,d=e.x,i=e.y,t=e.z;return Math.sqrt((d-f)*(d-f)+(i-n)*(i-n)+(t-o)*(t-o))},n.prototype.distanceSquared=function(e){var f=this.x,n=this.y,o=this.z,d=e.x,i=e.y,t=e.z;return(d-f)*(d-f)+(i-n)*(i-n)+(t-o)*(t-o)},n.prototype.mult=function(e,f){f=f||new n;var o=this.x,d=this.y,i=this.z;return f.x=e*o,f.y=e*d,f.z=e*i,f},n.prototype.scale=n.prototype.mult,n.prototype.dot=function(e){return this.x*e.x+this.y*e.y+this.z*e.z},n.prototype.isZero=function(){return 0===this.x&&0===this.y&&0===this.z},n.prototype.negate=function(e){return e=e||new n,e.x=-this.x,e.y=-this.y,e.z=-this.z,e};var d=new n,i=new n;n.prototype.tangents=function(e,f){var n=this.norm();if(n>0){var o=d,t=1/n;o.set(this.x*t,this.y*t,this.z*t);var l=i;Math.abs(o.x)<.9?(l.set(1,0,0),o.cross(l,e)):(l.set(0,1,0),o.cross(l,e)),o.cross(e,f)}else e.set(1,0,0),f.set(0,1,0)},n.prototype.toString=function(){return this.x+","+this.y+","+this.z},n.prototype.toArray=function(){return[this.x,this.y,this.z]},n.prototype.copy=function(e){return this.x=e.x,this.y=e.y,this.z=e.z,this},n.prototype.lerp=function(e,f,n){var o=this.x,d=this.y,i=this.z;n.x=o+(e.x-o)*f,n.y=d+(e.y-d)*f,n.z=i+(e.z-i)*f},n.prototype.almostEquals=function(e,f){return void 0===f&&(f=1e-6),Math.abs(this.x-e.x)>f||Math.abs(this.y-e.y)>f||Math.abs(this.z-e.z)>f?!1:!0},n.prototype.almostZero=function(e){return void 0===e&&(e=1e-6),Math.abs(this.x)>e||Math.abs(this.y)>e||Math.abs(this.z)>e?!1:!0};var t=new n;n.prototype.isAntiparallelTo=function(e,f){return this.negate(t),t.almostEquals(e,f)},n.prototype.clone=function(){return new n(this.x,this.y,this.z)}},{"./Mat3":27}],31:[function(e,f){function n(e){e=e||{},o.apply(this),this.id=n.idCounter++,this.world=null,this.preStep=null,this.postStep=null,this.vlambda=new d,this.collisionFilterGroup="number"==typeof e.collisionFilterGroup?e.collisionFilterGroup:1,this.collisionFilterMask="number"==typeof e.collisionFilterMask?e.collisionFilterMask:1,this.collisionResponse=!0,this.position=new d,e.position&&this.position.copy(e.position),this.previousPosition=new d,this.initPosition=new d,this.velocity=new d,e.velocity&&this.velocity.copy(e.velocity),this.initVelocity=new d,this.force=new d;var f="number"==typeof e.mass?e.mass:0;this.mass=f,this.invMass=f>0?1/f:0,this.material=e.material||null,this.linearDamping="number"==typeof e.linearDamping?e.linearDamping:.01,this.type=0>=f?n.STATIC:n.DYNAMIC,typeof e.type==typeof n.STATIC&&(this.type=e.type),this.allowSleep="undefined"!=typeof e.allowSleep?e.allowSleep:!0,this.sleepState=0,this.sleepSpeedLimit="undefined"!=typeof e.sleepSpeedLimit?e.sleepSpeedLimit:.1,this.sleepTimeLimit="undefined"!=typeof e.sleepTimeLimit?e.sleepTimeLimit:1,this.timeLastSleepy=0,this._wakeUpAfterNarrowphase=!1,this.torque=new d,this.quaternion=new t,e.quaternion&&this.quaternion.copy(e.quaternion),this.initQuaternion=new t,this.angularVelocity=new d,e.angularVelocity&&this.angularVelocity.copy(e.angularVelocity),this.initAngularVelocity=new d,this.interpolatedPosition=new d,this.interpolatedQuaternion=new t,this.shapes=[],this.shapeOffsets=[],this.shapeOrientations=[],this.inertia=new d,this.invInertia=new d,this.invInertiaWorld=new i,this.invMassSolve=0,this.invInertiaSolve=new d,this.invInertiaWorldSolve=new i,this.fixedRotation="undefined"!=typeof e.fixedRotation?e.fixedRotation:!1,this.angularDamping="undefined"!=typeof e.angularDamping?e.angularDamping:.01,this.aabb=new l,this.aabbNeedsUpdate=!0,this.wlambda=new d,e.shape&&this.addShape(e.shape),this.updateMassProperties()}f.exports=n;var o=e("../utils/EventTarget"),d=(e("../shapes/Shape"),e("../math/Vec3")),i=e("../math/Mat3"),t=e("../math/Quaternion"),l=(e("../material/Material"),e("../collision/AABB")),u=e("../shapes/Box");n.prototype=new o,n.prototype.constructor=n,n.DYNAMIC=1,n.STATIC=2,n.KINEMATIC=4,n.AWAKE=0,n.SLEEPY=1,n.SLEEPING=2,n.idCounter=0,n.prototype.wakeUp=function(){var e=this.sleepState;this.sleepState=0,e===n.SLEEPING&&this.dispatchEvent({type:"wakeup"})},n.prototype.sleep=function(){this.sleepState=n.SLEEPING,this.velocity.set(0,0,0),this.angularVelocity.set(0,0,0)},n.sleepyEvent={type:"sleepy"},n.sleepEvent={type:"sleep"},n.prototype.sleepTick=function(e){if(this.allowSleep){var f=this.sleepState,o=this.velocity.norm2()+this.angularVelocity.norm2(),d=Math.pow(this.sleepSpeedLimit,2);f===n.AWAKE&&d>o?(this.sleepState=n.SLEEPY,this.timeLastSleepy=e,this.dispatchEvent(n.sleepyEvent)):f===n.SLEEPY&&o>d?this.wakeUp():f===n.SLEEPY&&e-this.timeLastSleepy>this.sleepTimeLimit&&(this.sleep(),this.dispatchEvent(n.sleepEvent))}},n.prototype.updateSolveMassProperties=function(){this.sleepState===n.SLEEPING||this.type===n.KINEMATIC?(this.invMassSolve=0,this.invInertiaSolve.setZero(),this.invInertiaWorldSolve.setZero()):(this.invMassSolve=this.invMass,this.invInertiaSolve.copy(this.invInertia),this.invInertiaWorldSolve.copy(this.invInertiaWorld))},n.prototype.pointToLocalFrame=function(e,f){var f=f||new d;return e.vsub(this.position,f),this.quaternion.conjugate().vmult(f,f),f},n.prototype.vectorToLocalFrame=function(e,f){var f=f||new d;return this.quaternion.conjugate().vmult(e,f),f},n.prototype.pointToWorldFrame=function(e,f){var f=f||new d;return this.quaternion.vmult(e,f),f.vadd(this.position,f),f},n.prototype.vectorToWorldFrame=function(e,f){var f=f||new d;return this.quaternion.vmult(e,f),f};var p=new d,s=new t;n.prototype.addShape=function(e,f,n){var o=new d,i=new t;return f&&o.copy(f),n&&i.copy(n),this.shapes.push(e),this.shapeOffsets.push(o),this.shapeOrientations.push(i),this.updateMassProperties(),this.updateBoundingRadius(),this.aabbNeedsUpdate=!0,this},n.prototype.updateBoundingRadius=function(){for(var e=this.shapes,f=this.shapeOffsets,n=e.length,o=0,d=0;d!==n;d++){var i=e[d];i.updateBoundingSphereRadius();var t=f[d].norm(),l=i.boundingSphereRadius;t+l>o&&(o=t+l)}this.boundingRadius=o};var y=new l;n.prototype.computeAABB=function(){for(var e=this.shapes,f=this.shapeOffsets,n=this.shapeOrientations,o=e.length,d=p,i=s,t=this.quaternion,l=this.aabb,u=y,c=0;c!==o;c++){var a=e[c];n[c].mult(t,i),i.vmult(f[c],d),d.vadd(this.position,d),a.calculateWorldAABB(d,i,u.lowerBound,u.upperBound),0===c?l.copy(u):l.extend(u)}this.aabbNeedsUpdate=!1};{var c=new i,a=new i;new i}n.prototype.updateInertiaWorld=function(e){var f=this.invInertia;if(f.x!==f.y||f.y!==f.z||e){var n=c,o=a;n.setRotationFromQuaternion(this.quaternion),n.transpose(o),n.scale(f,n),n.mmult(o,this.invInertiaWorld)}else;};var r=new d,w=new d;n.prototype.applyForce=function(e,f){if(this.type===n.DYNAMIC){var o=r;f.vsub(this.position,o);var d=w;o.cross(e,d),this.force.vadd(e,this.force),this.torque.vadd(d,this.torque)}};var b=new d,m=new d;n.prototype.applyLocalForce=function(e,f){if(this.type===n.DYNAMIC){var o=b,d=m;this.vectorToWorldFrame(e,o),this.pointToWorldFrame(f,d),this.applyForce(o,d)}};var N=new d,g=new d,x=new d;n.prototype.applyImpulse=function(e,f){if(this.type===n.DYNAMIC){var o=N;f.vsub(this.position,o);var d=g;d.copy(e),d.mult(this.invMass,d),this.velocity.vadd(d,this.velocity);var i=x;o.cross(e,i),this.invInertiaWorld.vmult(i,i),this.angularVelocity.vadd(i,this.angularVelocity)}};var j=new d,v=new d;n.prototype.applyLocalImpulse=function(e,f){if(this.type===n.DYNAMIC){var o=j,d=v;this.vectorToWorldFrame(e,o),this.pointToWorldFrame(f,d),this.applyImpulse(o,d)}};var A=new d;n.prototype.updateMassProperties=function(){var e=A;this.invMass=this.mass>0?1/this.mass:0;var f=this.inertia,n=this.fixedRotation;this.computeAABB(),e.set((this.aabb.upperBound.x-this.aabb.lowerBound.x)/2,(this.aabb.upperBound.y-this.aabb.lowerBound.y)/2,(this.aabb.upperBound.z-this.aabb.lowerBound.z)/2),u.calculateInertia(e,this.mass,f),this.invInertia.set(f.x>0&&!n?1/f.x:0,f.y>0&&!n?1/f.y:0,f.z>0&&!n?1/f.z:0),this.updateInertiaWorld(!0)},n.prototype.getVelocityAtWorldPoint=function(e,f){var n=new d;return e.vsub(this.position,n),this.angularVelocity.cross(n,f),this.velocity.vadd(f,f),f}},{"../collision/AABB":3,"../material/Material":25,"../math/Mat3":27,"../math/Quaternion":28,"../math/Vec3":30,"../shapes/Box":37,"../shapes/Shape":43,"../utils/EventTarget":49}],32:[function(e,f){function n(e){this.chassisBody=e.chassisBody,this.wheelInfos=[],this.sliding=!1,this.world=null,this.indexRightAxis="undefined"!=typeof e.indexRightAxis?e.indexRightAxis:1,this.indexForwardAxis="undefined"!=typeof e.indexForwardAxis?e.indexForwardAxis:0,this.indexUpAxis="undefined"!=typeof e.indexUpAxis?e.indexUpAxis:2}function o(e,f,n,o,i){var t=0,l=n,u=x,p=j,s=v;e.getVelocityAtWorldPoint(l,u),f.getVelocityAtWorldPoint(l,p),u.vsub(p,s);var y=o.dot(s),c=d(e,n,o),a=d(f,n,o),r=1,w=r/(c+a);return t=-y*w,t>i&&(t=i),-i>t&&(t=-i),t}function d(e,f,n){var o=A,d=C,i=O,t=h;return f.vsub(e.position,o),o.cross(n,d),e.invInertiaWorld.vmult(d,t),t.cross(o,i),e.invMass+n.dot(i)}function i(e,f,n,o,d,i){var t=d.norm2();if(t>1.1)return 0;var l=k,u=q,p=z;e.getVelocityAtWorldPoint(f,l),n.getVelocityAtWorldPoint(o,u),l.vsub(u,p);var s=d.dot(p),y=.2,c=1/(e.invMass+n.invMass),i=-y*s*c;return i}var t=(e("./Body"),e("../math/Vec3")),l=e("../math/Quaternion"),u=(e("../collision/RaycastResult"),e("../collision/Ray")),p=e("../objects/WheelInfo");f.exports=n;{var s=(new t,new t,new t,new t),y=new t,c=new t;new u}n.prototype.addWheel=function(e){e=e||{};var f=new p(e),n=this.wheelInfos.length;return this.wheelInfos.push(f),n},n.prototype.setSteeringValue=function(e,f){var n=this.wheelInfos[f];n.steering=e};new t;n.prototype.applyEngineForce=function(e,f){this.wheelInfos[f].engineForce=e},n.prototype.setBrake=function(e,f){this.wheelInfos[f].brake=e},n.prototype.addToWorld=function(e){this.constraints;e.add(this.chassisBody);var f=this;this.preStepCallback=function(){f.updateVehicle(e.dt)},e.addEventListener("preStep",this.preStepCallback),this.world=e},n.prototype.getVehicleAxisWorld=function(e,f){f.set(0===e?1:0,1===e?1:0,2===e?1:0),this.chassisBody.vectorToWorldFrame(f,f)},n.prototype.updateVehicle=function(e){for(var f=this.wheelInfos,n=f.length,o=this.chassisBody,d=0;n>d;d++)this.updateWheelTransform(d);this.currentVehicleSpeedKmHour=3.6*o.velocity.norm();var i=new t;this.getVehicleAxisWorld(this.indexForwardAxis,i),i.dot(o.velocity)<0&&(this.currentVehicleSpeedKmHour*=-1);for(var d=0;n>d;d++)this.castRay(f[d]);this.updateSuspension(e);for(var l=new t,u=new t,d=0;n>d;d++){var p=f[d],s=p.suspensionForce;s>p.maxSuspensionForce&&(s=p.maxSuspensionForce),p.raycastResult.hitNormalWorld.scale(s*e,l),p.raycastResult.hitPointWorld.vsub(o.position,u),o.applyImpulse(l,p.raycastResult.hitPointWorld)}this.updateFriction(e);var y=new t,c=new t,a=new t;for(d=0;n>d;d++){var p=f[d];o.getVelocityAtWorldPoint(p.chassisConnectionPointWorld,a);var r=1;switch(this.indexUpAxis){case 1:r=-1}if(p.isInContact){this.getVehicleAxisWorld(this.indexForwardAxis,c);var w=c.dot(p.raycastResult.hitNormalWorld);p.raycastResult.hitNormalWorld.scale(w,y),c.vsub(y,c);var b=c.dot(a);p.deltaRotation=r*b*e/p.radius}!p.sliding&&p.isInContact||0===p.engineForce||!p.useCustomSlidingRotationalSpeed||(p.deltaRotation=(p.engineForce>0?1:-1)*p.customSlidingRotationalSpeed*e),Math.abs(p.brake)>Math.abs(p.engineForce)&&(p.deltaRotation=0),p.rotation+=p.deltaRotation,p.deltaRotation*=.99}},n.prototype.updateSuspension=function(){for(var e=this.chassisBody,f=e.mass,n=this.wheelInfos,o=n.length,d=0;o>d;d++){var i=n[d];if(i.isInContact){var t,l=i.suspensionRestLength,u=i.suspensionLength,p=l-u;t=i.suspensionStiffness*p*i.clippedInvContactDotSuspension;var s,y=i.suspensionRelativeVelocity;s=0>y?i.dampingCompression:i.dampingRelaxation,t-=s*y,i.suspensionForce=t*f,i.suspensionForce<0&&(i.suspensionForce=0)}else i.suspensionForce=0}},n.prototype.removeFromWorld=function(e){this.constraints;e.remove(this.chassisBody),e.removeEventListener("preStep",this.preStepCallback),this.world=null};var a=new t,r=new t;n.prototype.castRay=function(e){var f=a,n=r;this.updateWheelTransformWorld(e);var o=this.chassisBody,d=-1,i=e.suspensionRestLength+e.radius;e.directionWorld.scale(i,f);var l=e.chassisConnectionPointWorld;l.vadd(f,n);var u=e.raycastResult;u.reset();var p=o.collisionResponse;o.collisionResponse=!1,this.world.rayTest(l,n,u),o.collisionResponse=p;var s=u.body;if(e.raycastResult.groundObject=0,s){d=u.distance,e.raycastResult.hitNormalWorld=u.hitNormalWorld,e.isInContact=!0;var y=u.distance;e.suspensionLength=y-e.radius;var c=e.suspensionRestLength-e.maxSuspensionTravel,w=e.suspensionRestLength+e.maxSuspensionTravel;e.suspensionLengthw&&(e.suspensionLength=w,e.raycastResult.reset());var b=e.raycastResult.hitNormalWorld.dot(e.directionWorld),m=new t;o.getVelocityAtWorldPoint(e.raycastResult.hitPointWorld,m);var N=e.raycastResult.hitNormalWorld.dot(m);if(b>=-.1)e.suspensionRelativeVelocity=0,e.clippedInvContactDotSuspension=10;else{var g=-1/b;e.suspensionRelativeVelocity=N*g,e.clippedInvContactDotSuspension=g}}else e.suspensionLength=e.suspensionRestLength+0*e.maxSuspensionTravel,e.suspensionRelativeVelocity=0,e.directionWorld.scale(-1,e.raycastResult.hitNormalWorld),e.clippedInvContactDotSuspension=1;return d},n.prototype.updateWheelTransformWorld=function(e){e.isInContact=!1;var f=this.chassisBody;f.pointToWorldFrame(e.chassisConnectionPointLocal,e.chassisConnectionPointWorld),f.vectorToWorldFrame(e.directionLocal,e.directionWorld),f.vectorToWorldFrame(e.axleLocal,e.axleWorld)},n.prototype.updateWheelTransform=function(e){var f=s,n=y,o=c,d=this.wheelInfos[e];this.updateWheelTransformWorld(d),d.directionLocal.scale(-1,f),n.copy(d.axleLocal),f.cross(n,o),o.normalize(),n.normalize();var i=d.steering,t=new l;t.setFromAxisAngle(f,i);var u=new l;u.setFromAxisAngle(n,d.rotation);var p=d.worldTransform.quaternion;this.chassisBody.quaternion.mult(t,p),p.mult(u,p),p.normalize();var a=d.worldTransform.position;a.copy(d.directionWorld),a.scale(d.suspensionLength,a),a.vadd(d.chassisConnectionPointWorld,a)};var w=[new t(1,0,0),new t(0,1,0),new t(0,0,1)];n.prototype.getWheelTransformWorld=function(e){return this.wheelInfos[e].worldTransform};var b=new t,m=[],N=[],g=1;n.prototype.updateFriction=function(e){for(var f=b,n=this.wheelInfos,d=n.length,l=this.chassisBody,u=N,p=m,s=0,y=0;d>y;y++){var c=n[y],a=c.raycastResult.body;a&&s++,c.sideImpulse=0,c.forwardImpulse=0,u[y]||(u[y]=new t),p[y]||(p[y]=new t)}for(var y=0;d>y;y++){var c=n[y],a=c.raycastResult.body;if(a){var r=p[y],x=this.getWheelTransformWorld(y);x.vectorToWorldFrame(w[this.indexRightAxis],r);var j=c.raycastResult.hitNormalWorld,v=r.dot(j);j.scale(v,f),r.vsub(f,r),r.normalize(),j.cross(r,u[y]),u[y].normalize(),c.sideImpulse=i(l,c.raycastResult.hitPointWorld,a,c.raycastResult.hitPointWorld,r),c.sideImpulse*=g}}var A=1,C=.5;this.sliding=!1;for(var y=0;d>y;y++){var c=n[y],a=c.raycastResult.body,O=0;if(c.slipInfo=1,a){var h=0,k=c.brake?c.brake:h;O=o(l,a,c.raycastResult.hitPointWorld,u[y],k),O+=c.engineForce*e;var q=k/O;c.slipInfo*=q}if(c.forwardImpulse=0,c.skidInfo=1,a){c.skidInfo=1;var z=c.suspensionForce*e*c.frictionSlip,B=z,D=z*B;c.forwardImpulse=O;var E=c.forwardImpulse*C,F=c.sideImpulse*A,G=E*E+F*F;if(c.sliding=!1,G>D){this.sliding=!0,c.sliding=!0;var q=z/Math.sqrt(G);c.skidInfo*=q}}}if(this.sliding)for(var y=0;d>y;y++){var c=n[y];0!==c.sideImpulse&&c.skidInfo<1&&(c.forwardImpulse*=c.skidInfo,c.sideImpulse*=c.skidInfo)}for(var y=0;d>y;y++){var c=n[y],H=new t;if(H.copy(c.raycastResult.hitPointWorld),0!==c.forwardImpulse){var I=new t;u[y].scale(c.forwardImpulse,I),l.applyImpulse(I,H)}if(0!==c.sideImpulse){var a=c.raycastResult.body,J=new t;J.copy(c.raycastResult.hitPointWorld);var K=new t;p[y].scale(c.sideImpulse,K),l.pointToLocalFrame(H,H),H["xyz"[this.indexUpAxis]]*=c.rollInfluence,l.pointToWorldFrame(H,H),l.applyImpulse(K,H),K.scale(-1,K),a.applyImpulse(K,J)}}};var x=new t,j=new t,v=new t,A=new t,C=new t,O=new t,h=new t,k=new t,q=new t,z=new t},{"../collision/Ray":9,"../collision/RaycastResult":10,"../math/Quaternion":28,"../math/Vec3":30,"../objects/WheelInfo":36,"./Body":31}],33:[function(e,f){function n(e){if(this.wheelBodies=[],this.coordinateSystem="undefined"==typeof e.coordinateSystem?new t(1,2,3):e.coordinateSystem.clone(),this.chassisBody=e.chassisBody,!this.chassisBody){var f=new i(new t(5,2,.5));this.chassisBody=new o(1,f)}this.constraints=[],this.wheelAxes=[],this.wheelForces=[]}var o=e("./Body"),d=e("../shapes/Sphere"),i=e("../shapes/Box"),t=e("../math/Vec3"),l=e("../constraints/HingeConstraint");f.exports=n,n.prototype.addWheel=function(e){e=e||{};var f=e.body;f||(f=new o(1,new d(1.2))),this.wheelBodies.push(f),this.wheelForces.push(0);var n=(new t,"undefined"!=typeof e.position?e.position.clone():new t),i=new t;this.chassisBody.pointToWorldFrame(n,i),f.position.set(i.x,i.y,i.z);var u="undefined"!=typeof e.axis?e.axis.clone():new t(0,1,0);this.wheelAxes.push(u);var p=new l(this.chassisBody,f,{pivotA:n,axisA:u,pivotB:t.ZERO,axisB:u,collideConnected:!1});return this.constraints.push(p),this.wheelBodies.length-1},n.prototype.setSteeringValue=function(e,f){var n=this.wheelAxes[f],o=Math.cos(e),d=Math.sin(e),i=n.x,t=n.y;this.constraints[f].axisA.set(o*i-d*t,d*i+o*t,0)},n.prototype.setMotorSpeed=function(e,f){var n=this.constraints[f];n.enableMotor(),n.motorTargetVelocity=e},n.prototype.disableMotor=function(e){var f=this.constraints[e]; 26 | f.disableMotor()};var u=new t;n.prototype.setWheelForce=function(e,f){this.wheelForces[f]=e},n.prototype.applyWheelForce=function(e,f){var n=this.wheelAxes[f],o=this.wheelBodies[f],d=o.torque;n.scale(e,u),o.vectorToWorldFrame(u,u),d.vadd(u,d)},n.prototype.addToWorld=function(e){for(var f=this.constraints,n=this.wheelBodies.concat([this.chassisBody]),o=0;othis.particles.length&&this.neighbors.pop())};var d=new o;n.prototype.getNeighbors=function(e,f){for(var n=this.particles.length,o=e.id,i=this.smoothingRadius*this.smoothingRadius,t=d,l=0;l!==n;l++){var u=this.particles[l];u.position.vsub(e.position,t),o!==u.id&&t.norm2()=-.1)this.suspensionRelativeVelocity=0,this.clippedInvContactDotSuspension=10;else{var d=-1/n;this.suspensionRelativeVelocity=o*d,this.clippedInvContactDotSuspension=d}}else f.suspensionLength=this.suspensionRestLength,this.suspensionRelativeVelocity=0,f.directionWorld.scale(-1,f.hitNormalWorld),this.clippedInvContactDotSuspension=1}},{"../collision/RaycastResult":10,"../math/Transform":29,"../math/Vec3":30,"../utils/Utils":53}],37:[function(e,f){function n(e){o.call(this),this.type=o.types.BOX,this.halfExtents=e,this.convexPolyhedronRepresentation=null,this.updateConvexPolyhedronRepresentation(),this.updateBoundingSphereRadius()}f.exports=n;var o=e("./Shape"),d=e("../math/Vec3"),i=e("./ConvexPolyhedron");n.prototype=new o,n.prototype.constructor=n,n.prototype.updateConvexPolyhedronRepresentation=function(){var e=this.halfExtents.x,f=this.halfExtents.y,n=this.halfExtents.z,o=d,t=[new o(-e,-f,-n),new o(e,-f,-n),new o(e,f,-n),new o(-e,f,-n),new o(-e,-f,n),new o(e,-f,n),new o(e,f,n),new o(-e,f,n)],l=[[3,2,1,0],[4,5,6,7],[5,4,0,1],[2,3,7,6],[0,4,7,3],[1,2,6,5]],u=([new o(0,0,1),new o(0,1,0),new o(1,0,0)],new i(t,l));this.convexPolyhedronRepresentation=u,u.material=this.material},n.prototype.calculateLocalInertia=function(e,f){return f=f||new d,n.calculateInertia(this.halfExtents,e,f),f},n.calculateInertia=function(e,f,n){var o=e;n.x=1/12*f*(2*o.y*2*o.y+2*o.z*2*o.z),n.y=1/12*f*(2*o.x*2*o.x+2*o.z*2*o.z),n.z=1/12*f*(2*o.y*2*o.y+2*o.x*2*o.x)},n.prototype.getSideNormals=function(e,f){var n=e,o=this.halfExtents;if(n[0].set(o.x,0,0),n[1].set(0,o.y,0),n[2].set(0,0,o.z),n[3].set(-o.x,0,0),n[4].set(0,-o.y,0),n[5].set(0,0,-o.z),void 0!==f)for(var d=0;d!==n.length;d++)f.vmult(n[d],n[d]);return n},n.prototype.volume=function(){return 8*this.halfExtents.x*this.halfExtents.y*this.halfExtents.z},n.prototype.updateBoundingSphereRadius=function(){this.boundingSphereRadius=this.halfExtents.norm()};{var t=new d;new d}n.prototype.forEachWorldCorner=function(e,f,n){for(var o=this.halfExtents,d=[[o.x,o.y,o.z],[-o.x,o.y,o.z],[-o.x,-o.y,o.z],[-o.x,-o.y,-o.z],[o.x,-o.y,-o.z],[o.x,o.y,-o.z],[-o.x,o.y,-o.z],[o.x,-o.y,o.z]],i=0;it;t++){var i=l[t];f.vmult(i,i),e.vadd(i,i);var u=i.x,p=i.y,s=i.z;u>o.x&&(o.x=u),p>o.y&&(o.y=p),s>o.z&&(o.z=s),ua&&(a=w,c=r)}for(var b=[],m=n.faces[c],N=m.length,g=0;N>g;g++){var x=n.vertices[m[g]],j=new d;j.copy(x),i.vmult(j,j),o.vadd(j,j),b.push(j)}c>=0&&this.clipFaceAgainstHull(t,e,f,b,l,u,s)};var s=new d,y=new d,c=new d,a=new d,r=new d,w=new d;n.prototype.findSeparatingAxis=function(e,f,n,o,d,i,t,l){var u=s,p=y,b=c,m=a,N=r,g=w,x=Number.MAX_VALUE,j=this,v=0;if(j.uniqueAxes)for(var A=0;A!==j.uniqueAxes.length;A++){n.vmult(j.uniqueAxes[A],u);var C=j.testSepAxis(u,e,f,n,o,d);if(C===!1)return!1;x>C&&(x=C,i.copy(u))}else for(var O=t?t.length:j.faces.length,A=0;O>A;A++){var h=t?t[A]:A;u.copy(j.faceNormals[h]),n.vmult(u,u);var C=j.testSepAxis(u,e,f,n,o,d);if(C===!1)return!1;x>C&&(x=C,i.copy(u))}if(e.uniqueAxes)for(var A=0;A!==e.uniqueAxes.length;A++){d.vmult(e.uniqueAxes[A],p),v++;var C=j.testSepAxis(p,e,f,n,o,d);if(C===!1)return!1;x>C&&(x=C,i.copy(p))}else for(var k=l?l.length:e.faces.length,A=0;k>A;A++){var h=l?l[A]:A;p.copy(e.faceNormals[h]),d.vmult(p,p),v++;var C=j.testSepAxis(p,e,f,n,o,d);if(C===!1)return!1;x>C&&(x=C,i.copy(p))}for(var q=0;q!==j.uniqueEdges.length;q++){n.vmult(j.uniqueEdges[q],m);for(var z=0;z!==e.uniqueEdges.length;z++)if(d.vmult(e.uniqueEdges[z],N),m.cross(N,g),!g.almostZero()){g.normalize();var B=j.testSepAxis(g,e,f,n,o,d);if(B===!1)return!1;x>B&&(x=B,i.copy(g))}}return o.vsub(f,b),b.dot(i)>0&&i.negate(i),!0};var b=[],m=[];n.prototype.testSepAxis=function(e,f,o,d,i,t){var l=this;n.project(l,e,o,d,b),n.project(f,e,i,t,m);var u=b[0],p=b[1],s=m[0],y=m[1];if(y>u||p>s)return!1;var c=u-y,a=s-p,r=a>c?c:a;return r};var N=new d,g=new d;n.prototype.calculateLocalInertia=function(e,f){this.computeLocalAABB(N,g);var n=g.x-N.x,o=g.y-N.y,d=g.z-N.z;f.x=1/12*e*(2*o*2*o+2*d*2*d),f.y=1/12*e*(2*n*2*n+2*d*2*d),f.z=1/12*e*(2*o*2*o+2*n*2*n)},n.prototype.getPlaneConstantOfFace=function(e){var f=this.faces[e],n=this.faceNormals[e],o=this.vertices[f[0]],d=-n.dot(o);return d};var x=new d,j=new d,v=new d,A=new d,C=new d,O=new d,h=new d,k=new d;n.prototype.clipFaceAgainstHull=function(e,f,n,o,d,i,t){for(var l=x,u=j,p=v,s=A,y=C,c=O,a=h,r=k,w=this,b=[],m=o,N=b,g=-1,q=Number.MAX_VALUE,z=0;zB&&(q=B,g=z)}if(!(0>g)){var D=w.faces[g];D.connectedFaces=[];for(var E=0;EH;H++){var I=w.vertices[D[H]],J=w.vertices[D[(H+1)%G]];I.vsub(J,u),p.copy(u),n.vmult(p,p),f.vadd(p,p),s.copy(this.faceNormals[g]),n.vmult(s,s),f.vadd(s,s),p.cross(s,y),y.negate(y),c.copy(I),n.vmult(c,c),f.vadd(c,c);var K,L=(-c.dot(y),D.connectedFaces[H]);a.copy(this.faceNormals[L]);var M=this.getPlaneConstantOfFace(L);r.copy(a),n.vmult(r,r);var K=M-r.dot(f);for(this.clipFaceAgainstPlane(m,N,r,K);m.length;)m.shift();for(;N.length;)m.push(N.shift())}a.copy(this.faceNormals[g]);var M=this.getPlaneConstantOfFace(g);r.copy(a),n.vmult(r,r);for(var K=M-r.dot(f),E=0;E=P&&(console.log("clamped: depth="+P+" to minDist="+(d+"")),P=d),i>=P){var Q=m[E];if(0>=P){var R={point:Q,normal:r,depth:P};t.push(R)}}}}},n.prototype.clipFaceAgainstPlane=function(e,f,n,o){var i,t,l=e.length;if(2>l)return f;var u=e[e.length-1],p=e[0];i=n.dot(u)+o;for(var s=0;l>s;s++){if(p=e[s],t=n.dot(p)+o,0>i)if(0>t){var y=new d;y.copy(p),f.push(y)}else{var y=new d;u.lerp(p,i/(i-t),y),f.push(y)}else if(0>t){var y=new d;u.lerp(p,i/(i-t),y),f.push(y),f.push(p)}u=p,i=t}return f},n.prototype.computeWorldVertices=function(e,f){for(var n=this.vertices.length;this.worldVertices.lengthd;d++){var i=o[d];i.xf.x&&(f.x=i.x),i.yf.y&&(f.y=i.y),i.zf.z&&(f.z=i.z)}},n.prototype.computeWorldFaceNormals=function(e){for(var f=this.faceNormals.length;this.worldFaceNormals.lengthe&&(e=d)}this.boundingSphereRadius=Math.sqrt(e)};var q=new d;n.prototype.calculateWorldAABB=function(e,f,n,o){for(var d,i,t,l,u,p,s=this.vertices.length,y=this.vertices,c=0;s>c;c++){q.copy(y[c]),f.vmult(q,q),e.vadd(q,q);var a=q;a.xl||void 0===l)&&(l=a.x),a.yu||void 0===u)&&(u=a.y),a.zp||void 0===p)&&(p=a.z)}n.set(d,i,t),o.set(l,u,p)},n.prototype.volume=function(){return 4*Math.PI*this.boundingSphereRadius/3},n.prototype.getAveragePointLocal=function(e){e=e||new d;for(var f=this.vertices.length,n=this.vertices,o=0;f>o;o++)e.vadd(n[o],e);return e.mult(1/f,e),e},n.prototype.transformAllPoints=function(e,f){var n=this.vertices.length,o=this.vertices;if(f){for(var d=0;n>d;d++){var i=o[d];f.vmult(i,i)}for(var d=0;dd;d++){var i=o[d];i.vadd(e,i)}};var z=new d,B=new d,D=new d;n.prototype.pointIsInside=function(e){var f=this.vertices.length,n=this.vertices,o=this.faces,d=this.faceNormals,i=null,t=this.faces.length,l=z;this.getAveragePointLocal(l);for(var u=0;t>u;u++){var f=(this.faces[u].length,d[u]),p=n[o[u][0]],s=B;e.vsub(p,s);var y=f.dot(s),c=D;l.vsub(p,c);var a=f.dot(c);if(0>y&&a>0||y>0&&0>a)return!1}return i?1:-1};var E=(new d,new d),F=new d;n.project=function(e,f,n,o,d){var t=e.vertices.length,l=E,u=0,p=0,s=F,y=e.vertices;s.setZero(),i.vectorToLocalFrame(n,o,f,l),i.pointToLocalFrame(n,o,s,s);var c=s.dot(l);p=u=y[0].dot(l);for(var a=1;t>a;a++){var r=y[a].dot(l);r>u&&(u=r),p>r&&(p=r)}if(p-=c,u-=c,p>u){var w=p;p=u,u=w}d[0]=u,d[1]=p}},{"../math/Quaternion":28,"../math/Transform":29,"../math/Vec3":30,"./Shape":43}],39:[function(e,f){function n(e,f,n,t){var l=t,u=[],p=[],s=[],y=[],c=[],a=Math.cos,r=Math.sin;u.push(new d(f*a(0),f*r(0),.5*-n)),y.push(0),u.push(new d(e*a(0),e*r(0),.5*n)),c.push(1);for(var w=0;l>w;w++){var b=2*Math.PI/l*(w+1),m=2*Math.PI/l*(w+.5);l-1>w?(u.push(new d(f*a(b),f*r(b),.5*-n)),y.push(2*w+2),u.push(new d(e*a(b),e*r(b),.5*n)),c.push(2*w+3),s.push([2*w+2,2*w+3,2*w+1,2*w])):s.push([0,1,2*w+1,2*w]),(l%2===1||l/2>w)&&p.push(new d(a(m),r(m),0))}s.push(c),p.push(new d(0,0,1));for(var N=[],w=0;wd&&(f=d)}this.minValue=f},n.prototype.updateMaxValue=function(){for(var e=this.data,f=e[0][0],n=0;n!==e.length;n++)for(var o=0;o!==e[n].length;o++){var d=e[n][o];d>f&&(f=d)}this.maxValue=f},n.prototype.setHeightValueAtIndex=function(e,f,n){var o=this.data;o[e][f]=n,this.clearCachedConvexTrianglePillar(e,f,!1),e>0&&(this.clearCachedConvexTrianglePillar(e-1,f,!0),this.clearCachedConvexTrianglePillar(e-1,f,!1)),f>0&&(this.clearCachedConvexTrianglePillar(e,f-1,!0),this.clearCachedConvexTrianglePillar(e,f-1,!1)),f>0&&e>0&&this.clearCachedConvexTrianglePillar(e-1,f-1,!0)},n.prototype.getRectMinMax=function(e,f,n,o,d){d=d||[];for(var i=this.data,t=this.minValue,l=e;n>=l;l++)for(var u=f;o>=u;u++){var p=i[l][u];p>t&&(t=p)}d[0]=this.minValue,d[1]=t},n.prototype.getIndexOfPosition=function(e,f,n,o){var d=this.elementSize,i=this.data,t=Math.floor(e/d),l=Math.floor(f/d);return n[0]=t,n[1]=l,o&&(0>t&&(t=0),0>l&&(l=0),t>=i.length-1&&(t=i.length-1),l>=i[0].length-1&&(l=i[0].length-1)),0>t||0>l||t>=i.length-1||l>=i[0].length-1?!1:!0},n.prototype.getHeightAt=function(e,f,n){var o=[];this.getIndexOfPosition(e,f,o,n);var d=[];return this.getRectMinMax(o[0],o[1]+1,o[0],o[1]+1,d),(d[0]+d[1])/2},n.prototype.getCacheConvexTrianglePillarKey=function(e,f,n){return e+"_"+f+"_"+(n?1:0)},n.prototype.getCachedConvexTrianglePillar=function(e,f,n){return this._cachedPillars[this.getCacheConvexTrianglePillarKey(e,f,n)]},n.prototype.setCachedConvexTrianglePillar=function(e,f,n,o,d){this._cachedPillars[this.getCacheConvexTrianglePillarKey(e,f,n)]={convex:o,offset:d}},n.prototype.clearCachedConvexTrianglePillar=function(e,f,n){delete this._cachedPillars[this.getCacheConvexTrianglePillarKey(e,f,n)]},n.prototype.getConvexTrianglePillar=function(e,f,n){var o=this.pillarConvex,t=this.pillarOffset;if(this.cacheEnabled){var l=this.getCachedConvexTrianglePillar(e,f,n);if(l)return this.pillarConvex=l.convex,void(this.pillarOffset=l.offset);o=new d,t=new i,this.pillarConvex=o,this.pillarOffset=t}var l=this.data,u=this.elementSize,p=o.faces;o.vertices.length=6;for(var s=0;6>s;s++)o.vertices[s]||(o.vertices[s]=new i);p.length=5;for(var s=0;5>s;s++)p[s]||(p[s]=[]);var y=o.vertices,c=(Math.min(l[e][f],l[e+1][f],l[e][f+1],l[e+1][f+1])-this.minValue)/2+this.minValue;n?(t.set((e+.75)*u,(f+.75)*u,c),y[0].set(.25*u,.25*u,l[e+1][f+1]-c),y[1].set(-.75*u,.25*u,l[e][f+1]-c),y[2].set(.25*u,-.75*u,l[e+1][f]-c),y[3].set(.25*u,.25*u,-c-1),y[4].set(-.75*u,.25*u,-c-1),y[5].set(.25*u,-.75*u,-c-1),p[0][0]=0,p[0][1]=1,p[0][2]=2,p[1][0]=5,p[1][1]=4,p[1][2]=3,p[2][0]=2,p[2][1]=5,p[2][2]=3,p[2][3]=0,p[3][0]=3,p[3][1]=4,p[3][2]=1,p[3][3]=0,p[4][0]=1,p[4][1]=4,p[4][2]=5,p[4][3]=2):(t.set((e+.25)*u,(f+.25)*u,c),y[0].set(-.25*u,-.25*u,l[e][f]-c),y[1].set(.75*u,-.25*u,l[e+1][f]-c),y[2].set(-.25*u,.75*u,l[e][f+1]-c),y[3].set(-.25*u,-.25*u,-c-1),y[4].set(.75*u,-.25*u,-c-1),y[5].set(-.25*u,.75*u,-c-1),p[0][0]=0,p[0][1]=1,p[0][2]=2,p[1][0]=5,p[1][1]=4,p[1][2]=3,p[2][0]=0,p[2][1]=2,p[2][2]=5,p[2][3]=3,p[3][0]=1,p[3][1]=0,p[3][2]=3,p[3][3]=4,p[4][0]=4,p[4][1]=5,p[4][2]=2,p[4][3]=1),o.computeNormals(),o.computeEdges(),o.updateBoundingSphereRadius(),this.setCachedConvexTrianglePillar(e,f,n,o,t)},n.prototype.calculateLocalInertia=function(e,f){return f=f||new i,f.set(0,0,0),f},n.prototype.volume=function(){return Number.MAX_VALUE},n.prototype.calculateWorldAABB=function(e,f,n,o){n.set(-Number.MAX_VALUE,-Number.MAX_VALUE,-Number.MAX_VALUE),o.set(Number.MAX_VALUE,Number.MAX_VALUE,Number.MAX_VALUE)},n.prototype.updateBoundingSphereRadius=function(){var e=this.data,f=this.elementSize;this.boundingSphereRadius=new i(e.length*f,e[0].length*f,Math.max(Math.abs(this.maxValue),Math.abs(this.minValue))).norm()}},{"../math/Vec3":30,"../utils/Utils":53,"./ConvexPolyhedron":38,"./Shape":43}],41:[function(e,f){function n(){o.call(this),this.type=o.types.PARTICLE}f.exports=n;var o=e("./Shape"),d=e("../math/Vec3");n.prototype=new o,n.prototype.constructor=n,n.prototype.calculateLocalInertia=function(e,f){return f=f||new d,f.set(0,0,0),f},n.prototype.volume=function(){return 0},n.prototype.updateBoundingSphereRadius=function(){this.boundingSphereRadius=0},n.prototype.calculateWorldAABB=function(e,f,n,o){n.copy(e),o.copy(e)}},{"../math/Vec3":30,"./Shape":43}],42:[function(e,f){function n(){o.call(this),this.type=o.types.PLANE,this.worldNormal=new d,this.worldNormalNeedsUpdate=!0,this.boundingSphereRadius=Number.MAX_VALUE}f.exports=n;var o=e("./Shape"),d=e("../math/Vec3");n.prototype=new o,n.prototype.constructor=n,n.prototype.computeWorldNormal=function(e){var f=this.worldNormal;f.set(0,0,1),e.vmult(f,f),this.worldNormalNeedsUpdate=!1},n.prototype.calculateLocalInertia=function(e,f){return f=f||new d},n.prototype.volume=function(){return Number.MAX_VALUE};var i=new d;n.prototype.calculateWorldAABB=function(e,f,n,o){i.set(0,0,1),f.vmult(i,i);var d=Number.MAX_VALUE;n.set(-d,-d,-d),o.set(d,d,d),1===i.x&&(o.x=e.x),1===i.y&&(o.y=e.y),1===i.z&&(o.z=e.z),-1===i.x&&(n.x=e.x),-1===i.y&&(n.y=e.y),-1===i.z&&(n.z=e.z)},n.prototype.updateBoundingSphereRadius=function(){this.boundingSphereRadius=Number.MAX_VALUE}},{"../math/Vec3":30,"./Shape":43}],43:[function(e,f){function n(){this.id=n.idCounter++,this.type=0,this.boundingSphereRadius=0,this.collisionResponse=!0,this.material=null}f.exports=n;{var n=e("./Shape");e("../math/Vec3"),e("../math/Quaternion"),e("../material/Material")}n.prototype.constructor=n,n.prototype.updateBoundingSphereRadius=function(){throw"computeBoundingSphereRadius() not implemented for shape type "+this.type},n.prototype.volume=function(){throw"volume() not implemented for shape type "+this.type},n.prototype.calculateLocalInertia=function(){throw"calculateLocalInertia() not implemented for shape type "+this.type},n.idCounter=0,n.types={SPHERE:1,PLANE:2,BOX:4,COMPOUND:8,CONVEXPOLYHEDRON:16,HEIGHTFIELD:32,PARTICLE:64,CYLINDER:128,TRIMESH:256}},{"../material/Material":25,"../math/Quaternion":28,"../math/Vec3":30,"./Shape":43}],44:[function(e,f){function n(e){if(o.call(this),this.radius=void 0!==e?Number(e):1,this.type=o.types.SPHERE,this.radius<0)throw new Error("The sphere radius cannot be negative.");this.updateBoundingSphereRadius()}f.exports=n;var o=e("./Shape"),d=e("../math/Vec3");n.prototype=new o,n.prototype.constructor=n,n.prototype.calculateLocalInertia=function(e,f){f=f||new d;var n=2*e*this.radius*this.radius/5;return f.x=n,f.y=n,f.z=n,f},n.prototype.volume=function(){return 4*Math.PI*this.radius/3},n.prototype.updateBoundingSphereRadius=function(){this.boundingSphereRadius=this.radius},n.prototype.calculateWorldAABB=function(e,f,n,o){for(var d=this.radius,i=["x","y","z"],t=0;td?d+"_"+i:i+"_"+d;e[f]=!0},n=0;nn.x&&(n.x=d.x),d.yn.y&&(n.y=d.y),d.zn.z&&(n.z=d.z)},n.prototype.updateAABB=function(){this.computeLocalAABB(this.aabb)},n.prototype.updateBoundingSphereRadius=function(){for(var e=0,f=this.vertices,n=new d,o=0,i=f.length/3;o!==i;o++){this.getVertex(o,n);var t=n.norm2();t>e&&(e=t)}this.boundingSphereRadius=Math.sqrt(e)};var g=(new d,new i),x=new t;n.prototype.calculateWorldAABB=function(e,f,n,o){var d=g,i=x;d.position=e,d.quaternion=f,this.aabb.toWorldFrame(d,i),n.copy(i.lowerBound),o.copy(i.upperBound)},n.prototype.volume=function(){return 4*Math.PI*this.boundingSphereRadius/3},n.createTorus=function(e,f,o,d,i){e=e||1,f=f||.5,o=o||8,d=d||6,i=i||2*Math.PI;for(var t=[],l=[],u=0;o>=u;u++)for(var p=0;d>=p;p++){var s=p/d*i,y=u/o*Math.PI*2,c=(e+f*Math.cos(y))*Math.cos(s),a=(e+f*Math.cos(y))*Math.sin(s),r=f*Math.sin(y);t.push(c,a,r)}for(var u=1;o>=u;u++)for(var p=1;d>=p;p++){var w=(d+1)*u+p-1,b=(d+1)*(u-1)+p-1,m=(d+1)*(u-1)+p,N=(d+1)*u+p;l.push(w,b,N),l.push(b,m,N)}return new n(t,l)}},{"../collision/AABB":3,"../math/Quaternion":28,"../math/Transform":29,"../math/Vec3":30,"../utils/Octree":50,"./Shape":43}],46:[function(e,f){function n(){o.call(this),this.iterations=10,this.tolerance=1e-7}f.exports=n;var o=(e("../math/Vec3"),e("../math/Quaternion"),e("./Solver"));n.prototype=new o;var d=[],i=[],t=[];n.prototype.solve=function(e,f){var n,o,l,u,p,s,y=0,c=this.iterations,a=this.tolerance*this.tolerance,r=this.equations,w=r.length,b=f.bodies,m=b.length,N=e;if(0!==w)for(var g=0;g!==m;g++)b[g].updateSolveMassProperties();var x=i,j=t,v=d; 27 | x.length=w,j.length=w,v.length=w;for(var g=0;g!==w;g++){var A=r[g];v[g]=0,j[g]=A.computeB(N),x[g]=1/A.computeC()}if(0!==w){for(var g=0;g!==m;g++){var C=b[g],O=C.vlambda,h=C.wlambda;O.set(0,0,0),h&&h.set(0,0,0)}for(y=0;y!==c;y++){u=0;for(var k=0;k!==w;k++){var A=r[k];n=j[k],o=x[k],s=v[k],p=A.computeGWlambda(),l=o*(n-p-A.eps*s),s+lA.maxForce&&(l=A.maxForce-s),v[k]+=l,u+=l>0?l:-l,A.addToWlambda(l)}if(a>u*u)break}for(var g=0;g!==m;g++){var C=b[g],q=C.velocity,z=C.angularVelocity;q.vadd(C.vlambda,q),z&&z.vadd(C.wlambda,z)}}return y}},{"../math/Quaternion":28,"../math/Vec3":30,"./Solver":47}],47:[function(e,f){function n(){this.equations=[]}f.exports=n,n.prototype.solve=function(){return 0},n.prototype.addEquation=function(e){e.enabled&&this.equations.push(e)},n.prototype.removeEquation=function(e){var f=this.equations,n=f.indexOf(e);-1!==n&&f.splice(n,1)},n.prototype.removeAllEquations=function(){this.equations.length=0}},{}],48:[function(e,f){function n(e){for(l.call(this),this.iterations=10,this.tolerance=1e-7,this.subsolver=e,this.nodes=[],this.nodePool=[];this.nodePool.length<128;)this.nodePool.push(this.createNode())}function o(e){for(var f=e.length,n=0;n!==f;n++){var o=e[n];if(!(o.visited||o.body.type&c))return o}return!1}function d(e,f,n,d){for(a.push(e),e.visited=!0,f(e,n,d);a.length;)for(var i,t=a.pop();i=o(t.children);)i.visited=!0,f(i,n,d),a.push(i)}function i(e,f,n){f.push(e.body);for(var o=e.eqs.length,d=0;d!==o;d++){var i=e.eqs[d];-1===n.indexOf(i)&&n.push(i)}}function t(e,f){return f.id-e.id}f.exports=n;var l=(e("../math/Vec3"),e("../math/Quaternion"),e("./Solver")),u=e("../objects/Body");n.prototype=new l;var p=[],s=[],y={bodies:[]},c=u.STATIC,a=[];n.prototype.createNode=function(){return{body:null,children:[],eqs:[],visited:!1}},n.prototype.solve=function(e,f){for(var n=p,l=this.nodePool,u=f.bodies,c=this.equations,a=c.length,r=u.length,w=this.subsolver;l.lengthb;b++)n[b]=l[b];for(var b=0;b!==r;b++){var m=n[b];m.body=u[b],m.children.length=0,m.eqs.length=0,m.visited=!1}for(var N=0;N!==a;N++){var g=c[N],b=u.indexOf(g.bi),x=u.indexOf(g.bj),j=n[b],v=n[x];j.children.push(v),j.eqs.push(g),v.children.push(j),v.eqs.push(g)}var A,C=0,O=s;w.tolerance=this.tolerance,w.iterations=this.iterations;for(var h=y;A=o(n);){O.length=0,h.bodies.length=0,d(A,i,h.bodies,O);var k=O.length;O=O.sort(t);for(var b=0;b!==k;b++)w.addEquation(O[b]);{w.solve(e,h)}w.removeAllEquations(),C++}return C}},{"../math/Quaternion":28,"../math/Vec3":30,"../objects/Body":31,"./Solver":47}],49:[function(e,f){var n=function(){};f.exports=n,n.prototype={constructor:n,addEventListener:function(e,f){void 0===this._listeners&&(this._listeners={});var n=this._listeners;return void 0===n[e]&&(n[e]=[]),-1===n[e].indexOf(f)&&n[e].push(f),this},hasEventListener:function(e,f){if(void 0===this._listeners)return!1;var n=this._listeners;return void 0!==n[e]&&-1!==n[e].indexOf(f)?!0:!1},removeEventListener:function(e,f){if(void 0===this._listeners)return this;var n=this._listeners;if(void 0===n[e])return this;var o=n[e].indexOf(f);return-1!==o&&n[e].splice(o,1),this},dispatchEvent:function(e){if(void 0===this._listeners)return this;var f=this._listeners,n=f[e.type];if(void 0!==n){e.target=this;for(var o=0,d=n.length;d>o;o++)n[o].call(this,e)}return this}}},{}],50:[function(e,f){function n(e){e=e||{},this.root=e.root||null,this.aabb=e.aabb?e.aabb.clone():new d,this.data=[],this.children=[]}function o(e,f){f=f||{},f.root=null,f.aabb=e,n.call(this,f),this.maxDepth="undefined"!=typeof f.maxDepth?f.maxDepth:8}var d=e("../collision/AABB"),i=e("../math/Vec3");f.exports=o,o.prototype=new n,n.prototype.reset=function(){this.children.length=this.data.length=0},n.prototype.insert=function(e,f,n){var o=this.data;if(n=n||0,!this.aabb.contains(e))return!1;var d=this.children;if(n<(this.maxDepth||this.root.maxDepth)){var i=!1;d.length||(this.subdivide(),i=!0);for(var t=0;8!==t;t++)if(d[t].insert(e,f,n+1))return!0;i&&(d.length=0)}return o.push(f),!0};var t=new i;n.prototype.subdivide=function(){var e=this.aabb,f=e.lowerBound,o=e.upperBound,l=this.children;l.push(new n({aabb:new d({lowerBound:new i(0,0,0)})}),new n({aabb:new d({lowerBound:new i(1,0,0)})}),new n({aabb:new d({lowerBound:new i(1,1,0)})}),new n({aabb:new d({lowerBound:new i(1,1,1)})}),new n({aabb:new d({lowerBound:new i(0,1,1)})}),new n({aabb:new d({lowerBound:new i(0,0,1)})}),new n({aabb:new d({lowerBound:new i(1,0,1)})}),new n({aabb:new d({lowerBound:new i(0,1,0)})})),o.vsub(f,t),t.scale(.5,t);for(var u=this.root||this,p=0;8!==p;p++){var s=l[p];s.root=u;var y=s.aabb.lowerBound;y.x*=t.x,y.y*=t.y,y.z*=t.z,y.vadd(f,y),y.vadd(t,s.aabb.upperBound)}},n.prototype.aabbQuery=function(e,f){for(var n=(this.data,this.children,[this]);n.length;){var o=n.pop();o.aabb.overlaps(e)&&Array.prototype.push.apply(f,o.data),Array.prototype.push.apply(n,o.children)}return f};var l=new d;n.prototype.rayQuery=function(e,f,n){return e.getAABB(l),l.toLocalFrame(f,l),this.aabbQuery(l,n),n},n.prototype.removeEmptyNodes=function(){for(var e=[this];e.length;){for(var f=e.pop(),n=f.children.length-1;n>=0;n--)f.children[n].data.length||f.children.splice(n,1);Array.prototype.push.apply(e,f.children)}}},{"../collision/AABB":3,"../math/Vec3":30}],51:[function(e,f){function n(){this.objects=[],this.type=Object}f.exports=n,n.prototype.release=function(){for(var e=arguments.length,f=0;f!==e;f++)this.objects.push(arguments[f])},n.prototype.get=function(){return 0===this.objects.length?this.constructObject():this.objects.pop()},n.prototype.constructObject=function(){throw new Error("constructObject() not implemented in this Pool subclass yet!")}},{}],52:[function(e,f){function n(){this.data={keys:[]}}f.exports=n,n.prototype.get=function(e,f){if(e>f){var n=f;f=e,e=n}return this.data[e+"-"+f]},n.prototype.set=function(e,f,n){if(e>f){var o=f;f=e,e=o}var d=e+"-"+f;this.get(e,f)||this.data.keys.push(d),this.data[d]=n},n.prototype.reset=function(){for(var e=this.data,f=e.keys;f.length>0;){var n=f.pop();delete e[n]}}},{}],53:[function(e,f){function n(){}f.exports=n,n.defaults=function(e,f){e=e||{};for(var n in f)n in e||(e[n]=f[n]);return e}},{}],54:[function(e,f){function n(){d.call(this),this.type=o}f.exports=n;var o=e("../math/Vec3"),d=e("./Pool");n.prototype=new d,n.prototype.constructObject=function(){return new o}},{"../math/Vec3":30,"./Pool":51}],55:[function(e,f){function n(e){this.contactPointPool=[],this.frictionEquationPool=[],this.result=[],this.frictionResult=[],this.v3pool=new s,this.world=e,this.currentContactMaterial=null,this.enableFrictionReduction=!1}function o(e,f,n){for(var o=null,d=e.length,i=0;i!==d;i++){var t=e[i],l=M;e[(i+1)%d].vsub(t,l);var u=P;l.cross(f,u);var p=Q;n.vsub(t,p);var s=u.dot(p);if(!(null===o||s>0&&o===!0||0>=s&&o===!1))return!1;null===o&&(o=s>0)}return!0}f.exports=n;var d=e("../collision/AABB"),i=e("../shapes/Shape"),t=e("../collision/Ray"),l=e("../math/Vec3"),u=e("../math/Transform"),p=(e("../shapes/ConvexPolyhedron"),e("../math/Quaternion")),s=(e("../solver/Solver"),e("../utils/Vec3Pool")),y=e("../equations/ContactEquation"),c=e("../equations/FrictionEquation");n.prototype.createContactEquation=function(e,f,n,o,d,i){var t;this.contactPointPool.length?(t=this.contactPointPool.pop(),t.bi=e,t.bj=f):t=new y(e,f),t.enabled=e.collisionResponse&&f.collisionResponse&&n.collisionResponse&&o.collisionResponse;var l=this.currentContactMaterial;t.restitution=l.restitution,t.setSpookParams(l.contactEquationStiffness,l.contactEquationRelaxation,this.world.dt);var u=n.material||e.material,p=o.material||f.material;return u&&p&&u.restitution>=0&&p.restitution>=0&&(t.restitution=u.restitution*p.restitution),t.si=d||n,t.sj=i||o,t},n.prototype.createFrictionEquationsFromContact=function(e,f){var n=e.bi,o=e.bj,d=e.si,i=e.sj,t=this.world,l=this.currentContactMaterial,u=l.friction,p=d.material||n.material,s=i.material||o.material;if(p&&s&&p.friction>=0&&s.friction>=0&&(u=p.friction*s.friction),u>0){var y=u*t.gravity.length(),a=n.invMass+o.invMass;a>0&&(a=1/a);var r=this.frictionEquationPool,w=r.length?r.pop():new c(n,o,y*a),b=r.length?r.pop():new c(n,o,y*a);return w.bi=b.bi=n,w.bj=b.bj=o,w.minForce=b.minForce=-y*a,w.maxForce=b.maxForce=y*a,w.ri.copy(e.ri),w.rj.copy(e.rj),b.ri.copy(e.ri),b.rj.copy(e.rj),e.ni.tangents(w.t,b.t),w.setSpookParams(l.frictionEquationStiffness,l.frictionEquationRelaxation,t.dt),b.setSpookParams(l.frictionEquationStiffness,l.frictionEquationRelaxation,t.dt),w.enabled=b.enabled=e.enabled,f.push(w,b),!0}return!1};var a=new l,r=new l,w=new l;n.prototype.createFrictionFromAverage=function(e){var f=this.result[this.result.length-1];if(this.createFrictionEquationsFromContact(f,this.frictionResult)&&1!==e){var n=this.frictionResult[this.frictionResult.length-2],o=this.frictionResult[this.frictionResult.length-1];a.setZero(),r.setZero(),w.setZero();for(var d=f.bi,i=(f.bj,0);i!==e;i++)f=this.result[this.result.length-1-i],f.bodyA!==d?(a.vadd(f.ni,a),r.vadd(f.ri,r),w.vadd(f.rj,w)):(a.vsub(f.ni,a),r.vadd(f.rj,r),w.vadd(f.ri,w));var t=1/e;r.scale(t,n.ri),w.scale(t,n.rj),o.ri.copy(n.ri),o.rj.copy(n.rj),a.normalize(),a.tangents(n.t,o.t)}};var b=new l,m=new l,N=new p,g=new p;n.prototype.getContacts=function(e,f,n,o,d,i,t){this.contactPointPool=d,this.frictionEquationPool=t,this.result=o,this.frictionResult=i;for(var l=N,u=g,p=b,s=m,y=0,c=e.length;y!==c;y++){var a=e[y],r=f[y],w=null;a.material&&r.material&&(w=n.getContactMaterial(a.material,r.material)||null);for(var x=0;xj.boundingSphereRadius+A.boundingSphereRadius)){var C=null;j.material&&A.material&&(C=n.getContactMaterial(j.material,A.material)||null),this.currentContactMaterial=C||w||n.defaultContactMaterial;var O=this[j.type|A.type];O&&(j.type=w){var b=this.createContactEquation(t,p,e,f);b.ni.copy(y);var m=v;y.scale(r.dot(y),m),s.vsub(m,m),b.ri.copy(m),b.ri.vsub(t.position,b.ri),b.rj.copy(s),b.rj.vsub(p.position,b.rj),this.result.push(b),this.createFrictionEquationsFromContact(b,this.frictionResult)}}};var A=new l,C=new l,O=(new l,new l),h=new l,k=new l,q=new l,z=new l,B=new l,D=new l,E=new l,F=new l,G=new l,H=new l,I=new d,J=[];n.prototype[i.types.SPHERE|i.types.TRIMESH]=n.prototype.sphereTrimesh=function(e,f,n,o,d,i,l,p){var s=k,y=q,c=z,a=B,r=D,w=E,b=I,m=h,N=C,g=J;u.pointToLocalFrame(o,i,n,r);var x=e.radius;b.lowerBound.set(r.x-x,r.y-x,r.z-x),b.upperBound.set(r.x+x,r.y+x,r.z+x),f.getTrianglesInAABB(b,g);for(var j=O,v=e.radius*e.radius,K=0;KL;L++)if(f.getVertex(f.indices[3*g[K]+L],j),j.vsub(r,N),N.norm2()<=v){m.copy(j),u.pointToWorldFrame(o,i,m,j),j.vsub(n,N);var M=this.createContactEquation(l,p,e,f);M.ni.copy(N),M.ni.normalize(),M.ri.copy(M.ni),M.ri.scale(e.radius,M.ri),M.ri.vadd(n,M.ri),M.ri.vsub(l.position,M.ri),M.rj.copy(j),M.rj.vsub(p.position,M.rj),this.result.push(M),this.createFrictionEquationsFromContact(M,this.frictionResult)}for(var K=0;KL;L++){f.getVertex(f.indices[3*g[K]+L],s),f.getVertex(f.indices[3*g[K]+(L+1)%3],y),y.vsub(s,c),r.vsub(y,w);var P=w.dot(c);r.vsub(s,w);var Q=w.dot(c);if(Q>0&&0>P){r.vsub(s,w),a.copy(c),a.normalize(),Q=w.dot(a),a.scale(Q,w),w.vadd(s,w);var R=w.distanceTo(r);if(RC&&C>0){var O=T,h=U;O.copy(p[(x+1)%3]),h.copy(p[(x+2)%3]);var k=O.norm(),q=h.norm();O.normalize(),h.normalize();var z=R.dot(O),B=R.dot(h);if(k>z&&z>-k&&q>B&&B>-q){var D=Math.abs(C-A-s);(null===g||g>D)&&(g=D,m=z,N=B,w=A,c.copy(v),a.copy(O),r.copy(h),b++)}}}if(b){y=!0;var E=this.createContactEquation(t,l,e,f);c.mult(-s,E.ri),E.ni.copy(c),E.ni.negate(E.ni),c.mult(w,c),a.mult(m,a),c.vadd(a,c),r.mult(N,r),c.vadd(r,E.rj),E.ri.vadd(n,E.ri),E.ri.vsub(t.position,E.ri),E.rj.vadd(o,E.rj),E.rj.vsub(l.position,E.rj),this.result.push(E),this.createFrictionEquationsFromContact(E,this.frictionResult)}for(var F=u.get(),G=W,H=0;2!==H&&!y;H++)for(var I=0;2!==I&&!y;I++)for(var J=0;2!==J&&!y;J++)if(F.set(0,0,0),H?F.vadd(p[0],F):F.vsub(p[0],F),I?F.vadd(p[1],F):F.vsub(p[1],F),J?F.vadd(p[2],F):F.vsub(p[2],F),o.vadd(F,G),G.vsub(n,G),G.norm2()_){y=!0;var ef=this.createContactEquation(t,l,e,f);L.vadd(M,ef.rj),ef.rj.copy(ef.rj),D.negate(ef.ni),ef.ni.normalize(),ef.ri.copy(ef.rj),ef.ri.vadd(o,ef.ri),ef.ri.vsub(n,ef.ri),ef.ri.normalize(),ef.ri.mult(s,ef.ri),ef.ri.vadd(n,ef.ri),ef.ri.vsub(t.position,ef.ri),ef.rj.vadd(o,ef.rj),ef.rj.vsub(l.position,ef.rj),this.result.push(ef),this.createFrictionEquationsFromContact(ef,this.frictionResult)}}u.release(K,L,E,M,D)};var $=new l,_=new l,ef=new l,ff=new l,nf=new l,of=new l,df=new l,tf=new l,lf=new l,uf=new l;n.prototype[i.types.SPHERE|i.types.CONVEXPOLYHEDRON]=n.prototype.sphereConvex=function(e,f,n,d,i,t,l,u){var p=this.v3pool;n.vsub(d,$);for(var s=f.faceNormals,y=f.faces,c=f.vertices,a=e.radius,r=0;r!==c.length;r++){var w=c[r],b=nf;t.vmult(w,b),d.vadd(b,b);var m=ff;if(b.vsub(n,m),m.norm2()k&&q.dot(A)>0){for(var z=[],B=0,D=v.length;B!==D;B++){var E=p.get();t.vmult(c[v[B]],E),d.vadd(E,E),z.push(E)}if(o(z,A,n)){g=!0;var N=this.createContactEquation(l,u,e,f);A.mult(-a,N.ri),A.negate(N.ni);var F=p.get();A.mult(-k,F);var G=p.get();A.mult(-a,G),n.vsub(d,N.rj),N.rj.vadd(G,N.rj),N.rj.vadd(F,N.rj),N.rj.vadd(d,N.rj),N.rj.vsub(u.position,N.rj),N.ri.vadd(n,N.ri),N.ri.vsub(l.position,N.ri),p.release(F),p.release(G),this.result.push(N),this.createFrictionEquationsFromContact(N,this.frictionResult);for(var B=0,H=z.length;B!==H;B++)p.release(z[B]);return}for(var B=0;B!==v.length;B++){var I=p.get(),J=p.get();t.vmult(c[v[(B+1)%v.length]],I),t.vmult(c[v[(B+2)%v.length]],J),d.vadd(I,I),d.vadd(J,J);var K=_;J.vsub(I,K);var L=ef;K.unit(L);var M=p.get(),P=p.get();n.vsub(I,P);var Q=P.dot(L);L.mult(Q,M),M.vadd(I,M);var R=p.get();if(M.vsub(n,R),Q>0&&Q*Q=a){var r=this.createContactEquation(t,l,e,f),w=cf;p.mult(p.dot(y),w),u.vsub(w,w),w.vsub(n,r.ri),r.ni.copy(p),u.vsub(o,r.rj),r.ri.vadd(n,r.ri),r.ri.vsub(t.position,r.ri),r.rj.vadd(o,r.rj),r.rj.vsub(l.position,r.rj),this.result.push(r),s++,this.enableFrictionReduction||this.createFrictionEquationsFromContact(r,this.frictionResult)}}this.enableFrictionReduction&&s&&this.createFrictionFromAverage(s)};var af=new l,rf=new l;n.prototype[i.types.CONVEXPOLYHEDRON]=n.prototype.convexConvex=function(e,f,n,o,d,i,t,l,u,p,s,y){var c=af;if(!(n.distanceTo(o)>e.boundingSphereRadius+f.boundingSphereRadius)&&e.findSeparatingAxis(f,n,d,o,i,c,s,y)){var a=[],r=rf;e.clipAgainstHull(n,d,f,o,i,c,-100,100,a);for(var w=0,b=0;b!==a.length;b++){var m=this.createContactEquation(t,l,e,f,u,p),N=m.ri,g=m.rj;c.negate(m.ni),a[b].normal.negate(r),r.mult(a[b].depth,r),a[b].point.vadd(r,N),g.copy(a[b].point),N.vsub(n,N),g.vsub(o,g),N.vadd(n,N),N.vsub(t.position,N),g.vadd(o,g),g.vsub(l.position,g),this.result.push(m),w++,this.enableFrictionReduction||this.createFrictionEquationsFromContact(m,this.frictionResult)}this.enableFrictionReduction&&w&&this.createFrictionFromAverage(w)}};var wf=new l,bf=new l,mf=new l;n.prototype[i.types.PLANE|i.types.PARTICLE]=n.prototype.planeParticle=function(e,f,n,o,d,i,t,l){var u=wf;u.set(0,0,1),t.quaternion.vmult(u,u);var p=bf;o.vsub(t.position,p);var s=u.dot(p);if(0>=s){var y=this.createContactEquation(l,t,f,e);y.ni.copy(u),y.ni.negate(y.ni),y.ri.set(0,0,0);var c=mf;u.mult(u.dot(o),c),o.vsub(c,c),y.rj.copy(c),this.result.push(y),this.createFrictionEquationsFromContact(y,this.frictionResult)}};var Nf=new l;n.prototype[i.types.PARTICLE|i.types.SPHERE]=n.prototype.sphereParticle=function(e,f,n,o,d,i,t,l){var u=Nf;u.set(0,0,1),o.vsub(n,u);var p=u.norm2();if(p<=e.radius*e.radius){var s=this.createContactEquation(l,t,f,e);u.normalize(),s.rj.copy(u),s.rj.mult(e.radius,s.rj),s.ni.copy(u),s.ni.negate(s.ni),s.ri.set(0,0,0),this.result.push(s),this.createFrictionEquationsFromContact(s,this.frictionResult)}};var gf=new p,xf=new l,jf=(new l,new l),vf=new l,Af=new l;n.prototype[i.types.PARTICLE|i.types.CONVEXPOLYHEDRON]=n.prototype.convexParticle=function(e,f,n,o,d,i,t,l){var u=-1,p=jf,s=Af,y=null,c=0,a=xf;if(a.copy(o),a.vsub(n,a),d.conjugate(gf),gf.vmult(a,a),e.pointIsInside(a)){e.worldVerticesNeedsUpdate&&e.computeWorldVertices(n,d),e.worldFaceNormalsNeedsUpdate&&e.computeWorldFaceNormals(d);for(var r=0,w=e.faces.length;r!==w;r++){var b=[e.worldVertices[e.faces[r][0]]],m=e.worldFaceNormals[r];o.vsub(b[0],vf);var N=-m.dot(vf);(null===y||Math.abs(N)b||0>N||w>p.length||m>p[0].length)){0>w&&(w=0),0>b&&(b=0),0>m&&(m=0),0>N&&(N=0),w>=p.length&&(w=p.length-1),b>=p.length&&(b=p.length-1),N>=p[0].length&&(N=p[0].length-1),m>=p[0].length&&(m=p[0].length-1);var g=[];f.getRectMinMax(w,m,b,N,g);var x=g[0],j=g[1];if(!(r.z-y>j||r.z+yv;v++)for(var A=m;N>A;A++)f.getConvexTrianglePillar(v,A,!1),u.pointToWorldFrame(o,i,f.pillarOffset,c),n.distanceTo(c)w||0>m||r>p.length||m>p[0].length)){0>r&&(r=0),0>w&&(w=0),0>b&&(b=0),0>m&&(m=0),r>=p.length&&(r=p.length-1),w>=p.length&&(w=p.length-1),m>=p[0].length&&(m=p[0].length-1),b>=p[0].length&&(b=p[0].length-1);var N=[];f.getRectMinMax(r,b,w,m,N);var g=N[0],x=N[1];if(!(a.z-s>x||a.z+sv;v++)for(var A=b;m>A;A++){var C=j.length;f.getConvexTrianglePillar(v,A,!1),u.pointToWorldFrame(o,i,f.pillarOffset,c),n.distanceTo(c)2)return}}}},{"../collision/AABB":3,"../collision/Ray":9,"../equations/ContactEquation":19,"../equations/FrictionEquation":21,"../math/Quaternion":28,"../math/Transform":29,"../math/Vec3":30,"../shapes/ConvexPolyhedron":38,"../shapes/Shape":43,"../solver/Solver":47,"../utils/Vec3Pool":54}],56:[function(e,f){function n(){u.apply(this),this.dt=-1,this.allowSleep=!1,this.contacts=[],this.frictionEquations=[],this.quatNormalizeSkip=0,this.quatNormalizeFast=!1,this.time=0,this.stepnumber=0,this.default_dt=1/60,this.nextId=0,this.gravity=new d,this.broadphase=new m,this.bodies=[],this.solver=new t,this.constraints=[],this.narrowphase=new l(this),this.collisionMatrix=new p,this.collisionMatrixPrevious=new p,this.materials=[],this.contactmaterials=[],this.contactMaterialTable=new a,this.defaultMaterial=new s("default"),this.defaultContactMaterial=new y(this.defaultMaterial,this.defaultMaterial,{friction:.3,restitution:0}),this.doProfiling=!1,this.profile={solve:0,makeContactConstraints:0,broadphase:0,integrate:0,narrowphase:0},this.subsystems=[],this.addBodyEvent={type:"addBody",body:null},this.removeBodyEvent={type:"removeBody",body:null}}f.exports=n;var o=e("../shapes/Shape"),d=e("../math/Vec3"),i=e("../math/Quaternion"),t=e("../solver/GSSolver"),l=(e("../utils/Vec3Pool"),e("../equations/ContactEquation"),e("../equations/FrictionEquation"),e("./Narrowphase")),u=e("../utils/EventTarget"),p=e("../collision/ArrayCollisionMatrix"),s=e("../material/Material"),y=e("../material/ContactMaterial"),c=e("../objects/Body"),a=e("../utils/TupleDictionary"),r=e("../collision/RaycastResult"),w=e("../collision/AABB"),b=e("../collision/Ray"),m=e("../collision/NaiveBroadphase");n.prototype=new u;var N=(new w,new b);if(n.prototype.getContactMaterial=function(e,f){return this.contactMaterialTable.get(e.id,f.id)},n.prototype.numObjects=function(){return this.bodies.length},n.prototype.collisionMatrixTick=function(){var e=this.collisionMatrixPrevious;this.collisionMatrixPrevious=this.collisionMatrix,this.collisionMatrix=e,this.collisionMatrix.reset()},n.prototype.add=n.prototype.addBody=function(e){-1===this.bodies.indexOf(e)&&(e.index=this.bodies.length,this.bodies.push(e),e.world=this,e.initPosition.copy(e.position),e.initVelocity.copy(e.velocity),e.timeLastSleepy=this.time,e instanceof c&&(e.initAngularVelocity.copy(e.angularVelocity),e.initQuaternion.copy(e.quaternion)),this.collisionMatrix.setNumObjects(this.bodies.length),this.addBodyEvent.body=e,this.dispatchEvent(this.addBodyEvent))},n.prototype.addConstraint=function(e){this.constraints.push(e)},n.prototype.removeConstraint=function(e){var f=this.constraints.indexOf(e);-1!==f&&this.constraints.splice(f,1)},n.prototype.rayTest=function(e,f,n){n instanceof r?this.raycastClosest(e,f,{skipBackfaces:!0},n):this.raycastAll(e,f,{skipBackfaces:!0},n)},n.prototype.raycastAll=function(e,f,n,o){return n.mode=b.ALL,n.from=e,n.to=f,n.callback=o,N.intersectWorld(this,n)},n.prototype.raycastAny=function(e,f,n,o){return n.mode=b.ANY,n.from=e,n.to=f,n.result=o,N.intersectWorld(this,n)},n.prototype.raycastClosest=function(e,f,n,o){return n.mode=b.CLOSEST,n.from=e,n.to=f,n.result=o,N.intersectWorld(this,n)},n.prototype.remove=function(e){e.world=null;var f=this.bodies.length-1,n=this.bodies,o=n.indexOf(e);if(-1!==o){n.splice(o,1);for(var d=0;d!==n.length;d++)n[d].index=d;this.collisionMatrix.setNumObjects(f),this.removeBodyEvent.body=e,this.dispatchEvent(this.removeBodyEvent)}},n.prototype.removeBody=n.prototype.remove,n.prototype.addMaterial=function(e){this.materials.push(e)},n.prototype.addContactMaterial=function(e){this.contactmaterials.push(e),this.contactMaterialTable.set(e.materials[0].id,e.materials[1].id,e)},"undefined"==typeof performance&&(performance={}),!performance.now){var g=Date.now();performance.timing&&performance.timing.navigationStart&&(g=performance.timing.navigationStart),performance.now=function(){return Date.now()-g}}var x=new d;n.prototype.step=function(e,f,n){if(n=n||10,f=f||0,0===f)this.internalStep(e),this.time+=e;else{var o=Math.floor((this.time+f)/e)-Math.floor(this.time/e);o=Math.min(o,n);for(var d=performance.now(),i=0;i!==o&&(this.internalStep(e),!(performance.now()-d>1e3*e));i++);this.time+=f;for(var t=this.time%e,l=t/e,u=x,p=this.bodies,s=0;s!==p.length;s++){var y=p[s];y.type!==c.STATIC&&y.sleepState!==c.SLEEPING?(y.position.vsub(y.previousPosition,u),u.scale(l,u),y.position.vadd(u,y.interpolatedPosition)):(y.interpolatedPosition.copy(y.position),y.interpolatedQuaternion.copy(y.quaternion))}}};var j={type:"postStep"},v={type:"preStep"},A={type:"collide",body:null,contact:null},C=[],O=[],h=[],k=[],q=(new d,new d,new d,new d,new d,new d,new d,new d,new d,new i,new i),z=new i,B=new d;n.prototype.internalStep=function(e){this.dt=e;var f,n=this.contacts,d=h,i=k,t=this.numObjects(),l=this.bodies,u=this.solver,p=this.gravity,s=this.doProfiling,y=this.profile,a=c.DYNAMIC,r=this.constraints,w=O,b=(p.norm(),p.x),m=p.y,N=p.z,g=0;for(s&&(f=performance.now()),g=0;g!==t;g++){var x=l[g];if(x.type&a){var D=x.force,E=x.mass;D.x+=E*b,D.y+=E*m,D.z+=E*N}}for(var g=0,F=this.subsystems.length;g!==F;g++)this.subsystems[g].update();s&&(f=performance.now()),d.length=0,i.length=0,this.broadphase.collisionPairs(this,d,i),s&&(y.broadphase=performance.now()-f);var G=r.length;for(g=0;g!==G;g++){var H=r[g];if(!H.collideConnected)for(var I=d.length-1;I>=0;I-=1)(H.bodyA===d[I]&&H.bodyB===i[I]||H.bodyB===d[I]&&H.bodyA===i[I])&&(d.splice(I,1),i.splice(I,1))}this.collisionMatrixTick(),s&&(f=performance.now());var J=C,K=n.length;for(g=0;g!==K;g++)J.push(n[g]);n.length=0;var L=this.frictionEquations.length;for(g=0;g!==L;g++)w.push(this.frictionEquations[g]);this.frictionEquations.length=0,this.narrowphase.getContacts(d,i,this,n,J,this.frictionEquations,w),s&&(y.narrowphase=performance.now()-f),s&&(f=performance.now());for(var g=0;g=0&&R.material.friction>=0&&(S=x.material.friction*R.material.friction),x.material.restitution>=0&&R.material.restitution>=0&&(H.restitution=x.material.restitution*R.material.restitution)),u.addEquation(H),x.allowSleep&&x.type===c.DYNAMIC&&x.sleepState===c.SLEEPING&&R.sleepState===c.AWAKE&&R.type!==c.STATIC){var T=R.velocity.norm2()+R.angularVelocity.norm2(),U=Math.pow(R.sleepSpeedLimit,2); 28 | T>=2*U&&(x._wakeUpAfterNarrowphase=!0)}if(R.allowSleep&&R.type===c.DYNAMIC&&R.sleepState===c.SLEEPING&&x.sleepState===c.AWAKE&&x.type!==c.STATIC){var V=x.velocity.norm2()+x.angularVelocity.norm2(),W=Math.pow(x.sleepSpeedLimit,2);V>=2*W&&(R._wakeUpAfterNarrowphase=!0)}this.collisionMatrix.set(x,R,!0),this.collisionMatrixPrevious.get(x,R)||(A.body=R,A.contact=H,x.dispatchEvent(A),A.body=x,R.dispatchEvent(A))}for(s&&(y.makeContactConstraints=performance.now()-f,f=performance.now()),g=0;g!==t;g++){var x=l[g];x._wakeUpAfterNarrowphase&&(x.wakeUp(),x._wakeUpAfterNarrowphase=!1)}var G=r.length;for(g=0;g!==G;g++){var H=r[g];H.update();for(var I=0,X=H.equations.length;I!==X;I++){var Y=H.equations[I];u.addEquation(Y)}}u.solve(e,this),s&&(y.solve=performance.now()-f),u.removeAllEquations();var Z=Math.pow;for(g=0;g!==t;g++){var x=l[g];if(x.type&a){var $=Z(1-x.linearDamping,e),_=x.velocity;_.mult($,_);var ef=x.angularVelocity;if(ef){var ff=Z(1-x.angularDamping,e);ef.mult(ff,ef)}}}for(this.dispatchEvent(v),g=0;g!==t;g++){var x=l[g];x.preStep&&x.preStep.call(x)}s&&(f=performance.now());{var nf=q,of=z,df=this.stepnumber,tf=c.DYNAMIC|c.KINEMATIC,lf=df%(this.quatNormalizeSkip+1)===0,uf=this.quatNormalizeFast,pf=.5*e;o.types.PLANE,o.types.CONVEXPOLYHEDRON}for(g=0;g!==t;g++){var sf=l[g],yf=sf.force,cf=sf.torque;if(sf.type&tf&&sf.sleepState!==c.SLEEPING){var af=sf.velocity,rf=sf.angularVelocity,wf=sf.position,bf=sf.quaternion,mf=sf.invMass,Nf=sf.invInertiaWorld;af.x+=yf.x*mf*e,af.y+=yf.y*mf*e,af.z+=yf.z*mf*e,sf.angularVelocity&&(Nf.vmult(cf,B),B.mult(e,B),B.vadd(rf,rf)),wf.x+=af.x*e,wf.y+=af.y*e,wf.z+=af.z*e,sf.angularVelocity&&(nf.set(rf.x,rf.y,rf.z,0),nf.mult(bf,of),bf.x+=pf*of.x,bf.y+=pf*of.y,bf.z+=pf*of.z,bf.w+=pf*of.w,lf&&(uf?bf.normalizeFast():bf.normalize())),sf.aabb&&(sf.aabbNeedsUpdate=!0),sf.updateInertiaWorld&&sf.updateInertiaWorld()}}for(this.clearForces(),this.broadphase.dirty=!0,s&&(y.integrate=performance.now()-f),this.time+=e,this.stepnumber+=1,this.dispatchEvent(j),g=0;g!==t;g++){var x=l[g],gf=x.postStep;gf&&gf.call(x)}if(this.allowSleep)for(g=0;g!==t;g++)l[g].sleepTick(this.time)},n.prototype.clearForces=function(){for(var e=this.bodies,f=e.length,n=0;n!==f;n++){{var o=e[n];o.force,o.torque}o.force.set(0,0,0),o.torque.set(0,0,0)}}},{"../collision/AABB":3,"../collision/ArrayCollisionMatrix":4,"../collision/NaiveBroadphase":7,"../collision/Ray":9,"../collision/RaycastResult":10,"../equations/ContactEquation":19,"../equations/FrictionEquation":21,"../material/ContactMaterial":24,"../material/Material":25,"../math/Quaternion":28,"../math/Vec3":30,"../objects/Body":31,"../shapes/Shape":43,"../solver/GSSolver":46,"../utils/EventTarget":49,"../utils/TupleDictionary":52,"../utils/Vec3Pool":54,"./Narrowphase":55}]},{},[2])(2)}); --------------------------------------------------------------------------------