├── LICENSE ├── README.md └── cannonhelper.js /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 lmparppei 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies 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 included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cannonHelper 2 | ###A simple helper class for Three.js and Cannon integration 3 | 4 | Lauri-Matti Parppei 2016. Released under MIT License. 5 | 6 | A very very very simple helper class for fast and simple physics in Three.js. Created for my own needs but someone else might find this handy too. Creates Cannon shapes from Three.js meshes and also automatically removes them from world if they no longer exist. Supports box, sphere, plane and cylinder geometry. 7 | 8 | You can access the world through CannonHelper.world and all bodies added by the helper are held in CannonHelper.bodies array. The original parent mesh can be found in .bodies[i].parent. 9 | 10 | This could be expanded a lot. Feel free to do it - I lack the skills and knowledge! 11 | 12 | **Note:** You need to include Cannon.js in your project. 13 | 14 | 15 | ### Example 16 | 17 | A bare bones example. Set gravity to -9 on Y axis, create a mesh and add a physics body from it. Then just fire it up! If an object no longer exists its body will be automatically removed from world, so at basic level no additional checks or code is needed. 18 | ``` 19 | physics = new CannonHelper(0,-9,0); 20 | var mesh = new THREE.Mesh( geometry, material ); 21 | physics.addBody( mesh, mass ); 22 | 23 | animate () { 24 | physics.update(); 25 | render(); 26 | } 27 | ``` 28 | 29 | Easiest way to use the helper is through the .addBody function, which automatically creates a body from Three.js mesh. (Come to think of it, maybe this should use geometry instead of the mesh? Or support both?) 30 | 31 | For more control you can create a body and then add it to the world. Body object is a normal Cannon.js body, so you can do whatever you want with it. 32 | ``` 33 | var body = physics.newBody( mesh, mass, optional: Cannon shape )); 34 | physics.add(body); 35 | ``` 36 | 37 | You can also create compound shapes by adding parts similar to Three.js children. Note that you need to add the parts before adding the object to world. 38 | ``` 39 | var body = physics.newBody ( mesh, mass ); 40 | body.addPart( mesh ); 41 | physics.add(body); 42 | ``` 43 | 44 | If you want to set a different timeStep value for Cannon, you can set it with CannonHelper.timeStep. The default is 1.0 / 60.0. 45 | ``` 46 | physics.timeStep = 1.0 / 60.0; 47 | ``` 48 | 49 | I'll provide a simple example project some time soon. 50 | 51 | ### Collision helper 52 | 53 | Not exactly a Three.js integration thing, but I included my collision group helper here too. Assign names for groups and it automatically adds ALL collision groups to body's collision filter. You can then set the filter to exclude certain groups. 54 | 55 | ``` 56 | physics.setCollisionGroups([ 'floor', 'player', 'debris' ]); 57 | 58 | // This object belongs to collision group 'player' 59 | body.setCollisions('player'); 60 | 61 | // Excludes groups 'debris' and 'decoration' from collisions 62 | body.noCollisions(['debris', 'decoration']); 63 | ``` 64 | -------------------------------------------------------------------------------- /cannonhelper.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | CannonHelper 1.02 4 | 2016-07-01 5 | 6 | Lauri-Matti Parppei 7 | Released under the MIT license 8 | 9 | 10 | A very very very simple helper class for fast and simple physics in Three.js. 11 | Created for my own needs but someone else might find this handy too. Creates 12 | Cannon shapes from Three.js meshes and also automatically removes them from 13 | world if they no longer exist. 14 | 15 | You can access the world through CannonHelper.world and all bodies added by the 16 | helper are held in CannonHelper.bodies array. The original parent mesh can be 17 | found in .bodies[i].parent. 18 | 19 | This could be expanded a lot. Feel free to do it - I lack the skills and knowledge! 20 | 21 | Note: You need to include Cannon.js in your project. 22 | 23 | 24 | EXAMPLE 25 | 26 | A bare bones example. Set gravity to -9 on Y axis, create a mesh and add a physics 27 | body from it. Then just fire it up! If an object no longer exists its body will be 28 | automatically removed from world, so at basic level no additional checks or code is needed. 29 | 30 | physics = new CannonHelper(0,-9,0); 31 | var mesh = new THREE.Mesh( geometry, material ); 32 | physics.addBody( mesh, mass ); 33 | 34 | animate () { 35 | physics.update(); 36 | render(); 37 | } 38 | 39 | Easiest way to use the helper is through the .addBody function, which automatically 40 | creates a body from Three.js mesh. (Come to think of it, maybe this should use geometry 41 | instead of the mesh? Or support both?) 42 | 43 | For more control you can create a body and then add it to the world. Body object is a normal 44 | Cannon.js body, so you can do whatever you want with it. 45 | 46 | var body = physics.newBody( mesh, mass, optional: Cannon shape )); 47 | physics.add(body); 48 | 49 | You can also create compound shapes by adding parts similar to Three.js children. Note that 50 | you need to add the parts before adding the object to world. 51 | 52 | var body = physics.newBody ( mesh, mass ); 53 | body.addPart( mesh ); 54 | physics.add(body); 55 | 56 | If you want to set a different timeStep value for Cannon, you can set it with 57 | CannonHelper.timeStep. The default is 1.0 / 60.0. 58 | 59 | physics.timeStep = 1.0 / 60.0; 60 | 61 | 62 | COLLISION GROUP HELPER 63 | 64 | Not exactly a Three.js integration thing, but I included my collision group helper 65 | here too. It automatically adds ALL collision groups to body's collision filter 66 | and you can set the filter to exclude certain groups. 67 | 68 | physics.setCollisionGroups([ 'floor', 'player', 'debris' ]); 69 | 70 | // This object belongs to collision group 'floor' 71 | body.setCollisions('player'); 72 | 73 | // Excludes groups 'debris' and 'decoration' from collisions 74 | body.noCollisions(['debris', 'decoration']); 75 | 76 | */ 77 | 78 | function CannonHelper (gravityX,gravityY,gravityZ, timeStep) { 79 | if (!timeStep) { timeStep = 1.0/60.0; } 80 | 81 | this.bodies = []; 82 | this.world = new CANNON.World(); 83 | this.world.gravity.set(gravityX,gravityY,gravityZ); 84 | this.world.broadphase = new CANNON.NaiveBroadphase(); 85 | this.timeStep = timeStep; 86 | 87 | this.collisionGroups = {}; 88 | 89 | this.newBody = function (object3d, mass, shape) { 90 | var body = new CANNON.Body({ mass: mass }); 91 | 92 | if (!shape) { 93 | shape = this.getGeometry(object3d); 94 | } 95 | 96 | body.addShape(shape); 97 | body.parent = object3d; 98 | body.position.copy(object3d.position); 99 | body.quaternion.copy(object3d.quaternion); 100 | 101 | var that = this; 102 | 103 | body.addPart = function (object3d, shape) { 104 | if (!shape) { shape = that.getGeometry(object3d); } 105 | 106 | var position = new CANNON.Vec3(); 107 | var quaternion = new CANNON.Vec3(); 108 | 109 | position.copy(object3d.position); 110 | quaternion.copy(object3d.quaternion); 111 | 112 | this.addShape(shape, position); 113 | } 114 | 115 | body.applyCentralImpulse = function (forceX, forceY, forceZ, offsetX = 0, offsetY = 0, offsetZ = 0) { 116 | this.applyImpulse( 117 | new CANNON.Vec3(forceX, forceY, forceZ), 118 | new CANNON.Vec3(this.position.x + offsetX, this.position.y + offsetY, this.position.z + offsetZ) 119 | ); 120 | } 121 | 122 | // Set the collision group this body belongs to 123 | body.setCollisions = function (group) { 124 | this.collisionFilterGroup = that.collisionGroups[group]; 125 | this.collisionFilterMask = undefined; 126 | for (var index in that.collisionGroups) { 127 | this.collisionFilterMask |= parseInt(that.collisionGroups[index]); 128 | } 129 | } 130 | 131 | // Creates a filter mask that EXCLUDES certain groups 132 | body.noCollisions = function (groups) { 133 | var isArr = Object.prototype.toString.call(groups) == '[object Array]'; 134 | if (!isArr) { groups = [ groups ]; } 135 | 136 | this.collisionFilterMask = undefined; 137 | for (var index in that.collisionGroups) { 138 | if (groups.indexOf(index) == -1) { 139 | this.collisionFilterMask |= parseInt(that.collisionGroups[index]); 140 | } 141 | } 142 | } 143 | 144 | return body; 145 | } 146 | 147 | this.getGeometry = function (object3d) { 148 | var shape = {}; 149 | 150 | var geometry = object3d.geometry; 151 | var parameters = geometry.parameters; 152 | 153 | switch (geometry.type) { 154 | case "BoxGeometry": 155 | shape = new CANNON.Box( 156 | new CANNON.Vec3(parameters.width / 2, parameters.height / 2, parameters.depth / 2) 157 | ); 158 | break; 159 | 160 | case "SphereGeometry": 161 | shape = new CANNON.Sphere(parameters.radius); 162 | break; 163 | 164 | case "CylinderGeometry": 165 | // The cylinder in Cannon is different than Three.js cylinder. 166 | // We need to rotate it before attaching it to the mesh. 167 | 168 | shape = new CANNON.Cylinder(parameters.radiusTop, parameters.radiusBottom, parameters.height, parameters.radialSegments); 169 | 170 | var quat = new CANNON.Quaternion(); 171 | quat.setFromAxisAngle(new CANNON.Vec3(1,0,0),-Math.PI/2); 172 | var translation = new CANNON.Vec3(0,0,0); 173 | shape.transformAllPoints(translation,quat); 174 | 175 | break; 176 | 177 | case "PlaneGeometry": 178 | // NOTE: This is NOT the Cannon plane which is infinite. 179 | // It mimics a finite Three.js plane with a very thin box. 180 | 181 | shape = new CANNON.Box( 182 | new CANNON.Vec3(parameters.width / 2, parameters.height / 2, 0.01) 183 | ); 184 | break; 185 | 186 | default: 187 | console.log("Specify a Cannon.js shape"); 188 | break; 189 | } 190 | return shape; 191 | } 192 | 193 | // A cheat function for lazy me. 194 | this.addBody = function (body, mass, shape) { 195 | var newBody = this.newBody(body, mass, shape); 196 | this.add (newBody); 197 | return (newBody); 198 | } 199 | 200 | this.add = function (body) { 201 | this.world.add(body); 202 | this.bodies.push(body); 203 | } 204 | 205 | // Create collision groups 206 | this.setCollisionGroups = function (groups) { 207 | var n = 2; 208 | this.collisionGroups = {}; 209 | 210 | for (var index in groups) { 211 | var index = parseInt(index); 212 | 213 | this.collisionGroups[groups[index]] = Math.pow(n, (index + 1)); 214 | } 215 | } 216 | 217 | this.update = function () { 218 | for (var b in this.bodies) { 219 | var body = this.bodies[b]; 220 | 221 | if (body.parent.parent) { 222 | body.parent.position.copy(body.position); 223 | body.parent.quaternion.copy(body.quaternion); 224 | } else { 225 | this.world.remove(body) 226 | } 227 | } 228 | 229 | this.world.step(this.timeStep); 230 | } 231 | } --------------------------------------------------------------------------------