浏览代码

Cleanup, further functionality

Added executeNativeFunction,
cleanup unneeded code
added setVelocity
Raanan Weber 9 年之前
父节点
当前提交
3cc4fb7e0a

+ 20 - 500
src/Physics/Plugins/babylon.cannonJSPlugin.js

@@ -1,505 +1,5 @@
 var BABYLON;
 (function (BABYLON) {
-    /*interface IRegisteredMesh {
-        mesh: AbstractMesh;
-        body: any; //Cannon body
-        material: any;
-        delta: Vector3;
-        deltaRotation: Quaternion;
-        type: any;
-        collisionFunction?: (event: any) => void;
-
-    }*/
-    /*export class OldCannonJSPlugin {
-
-        private _world: any;
-        private _registeredMeshes: Array<IRegisteredMesh> = [];
-        private _physicsMaterials = [];
-        private _gravity: Vector3;
-        private _fixedTimeStep: number = 1 / 60;
-        //private _maxSubSteps : number = 15;
-
-        public name = "CannonJS";
-
-        public constructor(private _useDeltaForWorldStep: boolean = true) {
-
-        }
-
-        public initialize(iterations: number = 10): void {
-            this._world = new CANNON.World();
-            this._world.broadphase = new CANNON.NaiveBroadphase();
-            this._world.solver.iterations = iterations;
-        }
-
-        private _checkWithEpsilon(value: number): number {
-            return value < PhysicsEngine.Epsilon ? PhysicsEngine.Epsilon : value;
-        }
-
-        public runOneStep(delta: number): void {
-
-            this._world.step(this._fixedTimeStep, this._useDeltaForWorldStep ? delta * 1000 : 0);
-
-            this._registeredMeshes.forEach((registeredMesh) => {
-
-                // Body position
-                var bodyX = registeredMesh.body.position.x,
-                    bodyY = registeredMesh.body.position.y,
-                    bodyZ = registeredMesh.body.position.z;
-
-                registeredMesh.mesh.position.x = bodyX + registeredMesh.delta.x;
-                registeredMesh.mesh.position.y = bodyY + registeredMesh.delta.y;
-                registeredMesh.mesh.position.z = bodyZ + registeredMesh.delta.z;
-
-                registeredMesh.mesh.rotationQuaternion.copyFrom(registeredMesh.body.quaternion);
-                if (registeredMesh.deltaRotation) {
-                    registeredMesh.mesh.rotationQuaternion.multiplyInPlace(registeredMesh.deltaRotation);
-                }
-
-                //is the physics collision callback is set?
-                if (registeredMesh.mesh.onPhysicsCollide) {
-                    if (!registeredMesh.collisionFunction) {
-                        registeredMesh.collisionFunction = (e) => {
-                            //find the mesh that collided with the registered mesh
-                            for (var idx = 0; idx < this._registeredMeshes.length; idx++) {
-                                if (this._registeredMeshes[idx].body == e.body) {
-                                    registeredMesh.mesh.onPhysicsCollide(this._registeredMeshes[idx].mesh, e.contact);
-                                }
-                            }
-                        }
-                        registeredMesh.body.addEventListener("collide", registeredMesh.collisionFunction);
-                    }
-                } else {
-                    //unregister, in case the function was removed for some reason
-                    if (registeredMesh.collisionFunction) {
-                        registeredMesh.body.removeEventListener("collide", registeredMesh.collisionFunction);
-                    }
-                }
-            });
-        }
-
-        public setGravity(gravity: Vector3): void {
-            this._gravity = gravity;
-            this._world.gravity.set(gravity.x, gravity.y, gravity.z);
-        }
-
-        public getGravity(): Vector3 {
-            return this._gravity;
-        }
-
-        public registerMesh(mesh: AbstractMesh, impostor: number, options?: PhysicsImpostorParameters): any {
-            this.unregisterMesh(mesh);
-
-            if (!mesh.rotationQuaternion) {
-                mesh.rotationQuaternion = Quaternion.RotationYawPitchRoll(mesh.rotation.y, mesh.rotation.x, mesh.rotation.z);
-            }
-
-            mesh.computeWorldMatrix(true);
-
-            var shape = this._createShape(mesh, impostor);
-
-            return this._createRigidBodyFromShape(shape, mesh, options);
-        }
-
-        private _createShape(mesh: AbstractMesh, impostor: number) {
-        
-            //get the correct bounding box
-            var oldQuaternion = mesh.rotationQuaternion;
-            mesh.rotationQuaternion = new Quaternion(0, 0, 0, 1);
-            mesh.computeWorldMatrix(true);
-
-            var returnValue;
-
-            switch (impostor) {
-                case PhysicsEngine.SphereImpostor:
-                    var bbox = mesh.getBoundingInfo().boundingBox;
-                    var radiusX = bbox.maximumWorld.x - bbox.minimumWorld.x;
-                    var radiusY = bbox.maximumWorld.y - bbox.minimumWorld.y;
-                    var radiusZ = bbox.maximumWorld.z - bbox.minimumWorld.z;
-
-                    returnValue = new CANNON.Sphere(Math.max(this._checkWithEpsilon(radiusX), this._checkWithEpsilon(radiusY), this._checkWithEpsilon(radiusZ)) / 2);
-
-                    break;
-                //TMP also for cylinder - TODO Cannon supports cylinder natively.
-                case PhysicsEngine.CylinderImpostor:
-                    Tools.Warn("CylinderImposter not yet implemented, using BoxImposter instead");
-                case PhysicsEngine.BoxImpostor:
-                    bbox = mesh.getBoundingInfo().boundingBox;
-                    var min = bbox.minimumWorld;
-                    var max = bbox.maximumWorld;
-                    var box = max.subtract(min).scale(0.5);
-                    returnValue = new CANNON.Box(new CANNON.Vec3(this._checkWithEpsilon(box.x), this._checkWithEpsilon(box.y), this._checkWithEpsilon(box.z)));
-                    break;
-                case PhysicsEngine.PlaneImpostor:
-                    Tools.Warn("Attention, Cannon.js PlaneImposter might not behave as you wish. Consider using BoxImposter instead");
-                    returnValue = new CANNON.Plane();
-                    break;
-                case PhysicsEngine.MeshImpostor:
-                    var rawVerts = mesh.getVerticesData(VertexBuffer.PositionKind);
-                    var rawFaces = mesh.getIndices();
-                    Tools.Warn("MeshImpostor only collides against spheres.");
-                    returnValue = new CANNON.Trimesh(rawVerts, rawFaces); //this._createConvexPolyhedron(rawVerts, rawFaces, mesh);
-                    break;
-                case PhysicsEngine.HeightmapImpostor:
-                    returnValue = this._createHeightmap(mesh);
-                    break;
-
-            }
-
-            mesh.rotationQuaternion = oldQuaternion;
-
-            return returnValue;
-        }
-
-        private _createConvexPolyhedron(rawVerts: number[] | Float32Array, rawFaces: number[] | Int32Array, mesh: AbstractMesh): any {
-            var verts = [], faces = [];
-
-            mesh.computeWorldMatrix(true);
-
-            //reuse this variable
-            var transformed = Vector3.Zero();
-            // Get vertices
-            for (var i = 0; i < rawVerts.length; i += 3) {
-                Vector3.TransformNormalFromFloatsToRef(rawVerts[i], rawVerts[i + 1], rawVerts[i + 2], mesh.getWorldMatrix(), transformed);
-                verts.push(new CANNON.Vec3(transformed.x, transformed.y, transformed.z));
-            }
-
-            // Get faces
-            for (var j = 0; j < rawFaces.length; j += 3) {
-                faces.push([rawFaces[j], rawFaces[j + 2], rawFaces[j + 1]]);
-            }
-
-            var shape = new CANNON.ConvexPolyhedron(verts, faces);
-
-            return shape;
-        }
-
-        private _createHeightmap(mesh: AbstractMesh, pointDepth?: number) {
-            var pos = mesh.getVerticesData(VertexBuffer.PositionKind);
-            var matrix = [];
-    
-            //For now pointDepth will not be used and will be automatically calculated.
-            //Future reference - try and find the best place to add a reference to the pointDepth variable.
-            var arraySize = pointDepth || ~~(Math.sqrt(pos.length / 3) - 1);
-
-            var dim = Math.min(mesh.getBoundingInfo().boundingBox.extendSize.x, mesh.getBoundingInfo().boundingBox.extendSize.z);
-
-            var elementSize = dim * 2 / arraySize;
-
-            var minY = mesh.getBoundingInfo().boundingBox.extendSize.y;
-
-            for (var i = 0; i < pos.length; i = i + 3) {
-                var x = Math.round((pos[i + 0]) / elementSize + arraySize / 2);
-                var z = Math.round(((pos[i + 2]) / elementSize - arraySize / 2) * -1);
-                var y = pos[i + 1] + minY;
-                if (!matrix[x]) {
-                    matrix[x] = [];
-                }
-                if (!matrix[x][z]) {
-                    matrix[x][z] = y;
-                }
-                matrix[x][z] = Math.max(y, matrix[x][z]);
-            }
-
-
-            for (var x = 0; x <= arraySize; ++x) {
-                if (!matrix[x]) {
-                    var loc = 1;
-                    while (!matrix[(x + loc) % arraySize]) {
-                        loc++;
-                    }
-                    matrix[x] = matrix[(x + loc) % arraySize].slice();
-                    //console.log("missing x", x);
-                }
-                for (var z = 0; z <= arraySize; ++z) {
-                    if (!matrix[x][z]) {
-                        var loc = 1;
-                        var newValue;
-                        while (newValue === undefined) {
-                            newValue = matrix[x][(z + loc++) % arraySize];
-                        }
-                        matrix[x][z] = newValue;
-
-                    }
-                }
-            }
-
-            var shape = new CANNON.Heightfield(matrix, {
-                elementSize: elementSize
-            });
-            
-            //For future reference, needed for body transformation
-            shape.minY = minY;
-
-            return shape;
-        }
-
-        private _addMaterial(friction: number, restitution: number) {
-            var index;
-            var mat;
-
-            for (index = 0; index < this._physicsMaterials.length; index++) {
-                mat = this._physicsMaterials[index];
-
-                if (mat.friction === friction && mat.restitution === restitution) {
-                    return mat;
-                }
-            }
-
-            var currentMat = new CANNON.Material("mat");
-            this._physicsMaterials.push(currentMat);
-
-            for (index = 0; index < this._physicsMaterials.length; index++) {
-                mat = this._physicsMaterials[index];
-
-                var contactMaterial = new CANNON.ContactMaterial(mat, currentMat, { friction: friction, restitution: restitution });
-
-                this._world.addContactMaterial(contactMaterial);
-            }
-
-            return currentMat;
-        }
-
-        private _createRigidBodyFromShape(shape: any, mesh: AbstractMesh, options: PhysicsImpostorParameters): any {
-            if (!mesh.rotationQuaternion) {
-                mesh.rotationQuaternion = Quaternion.RotationYawPitchRoll(mesh.rotation.y, mesh.rotation.x, mesh.rotation.z);
-            }
-            
-            // The delta between the mesh position and the mesh bounding box center
-            var bbox = mesh.getBoundingInfo().boundingBox;
-            var deltaPosition = mesh.position.subtract(bbox.center);
-            var deltaRotation;
-
-            var material = this._addMaterial(options.friction, options.restitution);
-            var body = new CANNON.Body({
-                mass: options.mass,
-                material: material,
-                position: new CANNON.Vec3(bbox.center.x, bbox.center.y, bbox.center.z)
-            });
-
-            body.quaternion = new CANNON.Quaternion(mesh.rotationQuaternion.x, mesh.rotationQuaternion.y, mesh.rotationQuaternion.z, mesh.rotationQuaternion.w);
-            //is shape is a plane or a heightmap, it must be rotated 90 degs in the X axis.
-            if (shape.type === CANNON.Shape.types.PLANE || shape.type === CANNON.Shape.types.HEIGHTFIELD) {
-                //-90 DEG in X, precalculated
-                var tmpQ = new CANNON.Quaternion(-0.7071067811865475, 0, 0, 0.7071067811865475);
-                body.quaternion = body.quaternion.mult(tmpQ);
-                //Invert! (Precalculated, 90 deg in X)
-                deltaRotation = new Quaternion(0.7071067811865475, 0, 0, 0.7071067811865475);
-            }
-            
-            //If it is a heightfield, if should be centered.
-            if (shape.type === CANNON.Shape.types.HEIGHTFIELD) {
-                
-                //calculate the correct body position:
-                var rotationQuaternion = mesh.rotationQuaternion;
-                mesh.rotationQuaternion = new Quaternion();
-                mesh.computeWorldMatrix(true);
-                
-                //get original center with no rotation
-                var center = mesh.getBoundingInfo().boundingBox.center.clone();
-
-                var oldPivot = mesh.getPivotMatrix() || Matrix.Translation(0, 0, 0);
-                
-                //rotation is back
-                mesh.rotationQuaternion = rotationQuaternion;
-        
-                //calculate the new center using a pivot (since Cannon.js doesn't center height maps)
-                var p = Matrix.Translation(mesh.getBoundingInfo().boundingBox.extendSize.x, 0, -mesh.getBoundingInfo().boundingBox.extendSize.z);
-                mesh.setPivotMatrix(p);
-                mesh.computeWorldMatrix(true);
-        
-                //calculate the translation
-                var translation = mesh.getBoundingInfo().boundingBox.center.subtract(center).subtract(mesh.position).negate();
-
-                body.position = new CANNON.Vec3(translation.x, translation.y - mesh.getBoundingInfo().boundingBox.extendSize.y, translation.z);
-                //add it inverted to the delta
-                deltaPosition = mesh.getBoundingInfo().boundingBox.center.subtract(center);
-                deltaPosition.y += mesh.getBoundingInfo().boundingBox.extendSize.y;
-
-                mesh.setPivotMatrix(oldPivot);
-                mesh.computeWorldMatrix(true);
-            } else if (shape.type === CANNON.Shape.types.TRIMESH) {
-                deltaPosition = Vector3.Zero();
-            }
-            
-            //add the shape
-            body.addShape(shape);
-
-            this._world.add(body);
-
-            this._registeredMeshes.push({ mesh: mesh, body: body, material: material, delta: deltaPosition, deltaRotation: deltaRotation, type: shape.type });
-
-            return body;
-        }
-
-        public registerMeshesAsCompound(parts: PhysicsCompoundBodyPart[], options: PhysicsBodyCreationOptions): any {
-
-            var initialMesh = parts[0].mesh;
-
-            this.unregisterMesh(initialMesh);
-
-            initialMesh.computeWorldMatrix(true);
-
-            var initialShape = this._createShape(initialMesh, parts[0].impostor);
-            var body = this._createRigidBodyFromShape(initialShape, initialMesh, options);
-
-            for (var index = 1; index < parts.length; index++) {
-                var mesh = parts[index].mesh;
-                mesh.computeWorldMatrix(true);
-                var shape = this._createShape(mesh, parts[index].impostor);
-                var localPosition = mesh.position;
-
-                body.addShape(shape, new CANNON.Vec3(localPosition.x, localPosition.y, localPosition.z));
-            }
-
-            return body;
-        }
-
-        private _unbindBody(body): void {
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-
-                if (registeredMesh.body === body) {
-                    this._world.remove(registeredMesh.body);
-                    registeredMesh.body = null;
-                    registeredMesh.delta = null;
-                    registeredMesh.deltaRotation = null;
-                }
-            }
-        }
-
-        public unregisterMesh(mesh: AbstractMesh): void {
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-
-                if (registeredMesh.mesh === mesh) {
-                    // Remove body
-                    if (registeredMesh.body) {
-                        this._unbindBody(registeredMesh.body);
-                    }
-
-                    this._registeredMeshes.splice(index, 1);
-                    return;
-                }
-            }
-        }
-
-        public applyImpulse(mesh: AbstractMesh, force: Vector3, contactPoint: Vector3): void {
-            var worldPoint = new CANNON.Vec3(contactPoint.x, contactPoint.y, contactPoint.z);
-            var impulse = new CANNON.Vec3(force.x, force.y, force.z);
-
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-
-                if (registeredMesh.mesh === mesh) {
-                    registeredMesh.body.applyImpulse(impulse, worldPoint);
-                    return;
-                }
-            }
-        }
-
-        public updateBodyPosition = function(mesh: AbstractMesh): void {
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-                if (registeredMesh.mesh === mesh || registeredMesh.mesh === mesh.parent) {
-                    var body = registeredMesh.body;
-
-                    var center = mesh.getBoundingInfo().boundingBox.center.clone();
-
-                    body.quaternion.copy(mesh.rotationQuaternion);
-
-                    if (registeredMesh.deltaRotation) {
-                        var tmpQ = new CANNON.Quaternion(-0.7071067811865475, 0, 0, 0.7071067811865475);
-                        body.quaternion = body.quaternion.mult(tmpQ);
-                    }
-
-                    if (registeredMesh.type === CANNON.Shape.types.HEIGHTFIELD) {
-                        //calculate the correct body position:
-                        var rotationQuaternion = mesh.rotationQuaternion;
-                        mesh.rotationQuaternion = new Quaternion();
-                        mesh.computeWorldMatrix(true);
-                        
-                        //get original center with no rotation
-                        var center = mesh.getBoundingInfo().boundingBox.center.clone();
-
-                        var oldPivot = mesh.getPivotMatrix() || Matrix.Translation(0, 0, 0);
-                        
-                        //rotation is back
-                        mesh.rotationQuaternion = rotationQuaternion;
-                
-                        //calculate the new center using a pivot (since Cannon.js doesn't center height maps)
-                        var p = Matrix.Translation(mesh.getBoundingInfo().boundingBox.extendSize.x, 0, -mesh.getBoundingInfo().boundingBox.extendSize.z);
-                        mesh.setPivotMatrix(p);
-                        mesh.computeWorldMatrix(true);
-                
-                        //calculate the translation
-                        var translation = mesh.getBoundingInfo().boundingBox.center.subtract(center).subtract(mesh.position).negate();
-
-                        center.copyFromFloats(translation.x, translation.y - mesh.getBoundingInfo().boundingBox.extendSize.y, translation.z);
-                        //add it inverted to the delta
-                        registeredMesh.delta = mesh.getBoundingInfo().boundingBox.center.subtract(center);
-                        registeredMesh.delta.y += mesh.getBoundingInfo().boundingBox.extendSize.y;
-
-                        mesh.setPivotMatrix(oldPivot);
-                        mesh.computeWorldMatrix(true);
-                    } else if (registeredMesh.type === CANNON.Shape.types.TRIMESH) {
-                        center.copyFromFloats(mesh.position.x, mesh.position.y, mesh.position.z);
-                    }
-
-                    body.position.set(center.x, center.y, center.z);
-
-                    return;
-                }
-            }
-        }
-
-        public createLink(mesh1: AbstractMesh, mesh2: AbstractMesh, pivot1: Vector3, pivot2: Vector3): boolean {
-            var body1 = null, body2 = null;
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-
-                if (registeredMesh.mesh === mesh1) {
-                    body1 = registeredMesh.body;
-                    if (body2) break;
-                } else if (registeredMesh.mesh === mesh2) {
-                    body2 = registeredMesh.body;
-                    if (body1) break;
-                }
-            }
-
-            if (!body1 || !body2) {
-                return false;
-            }
-
-            var constraint = new CANNON.PointToPointConstraint(body1, new CANNON.Vec3(pivot1.x, pivot1.y, pivot1.z), body2, new CANNON.Vec3(pivot2.x, pivot2.y, pivot2.z));
-            this._world.addConstraint(constraint);
-
-            return true;
-        }
-
-        public dispose(): void {
-            while (this._registeredMeshes.length) {
-                this.unregisterMesh(this._registeredMeshes[0].mesh);
-            }
-        }
-
-        public isSupported(): boolean {
-            return window.CANNON !== undefined;
-        }
-
-        public getWorldObject(): any {
-            return this._world;
-        }
-
-        public getPhysicsBodyOfMesh(mesh: AbstractMesh) {
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-                if (registeredMesh.mesh === mesh) {
-                    return registeredMesh.body;
-                }
-            }
-            return null;
-        }
-    }*/
     var CannonJSPlugin = (function () {
         function CannonJSPlugin(_useDeltaForWorldStep, iterations) {
             if (_useDeltaForWorldStep === void 0) { _useDeltaForWorldStep = true; }
@@ -508,6 +8,8 @@ var BABYLON;
             this.name = "CannonJSPlugin";
             this._physicsMaterials = [];
             this._fixedTimeStep = 1 / 60;
+            //See https://github.com/schteppe/cannon.js/blob/gh-pages/demos/collisionFilter.html
+            this._currentCollisionGroup = 2;
             this._minus90X = new BABYLON.Quaternion(-0.7071067811865475, 0, 0, 0.7071067811865475);
             this._plus90X = new BABYLON.Quaternion(0.7071067811865475, 0, 0, 0.7071067811865475);
             this._tmpPosition = BABYLON.Vector3.Zero();
@@ -631,6 +133,7 @@ var BABYLON;
             }
             var constraint;
             var jointData = impostorJoint.joint.jointData;
+            //TODO - https://github.com/schteppe/cannon.js/blob/gh-pages/demos/collisionFilter.html
             var constraintData = {
                 pivotA: jointData.mainPivot ? new CANNON.Vec3().copy(jointData.mainPivot) : null,
                 pivotB: jointData.connectedPivot ? new CANNON.Vec3().copy(jointData.connectedPivot) : null,
@@ -638,6 +141,20 @@ var BABYLON;
                 axisB: jointData.connectedAxis ? new CANNON.Vec3().copy(jointData.connectedAxis) : null,
                 maxForce: jointData.nativeParams.maxForce
             };
+            if (!jointData.collision) {
+                //add 1st body to a collision group of its own, if it is not in 1
+                if (mainBody.collisionFilterGroup === 1) {
+                    mainBody.collisionFilterGroup = this._currentCollisionGroup;
+                    this._currentCollisionGroup <<= 1;
+                }
+                if (connectedBody.collisionFilterGroup === 1) {
+                    connectedBody.collisionFilterGroup = this._currentCollisionGroup;
+                    this._currentCollisionGroup <<= 1;
+                }
+                //add their mask to the collisionFilterMask of each other:
+                connectedBody.collisionFilterMask = connectedBody.collisionFilterMask | ~mainBody.collisionFilterGroup;
+                mainBody.collisionFilterMask = mainBody.collisionFilterMask | ~connectedBody.collisionFilterGroup;
+            }
             switch (impostorJoint.joint.type) {
                 case BABYLON.PhysicsJoint.HingeJoint:
                     constraint = new CANNON.HingeConstraint(mainBody, connectedBody, constraintData);
@@ -826,6 +343,9 @@ var BABYLON;
         CannonJSPlugin.prototype.isSupported = function () {
             return window.CANNON !== undefined;
         };
+        CannonJSPlugin.prototype.setVelocity = function (impostor, velocity) {
+            impostor.physicsBody.velocity.copy(velocity);
+        };
         CannonJSPlugin.prototype.dispose = function () {
             //nothing to do, actually.
         };

+ 21 - 502
src/Physics/Plugins/babylon.cannonJSPlugin.ts

@@ -1,514 +1,14 @@
 module BABYLON {
     declare var CANNON;
 
-    /*interface IRegisteredMesh {
-        mesh: AbstractMesh;
-        body: any; //Cannon body
-        material: any;
-        delta: Vector3;
-        deltaRotation: Quaternion;
-        type: any;
-        collisionFunction?: (event: any) => void;
-
-    }*/
-
-    /*export class OldCannonJSPlugin {
-
-        private _world: any;
-        private _registeredMeshes: Array<IRegisteredMesh> = [];
-        private _physicsMaterials = [];
-        private _gravity: Vector3;
-        private _fixedTimeStep: number = 1 / 60;
-        //private _maxSubSteps : number = 15;
-
-        public name = "CannonJS";
-
-        public constructor(private _useDeltaForWorldStep: boolean = true) {
-
-        }
-
-        public initialize(iterations: number = 10): void {
-            this._world = new CANNON.World();
-            this._world.broadphase = new CANNON.NaiveBroadphase();
-            this._world.solver.iterations = iterations;
-        }
-
-        private _checkWithEpsilon(value: number): number {
-            return value < PhysicsEngine.Epsilon ? PhysicsEngine.Epsilon : value;
-        }
-
-        public runOneStep(delta: number): void {
-
-            this._world.step(this._fixedTimeStep, this._useDeltaForWorldStep ? delta * 1000 : 0);
-
-            this._registeredMeshes.forEach((registeredMesh) => {
-
-                // Body position
-                var bodyX = registeredMesh.body.position.x,
-                    bodyY = registeredMesh.body.position.y,
-                    bodyZ = registeredMesh.body.position.z;
-
-                registeredMesh.mesh.position.x = bodyX + registeredMesh.delta.x;
-                registeredMesh.mesh.position.y = bodyY + registeredMesh.delta.y;
-                registeredMesh.mesh.position.z = bodyZ + registeredMesh.delta.z;
-
-                registeredMesh.mesh.rotationQuaternion.copyFrom(registeredMesh.body.quaternion);
-                if (registeredMesh.deltaRotation) {
-                    registeredMesh.mesh.rotationQuaternion.multiplyInPlace(registeredMesh.deltaRotation);
-                }
-
-                //is the physics collision callback is set?
-                if (registeredMesh.mesh.onPhysicsCollide) {
-                    if (!registeredMesh.collisionFunction) {
-                        registeredMesh.collisionFunction = (e) => {
-                            //find the mesh that collided with the registered mesh
-                            for (var idx = 0; idx < this._registeredMeshes.length; idx++) {
-                                if (this._registeredMeshes[idx].body == e.body) {
-                                    registeredMesh.mesh.onPhysicsCollide(this._registeredMeshes[idx].mesh, e.contact);
-                                }
-                            }
-                        }
-                        registeredMesh.body.addEventListener("collide", registeredMesh.collisionFunction);
-                    }
-                } else {
-                    //unregister, in case the function was removed for some reason
-                    if (registeredMesh.collisionFunction) {
-                        registeredMesh.body.removeEventListener("collide", registeredMesh.collisionFunction);
-                    }
-                }
-            });
-        }
-
-        public setGravity(gravity: Vector3): void {
-            this._gravity = gravity;
-            this._world.gravity.set(gravity.x, gravity.y, gravity.z);
-        }
-
-        public getGravity(): Vector3 {
-            return this._gravity;
-        }
-
-        public registerMesh(mesh: AbstractMesh, impostor: number, options?: PhysicsImpostorParameters): any {
-            this.unregisterMesh(mesh);
-
-            if (!mesh.rotationQuaternion) {
-                mesh.rotationQuaternion = Quaternion.RotationYawPitchRoll(mesh.rotation.y, mesh.rotation.x, mesh.rotation.z);
-            }
-
-            mesh.computeWorldMatrix(true);
-
-            var shape = this._createShape(mesh, impostor);
-
-            return this._createRigidBodyFromShape(shape, mesh, options);
-        }
-
-        private _createShape(mesh: AbstractMesh, impostor: number) {
-		
-            //get the correct bounding box
-            var oldQuaternion = mesh.rotationQuaternion;
-            mesh.rotationQuaternion = new Quaternion(0, 0, 0, 1);
-            mesh.computeWorldMatrix(true);
-
-            var returnValue;
-
-            switch (impostor) {
-                case PhysicsEngine.SphereImpostor:
-                    var bbox = mesh.getBoundingInfo().boundingBox;
-                    var radiusX = bbox.maximumWorld.x - bbox.minimumWorld.x;
-                    var radiusY = bbox.maximumWorld.y - bbox.minimumWorld.y;
-                    var radiusZ = bbox.maximumWorld.z - bbox.minimumWorld.z;
-
-                    returnValue = new CANNON.Sphere(Math.max(this._checkWithEpsilon(radiusX), this._checkWithEpsilon(radiusY), this._checkWithEpsilon(radiusZ)) / 2);
-
-                    break;
-                //TMP also for cylinder - TODO Cannon supports cylinder natively.
-                case PhysicsEngine.CylinderImpostor:
-                    Tools.Warn("CylinderImposter not yet implemented, using BoxImposter instead");
-                case PhysicsEngine.BoxImpostor:
-                    bbox = mesh.getBoundingInfo().boundingBox;
-                    var min = bbox.minimumWorld;
-                    var max = bbox.maximumWorld;
-                    var box = max.subtract(min).scale(0.5);
-                    returnValue = new CANNON.Box(new CANNON.Vec3(this._checkWithEpsilon(box.x), this._checkWithEpsilon(box.y), this._checkWithEpsilon(box.z)));
-                    break;
-                case PhysicsEngine.PlaneImpostor:
-                    Tools.Warn("Attention, Cannon.js PlaneImposter might not behave as you wish. Consider using BoxImposter instead");
-                    returnValue = new CANNON.Plane();
-                    break;
-                case PhysicsEngine.MeshImpostor:
-                    var rawVerts = mesh.getVerticesData(VertexBuffer.PositionKind);
-                    var rawFaces = mesh.getIndices();
-                    Tools.Warn("MeshImpostor only collides against spheres.");
-                    returnValue = new CANNON.Trimesh(rawVerts, rawFaces); //this._createConvexPolyhedron(rawVerts, rawFaces, mesh);
-                    break;
-                case PhysicsEngine.HeightmapImpostor:
-                    returnValue = this._createHeightmap(mesh);
-                    break;
-
-            }
-
-            mesh.rotationQuaternion = oldQuaternion;
-
-            return returnValue;
-        }
-
-        private _createConvexPolyhedron(rawVerts: number[] | Float32Array, rawFaces: number[] | Int32Array, mesh: AbstractMesh): any {
-            var verts = [], faces = [];
-
-            mesh.computeWorldMatrix(true);
-
-            //reuse this variable
-            var transformed = Vector3.Zero();
-            // Get vertices
-            for (var i = 0; i < rawVerts.length; i += 3) {
-                Vector3.TransformNormalFromFloatsToRef(rawVerts[i], rawVerts[i + 1], rawVerts[i + 2], mesh.getWorldMatrix(), transformed);
-                verts.push(new CANNON.Vec3(transformed.x, transformed.y, transformed.z));
-            }
-
-            // Get faces
-            for (var j = 0; j < rawFaces.length; j += 3) {
-                faces.push([rawFaces[j], rawFaces[j + 2], rawFaces[j + 1]]);
-            }
-
-            var shape = new CANNON.ConvexPolyhedron(verts, faces);
-
-            return shape;
-        }
-
-        private _createHeightmap(mesh: AbstractMesh, pointDepth?: number) {
-            var pos = mesh.getVerticesData(VertexBuffer.PositionKind);
-            var matrix = [];
-    
-            //For now pointDepth will not be used and will be automatically calculated.
-            //Future reference - try and find the best place to add a reference to the pointDepth variable.
-            var arraySize = pointDepth || ~~(Math.sqrt(pos.length / 3) - 1);
-
-            var dim = Math.min(mesh.getBoundingInfo().boundingBox.extendSize.x, mesh.getBoundingInfo().boundingBox.extendSize.z);
-
-            var elementSize = dim * 2 / arraySize;
-
-            var minY = mesh.getBoundingInfo().boundingBox.extendSize.y;
-
-            for (var i = 0; i < pos.length; i = i + 3) {
-                var x = Math.round((pos[i + 0]) / elementSize + arraySize / 2);
-                var z = Math.round(((pos[i + 2]) / elementSize - arraySize / 2) * -1);
-                var y = pos[i + 1] + minY;
-                if (!matrix[x]) {
-                    matrix[x] = [];
-                }
-                if (!matrix[x][z]) {
-                    matrix[x][z] = y;
-                }
-                matrix[x][z] = Math.max(y, matrix[x][z]);
-            }
-
-
-            for (var x = 0; x <= arraySize; ++x) {
-                if (!matrix[x]) {
-                    var loc = 1;
-                    while (!matrix[(x + loc) % arraySize]) {
-                        loc++;
-                    }
-                    matrix[x] = matrix[(x + loc) % arraySize].slice();
-                    //console.log("missing x", x);
-                }
-                for (var z = 0; z <= arraySize; ++z) {
-                    if (!matrix[x][z]) {
-                        var loc = 1;
-                        var newValue;
-                        while (newValue === undefined) {
-                            newValue = matrix[x][(z + loc++) % arraySize];
-                        }
-                        matrix[x][z] = newValue;
-
-                    }
-                }
-            }
-
-            var shape = new CANNON.Heightfield(matrix, {
-                elementSize: elementSize
-            });
-            
-            //For future reference, needed for body transformation
-            shape.minY = minY;
-
-            return shape;
-        }
-
-        private _addMaterial(friction: number, restitution: number) {
-            var index;
-            var mat;
-
-            for (index = 0; index < this._physicsMaterials.length; index++) {
-                mat = this._physicsMaterials[index];
-
-                if (mat.friction === friction && mat.restitution === restitution) {
-                    return mat;
-                }
-            }
-
-            var currentMat = new CANNON.Material("mat");
-            this._physicsMaterials.push(currentMat);
-
-            for (index = 0; index < this._physicsMaterials.length; index++) {
-                mat = this._physicsMaterials[index];
-
-                var contactMaterial = new CANNON.ContactMaterial(mat, currentMat, { friction: friction, restitution: restitution });
-
-                this._world.addContactMaterial(contactMaterial);
-            }
-
-            return currentMat;
-        }
-
-        private _createRigidBodyFromShape(shape: any, mesh: AbstractMesh, options: PhysicsImpostorParameters): any {
-            if (!mesh.rotationQuaternion) {
-                mesh.rotationQuaternion = Quaternion.RotationYawPitchRoll(mesh.rotation.y, mesh.rotation.x, mesh.rotation.z);
-            }
-            
-            // The delta between the mesh position and the mesh bounding box center
-            var bbox = mesh.getBoundingInfo().boundingBox;
-            var deltaPosition = mesh.position.subtract(bbox.center);
-            var deltaRotation;
-
-            var material = this._addMaterial(options.friction, options.restitution);
-            var body = new CANNON.Body({
-                mass: options.mass,
-                material: material,
-                position: new CANNON.Vec3(bbox.center.x, bbox.center.y, bbox.center.z)
-            });
-
-            body.quaternion = new CANNON.Quaternion(mesh.rotationQuaternion.x, mesh.rotationQuaternion.y, mesh.rotationQuaternion.z, mesh.rotationQuaternion.w);
-            //is shape is a plane or a heightmap, it must be rotated 90 degs in the X axis.
-            if (shape.type === CANNON.Shape.types.PLANE || shape.type === CANNON.Shape.types.HEIGHTFIELD) {
-                //-90 DEG in X, precalculated
-                var tmpQ = new CANNON.Quaternion(-0.7071067811865475, 0, 0, 0.7071067811865475);
-                body.quaternion = body.quaternion.mult(tmpQ);
-                //Invert! (Precalculated, 90 deg in X)
-                deltaRotation = new Quaternion(0.7071067811865475, 0, 0, 0.7071067811865475);
-            }
-            
-            //If it is a heightfield, if should be centered.
-            if (shape.type === CANNON.Shape.types.HEIGHTFIELD) {
-                
-                //calculate the correct body position:
-                var rotationQuaternion = mesh.rotationQuaternion;
-                mesh.rotationQuaternion = new Quaternion();
-                mesh.computeWorldMatrix(true);
-                
-                //get original center with no rotation
-                var center = mesh.getBoundingInfo().boundingBox.center.clone();
-
-                var oldPivot = mesh.getPivotMatrix() || Matrix.Translation(0, 0, 0);
-                
-                //rotation is back
-                mesh.rotationQuaternion = rotationQuaternion;
-        
-                //calculate the new center using a pivot (since Cannon.js doesn't center height maps)
-                var p = Matrix.Translation(mesh.getBoundingInfo().boundingBox.extendSize.x, 0, -mesh.getBoundingInfo().boundingBox.extendSize.z);
-                mesh.setPivotMatrix(p);
-                mesh.computeWorldMatrix(true);
-        
-                //calculate the translation
-                var translation = mesh.getBoundingInfo().boundingBox.center.subtract(center).subtract(mesh.position).negate();
-
-                body.position = new CANNON.Vec3(translation.x, translation.y - mesh.getBoundingInfo().boundingBox.extendSize.y, translation.z);
-                //add it inverted to the delta 
-                deltaPosition = mesh.getBoundingInfo().boundingBox.center.subtract(center);
-                deltaPosition.y += mesh.getBoundingInfo().boundingBox.extendSize.y;
-
-                mesh.setPivotMatrix(oldPivot);
-                mesh.computeWorldMatrix(true);
-            } else if (shape.type === CANNON.Shape.types.TRIMESH) {
-                deltaPosition = Vector3.Zero();
-            }
-            
-            //add the shape
-            body.addShape(shape);
-
-            this._world.add(body);
-
-            this._registeredMeshes.push({ mesh: mesh, body: body, material: material, delta: deltaPosition, deltaRotation: deltaRotation, type: shape.type });
-
-            return body;
-        }
-
-        public registerMeshesAsCompound(parts: PhysicsCompoundBodyPart[], options: PhysicsBodyCreationOptions): any {
-
-            var initialMesh = parts[0].mesh;
-
-            this.unregisterMesh(initialMesh);
-
-            initialMesh.computeWorldMatrix(true);
-
-            var initialShape = this._createShape(initialMesh, parts[0].impostor);
-            var body = this._createRigidBodyFromShape(initialShape, initialMesh, options);
-
-            for (var index = 1; index < parts.length; index++) {
-                var mesh = parts[index].mesh;
-                mesh.computeWorldMatrix(true);
-                var shape = this._createShape(mesh, parts[index].impostor);
-                var localPosition = mesh.position;
-
-                body.addShape(shape, new CANNON.Vec3(localPosition.x, localPosition.y, localPosition.z));
-            }
-
-            return body;
-        }
-
-        private _unbindBody(body): void {
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-
-                if (registeredMesh.body === body) {
-                    this._world.remove(registeredMesh.body);
-                    registeredMesh.body = null;
-                    registeredMesh.delta = null;
-                    registeredMesh.deltaRotation = null;
-                }
-            }
-        }
-
-        public unregisterMesh(mesh: AbstractMesh): void {
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-
-                if (registeredMesh.mesh === mesh) {
-                    // Remove body
-                    if (registeredMesh.body) {
-                        this._unbindBody(registeredMesh.body);
-                    }
-
-                    this._registeredMeshes.splice(index, 1);
-                    return;
-                }
-            }
-        }
-
-        public applyImpulse(mesh: AbstractMesh, force: Vector3, contactPoint: Vector3): void {
-            var worldPoint = new CANNON.Vec3(contactPoint.x, contactPoint.y, contactPoint.z);
-            var impulse = new CANNON.Vec3(force.x, force.y, force.z);
-
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-
-                if (registeredMesh.mesh === mesh) {
-                    registeredMesh.body.applyImpulse(impulse, worldPoint);
-                    return;
-                }
-            }
-        }
-
-        public updateBodyPosition = function(mesh: AbstractMesh): void {
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-                if (registeredMesh.mesh === mesh || registeredMesh.mesh === mesh.parent) {
-                    var body = registeredMesh.body;
-
-                    var center = mesh.getBoundingInfo().boundingBox.center.clone();
-
-                    body.quaternion.copy(mesh.rotationQuaternion);
-
-                    if (registeredMesh.deltaRotation) {
-                        var tmpQ = new CANNON.Quaternion(-0.7071067811865475, 0, 0, 0.7071067811865475);
-                        body.quaternion = body.quaternion.mult(tmpQ);
-                    }
-
-                    if (registeredMesh.type === CANNON.Shape.types.HEIGHTFIELD) {
-                        //calculate the correct body position:
-                        var rotationQuaternion = mesh.rotationQuaternion;
-                        mesh.rotationQuaternion = new Quaternion();
-                        mesh.computeWorldMatrix(true);
-                        
-                        //get original center with no rotation
-                        var center = mesh.getBoundingInfo().boundingBox.center.clone();
-
-                        var oldPivot = mesh.getPivotMatrix() || Matrix.Translation(0, 0, 0);
-                        
-                        //rotation is back
-                        mesh.rotationQuaternion = rotationQuaternion;
-                
-                        //calculate the new center using a pivot (since Cannon.js doesn't center height maps)
-                        var p = Matrix.Translation(mesh.getBoundingInfo().boundingBox.extendSize.x, 0, -mesh.getBoundingInfo().boundingBox.extendSize.z);
-                        mesh.setPivotMatrix(p);
-                        mesh.computeWorldMatrix(true);
-                
-                        //calculate the translation
-                        var translation = mesh.getBoundingInfo().boundingBox.center.subtract(center).subtract(mesh.position).negate();
-
-                        center.copyFromFloats(translation.x, translation.y - mesh.getBoundingInfo().boundingBox.extendSize.y, translation.z);
-                        //add it inverted to the delta 
-                        registeredMesh.delta = mesh.getBoundingInfo().boundingBox.center.subtract(center);
-                        registeredMesh.delta.y += mesh.getBoundingInfo().boundingBox.extendSize.y;
-
-                        mesh.setPivotMatrix(oldPivot);
-                        mesh.computeWorldMatrix(true);
-                    } else if (registeredMesh.type === CANNON.Shape.types.TRIMESH) {
-                        center.copyFromFloats(mesh.position.x, mesh.position.y, mesh.position.z);
-                    }
-
-                    body.position.set(center.x, center.y, center.z);
-
-                    return;
-                }
-            }
-        }
-
-        public createLink(mesh1: AbstractMesh, mesh2: AbstractMesh, pivot1: Vector3, pivot2: Vector3): boolean {
-            var body1 = null, body2 = null;
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-
-                if (registeredMesh.mesh === mesh1) {
-                    body1 = registeredMesh.body;
-                    if (body2) break;
-                } else if (registeredMesh.mesh === mesh2) {
-                    body2 = registeredMesh.body;
-                    if (body1) break;
-                }
-            }
-
-            if (!body1 || !body2) {
-                return false;
-            }
-
-            var constraint = new CANNON.PointToPointConstraint(body1, new CANNON.Vec3(pivot1.x, pivot1.y, pivot1.z), body2, new CANNON.Vec3(pivot2.x, pivot2.y, pivot2.z));
-            this._world.addConstraint(constraint);
-
-            return true;
-        }
-
-        public dispose(): void {
-            while (this._registeredMeshes.length) {
-                this.unregisterMesh(this._registeredMeshes[0].mesh);
-            }
-        }
-
-        public isSupported(): boolean {
-            return window.CANNON !== undefined;
-        }
-
-        public getWorldObject(): any {
-            return this._world;
-        }
-
-        public getPhysicsBodyOfMesh(mesh: AbstractMesh) {
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-                if (registeredMesh.mesh === mesh) {
-                    return registeredMesh.body;
-                }
-            }
-            return null;
-        }
-    }*/
-
     export class CannonJSPlugin implements IPhysicsEnginePlugin {
 
         public world: any; //CANNON.World
         public name: string = "CannonJSPlugin";
         private _physicsMaterials = [];
         private _fixedTimeStep: number = 1 / 60;
+        //See https://github.com/schteppe/cannon.js/blob/gh-pages/demos/collisionFilter.html
+        private _currentCollisionGroup = 2;
 
         public constructor(private _useDeltaForWorldStep: boolean = true, iterations: number = 10) {
             if (!this.isSupported()) {
@@ -643,6 +143,7 @@
             }
             var constraint;
             var jointData = impostorJoint.joint.jointData;
+            //TODO - https://github.com/schteppe/cannon.js/blob/gh-pages/demos/collisionFilter.html
             var constraintData = {
                 pivotA: jointData.mainPivot ? new CANNON.Vec3().copy(jointData.mainPivot) : null,
                 pivotB: jointData.connectedPivot ? new CANNON.Vec3().copy(jointData.connectedPivot) : null,
@@ -650,6 +151,20 @@
                 axisB: jointData.connectedAxis ? new CANNON.Vec3().copy(jointData.connectedAxis) : null,
                 maxForce: jointData.nativeParams.maxForce
             };
+            if(!jointData.collision) {
+                //add 1st body to a collision group of its own, if it is not in 1
+                if(mainBody.collisionFilterGroup === 1) {
+                    mainBody.collisionFilterGroup = this._currentCollisionGroup;
+                    this._currentCollisionGroup <<= 1;
+                }
+                if(connectedBody.collisionFilterGroup === 1) {
+                    connectedBody.collisionFilterGroup = this._currentCollisionGroup;
+                    this._currentCollisionGroup <<= 1;
+                }
+                //add their mask to the collisionFilterMask of each other:
+                connectedBody.collisionFilterMask = connectedBody.collisionFilterMask | ~mainBody.collisionFilterGroup;
+                mainBody.collisionFilterMask = mainBody.collisionFilterMask | ~connectedBody.collisionFilterGroup;
+            }
             switch (impostorJoint.joint.type) {
                 case PhysicsJoint.HingeJoint:
                     constraint = new CANNON.HingeConstraint(mainBody, connectedBody, constraintData);
@@ -892,6 +407,10 @@
         public isSupported(): boolean {
             return window.CANNON !== undefined;
         }
+        
+        public setVelocity(impostor: PhysicsImpostor, velocity: Vector3) {
+            impostor.physicsBody.velocity.copy(velocity);
+        }
 
         public dispose() {
             //nothing to do, actually.

+ 4 - 3
src/Physics/Plugins/babylon.oimoJSPlugin.js

@@ -185,7 +185,7 @@ var BABYLON;
                 pos2: options.pos2 || (jointData.connectedPivot ? jointData.connectedPivot.asArray() : null),
                 min: options.min,
                 max: options.max,
-                collision: options.collision,
+                collision: options.collision || jointData.collision,
                 spring: options.spring,
                 //supporting older version of Oimo
                 world: this.world
@@ -238,9 +238,7 @@ var BABYLON;
         };
         OimoJSPlugin.prototype.setPhysicsBodyTransformation = function (impostor, newPosition, newRotation) {
             var body = impostor.physicsBody;
-            //if (!newPosition.equalsWithEpsilon(impostor.mesh.position)) {
             body.position.init(newPosition.x * OIMO.INV_SCALE, newPosition.y * OIMO.INV_SCALE, newPosition.z * OIMO.INV_SCALE);
-            //}
             body.orientation.init(newRotation.w, newRotation.x, newRotation.y, newRotation.z);
             body.syncShapes();
             body.awake();
@@ -252,6 +250,9 @@ var BABYLON;
             }
             return lastShape;
         };
+        OimoJSPlugin.prototype.setVelocity = function (impostor, velocity) {
+            impostor.physicsBody.linearVelocity.init(velocity.x, velocity.y, velocity.z);
+        };
         OimoJSPlugin.prototype.dispose = function () {
             this.world.clear();
         };

+ 5 - 412
src/Physics/Plugins/babylon.oimoJSPlugin.ts

@@ -232,7 +232,7 @@ module BABYLON {
 
                 min: options.min,
                 max: options.max,
-                collision: options.collision,
+                collision: options.collision || jointData.collision,
                 spring: options.spring,
                 
                 //supporting older version of Oimo
@@ -292,9 +292,7 @@ module BABYLON {
         public setPhysicsBodyTransformation(impostor: PhysicsImpostor, newPosition: Vector3, newRotation: Quaternion) {
             var body = impostor.physicsBody;
 
-            //if (!newPosition.equalsWithEpsilon(impostor.mesh.position)) {
             body.position.init(newPosition.x * OIMO.INV_SCALE, newPosition.y * OIMO.INV_SCALE, newPosition.z * OIMO.INV_SCALE);
-            //}
             
             body.orientation.init(newRotation.w, newRotation.x, newRotation.y, newRotation.z);
             body.syncShapes();
@@ -308,418 +306,13 @@ module BABYLON {
             }
             return lastShape;
         }
+        
+        public setVelocity(impostor: PhysicsImpostor, velocity: Vector3) {
+            impostor.physicsBody.linearVelocity.init(velocity.x, velocity.y, velocity.z);
+        }
 
         public dispose() {
             this.world.clear();
         }
     }
-
-    /*export class OldOimoJSPlugin {
-        private _world;
-        private _registeredMeshes = [];
-
-        public name = "oimo";
-
-        private _gravity: Vector3;
-
-        private _checkWithEpsilon(value: number): number {
-            return value < PhysicsEngine.Epsilon ? PhysicsEngine.Epsilon : value;
-        }
-
-        public initialize(iterations?: number): void {
-            this._world = new OIMO.World(null, null, iterations);
-            this._world.clear();
-        }
-
-        public setGravity(gravity: Vector3): void {
-            this._gravity = this._world.gravity = gravity;
-        }
-
-        public getGravity(): Vector3 {
-            return this._gravity;
-        }
-
-        public registerMesh(mesh: AbstractMesh, impostor: number, options: PhysicsImpostorParameters): any {
-            this.unregisterMesh(mesh);
-
-            if (!mesh.rotationQuaternion) {
-                mesh.rotationQuaternion = Quaternion.RotationYawPitchRoll(mesh.rotation.y, mesh.rotation.x, mesh.rotation.z);
-            }
-
-            mesh.computeWorldMatrix(true);
-
-            var bbox = mesh.getBoundingInfo().boundingBox;
-
-            // The delta between the mesh position and the mesh bounding box center
-            var deltaPosition = mesh.position.subtract(bbox.center);
-            
-            //calculate rotation to fit Oimo's needs (Euler...)
-            var rot = new OIMO.Euler().setFromQuaternion({ x: mesh.rotationQuaternion.x, y: mesh.rotationQuaternion.y, z: mesh.rotationQuaternion.z, s: mesh.rotationQuaternion.w });
-
-            //get the correct bounding box
-            var oldQuaternion = mesh.rotationQuaternion;
-            mesh.rotationQuaternion = new Quaternion(0, 0, 0, 1);
-            mesh.computeWorldMatrix(true);
-
-            var bodyConfig: any = {
-                name: mesh.uniqueId,
-                //pos: [bbox.center.x, bbox.center.y, bbox.center.z],
-                //rot: [rot.x / OIMO.TO_RAD, rot.y / OIMO.TO_RAD, rot.z / OIMO.TO_RAD],
-                move: options.mass != 0,
-                config: [options.mass, options.friction, options.restitution],
-                type: [],
-                shape: [],
-                pos: [],
-                rot: []
-            };
-
-            // register mesh
-            switch (impostor) {
-                case PhysicsEngine.SphereImpostor:
-                    var radiusX = bbox.maximumWorld.x - bbox.minimumWorld.x;
-                    var radiusY = bbox.maximumWorld.y - bbox.minimumWorld.y;
-                    var radiusZ = bbox.maximumWorld.z - bbox.minimumWorld.z;
-
-                    var size = Math.max(
-                        this._checkWithEpsilon(radiusX),
-                        this._checkWithEpsilon(radiusY),
-                        this._checkWithEpsilon(radiusZ)) / 2;
-
-                    bodyConfig.type = 'sphere';
-                    bodyConfig.size = [size];
-                    break;
-
-                case PhysicsEngine.PlaneImpostor:
-                //Oimo "fakes" a cylinder as a box, so why don't we!
-                case PhysicsEngine.CylinderImpostor:
-                case PhysicsEngine.BoxImpostor:
-
-                    var min = bbox.minimumWorld;
-                    var max = bbox.maximumWorld;
-                    var box = max.subtract(min);
-                    var sizeX = this._checkWithEpsilon(box.x);
-                    var sizeY = this._checkWithEpsilon(box.y);
-                    var sizeZ = this._checkWithEpsilon(box.z);
-
-                    bodyConfig.type = 'box';
-                    bodyConfig.size = [sizeX, sizeY, sizeZ];
-                    break;
-            }
-
-            var body = new OIMO.Body(bodyConfig);
-
-            //We have to access the rigid body's properties to set the quaternion. 
-            //The setQuaternion function of Oimo only sets the newOrientation that is only set after an impulse is given or a collision.
-            //body.body.orientation = new OIMO.Quat(mesh.rotationQuaternion.w, mesh.rotationQuaternion.x, mesh.rotationQuaternion.y, mesh.rotationQuaternion.z);
-            //TEST
-            //body.body.resetQuaternion(new OIMO.Quat(mesh.rotationQuaternion.w, mesh.rotationQuaternion.x, mesh.rotationQuaternion.y, mesh.rotationQuaternion.z));
-            //update the internal rotation matrix
-            //body.body.syncShapes();
-            
-            this._registeredMeshes.push({
-                mesh: mesh,
-                body: body,
-                delta: deltaPosition
-            });
-			
-            //for the sake of consistency.
-            mesh.rotationQuaternion = oldQuaternion;
-
-            return body;
-        }
-
-        public registerMeshesAsCompound(parts: any[], options: PhysicsImpostorParameters): any {
-            var types = [],
-                sizes = [],
-                positions = [],
-                rotations = [];
-
-            var initialMesh = parts[0].mesh;
-
-            for (var index = 0; index < parts.length; index++) {
-                var part = parts[index];
-                var bodyParameters = this._createBodyAsCompound(part, options, initialMesh);
-                types.push(bodyParameters.type);
-                sizes.push.apply(sizes, bodyParameters.size);
-                positions.push.apply(positions, bodyParameters.pos);
-                rotations.push.apply(rotations, bodyParameters.rot);
-            }
-
-            var body = new OIMO.Body({
-                name: initialMesh.uniqueId,
-                type: types,
-                size: sizes,
-                pos: positions,
-                rot: rotations,
-                move: options.mass != 0,
-                config: [options.mass, options.friction, options.restitution],
-                world: this._world
-            });
-            
-            //Reset the body's rotation to be of the initial mesh's.
-            var rot = new OIMO.Euler().setFromQuaternion({ x: initialMesh.rotationQuaternion.x, y: initialMesh.rotationQuaternion.y, z: initialMesh.rotationQuaternion.z, s: initialMesh.rotationQuaternion.w });
-
-            body.resetRotation(rot.x / OIMO.TO_RAD, rot.y / OIMO.TO_RAD, rot.z / OIMO.TO_RAD);
-
-            this._registeredMeshes.push({
-                mesh: initialMesh,
-                body: body
-            });
-
-            return body;
-        }
-
-        private _createBodyAsCompound(part: any, options: PhysicsImpostorParameters, initialMesh: AbstractMesh): any {
-            var mesh = part.mesh;
-
-            if (!mesh.rotationQuaternion) {
-                mesh.rotationQuaternion = Quaternion.RotationYawPitchRoll(mesh.rotation.y, mesh.rotation.x, mesh.rotation.z);
-            }
-			
-            // We need the bounding box/sphere info to compute the physics body
-            mesh.computeWorldMatrix(true);
-
-            var rot = new OIMO.Euler().setFromQuaternion({ x: mesh.rotationQuaternion.x, y: mesh.rotationQuaternion.y, z: mesh.rotationQuaternion.z, s: mesh.rotationQuaternion.w });
-
-            var bodyParameters: any = {
-                name: mesh.uniqueId,
-                pos: [mesh.position.x, mesh.position.y, mesh.position.z],
-                //A bug in Oimo (Body class) prevents us from using rot directly.
-                rot: [0, 0, 0],
-                //For future reference, if the bug will ever be fixed.
-                realRot: [rot.x / OIMO.TO_RAD, rot.y / OIMO.TO_RAD, rot.z / OIMO.TO_RAD]
-            };
-
-            var oldQuaternion = mesh.rotationQuaternion;
-            mesh.rotationQuaternion = new Quaternion(0, 0, 0, 1);
-            mesh.computeWorldMatrix(true);
-
-            switch (part.impostor) {
-                case PhysicsEngine.SphereImpostor:
-                    var bbox = mesh.getBoundingInfo().boundingBox;
-                    var radiusX = bbox.maximumWorld.x - bbox.minimumWorld.x;
-                    var radiusY = bbox.maximumWorld.y - bbox.minimumWorld.y;
-                    var radiusZ = bbox.maximumWorld.z - bbox.minimumWorld.z;
-
-                    var size = Math.max(
-                        this._checkWithEpsilon(radiusX),
-                        this._checkWithEpsilon(radiusY),
-                        this._checkWithEpsilon(radiusZ)) / 2;
-
-                    bodyParameters.type = 'sphere';
-                    bodyParameters.size = [size, size, size];
-
-                    break;
-
-                case PhysicsEngine.PlaneImpostor:
-                case PhysicsEngine.CylinderImpostor:
-                case PhysicsEngine.BoxImpostor:
-                    bbox = mesh.getBoundingInfo().boundingBox;
-                    var min = bbox.minimumWorld;
-                    var max = bbox.maximumWorld;
-                    var box = max.subtract(min);
-                    var sizeX = this._checkWithEpsilon(box.x);
-                    var sizeY = this._checkWithEpsilon(box.y);
-                    var sizeZ = this._checkWithEpsilon(box.z);
-
-                    bodyParameters.type = 'box';
-                    bodyParameters.size = [sizeX, sizeY, sizeZ];
-
-                    break;
-            }
-
-            mesh.rotationQuaternion = oldQuaternion;
-
-            return bodyParameters;
-        }
-
-        public unregisterMesh(mesh: AbstractMesh): void {
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-                if (registeredMesh.mesh === mesh || registeredMesh.mesh === mesh.parent) {
-                    if (registeredMesh.body) {
-                        this._world.removeRigidBody(registeredMesh.body.body);
-                        this._unbindBody(registeredMesh.body);
-                    }
-                    this._registeredMeshes.splice(index, 1);
-                    return;
-                }
-            }
-        }
-
-        private _unbindBody(body: any): void {
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-                if (registeredMesh.body === body) {
-                    registeredMesh.body = null;
-                }
-            }
-        }
-
-        public updateBodyPosition = function(mesh: AbstractMesh): void {
-
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-                var body = registeredMesh.body.body;
-                var updated: boolean = false;
-                var newPosition: Vector3;
-                if (registeredMesh.mesh === mesh || registeredMesh.mesh === mesh.parent) {
-                    mesh.computeWorldMatrix(true);
-
-                    newPosition = mesh.getBoundingInfo().boundingBox.center;
-
-                    updated = true;
-                }
-                // Case where the parent has been updated
-                else if (registeredMesh.mesh.parent === mesh) {
-                    mesh.computeWorldMatrix(true);
-                    registeredMesh.mesh.computeWorldMatrix(true);
-
-                    newPosition = registeredMesh.mesh.getAbsolutePosition();
-
-                    updated = true;
-                }
-
-                if (updated) {
-                    body.setPosition(new OIMO.Vec3(newPosition.x, newPosition.y, newPosition.z));
-                    body.setQuaternion(mesh.rotationQuaternion);
-                    body.sleeping = false;
-                    //force Oimo to update the body's position
-                    body.updatePosition(1);
-                }
-            }
-        }
-
-        public applyImpulse(mesh: AbstractMesh, force: Vector3, contactPoint: Vector3): void {
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-                if (registeredMesh.mesh === mesh || registeredMesh.mesh === mesh.parent) {
-                    // Get object mass to have a behaviour similar to cannon.js
-                    var mass = registeredMesh.body.body.massInfo.mass;
-                    // The force is scaled with the mass of object
-                    registeredMesh.body.body.applyImpulse(contactPoint.scale(OIMO.INV_SCALE), force.scale(OIMO.INV_SCALE * mass));
-                    return;
-                }
-            }
-        }
-
-        public createLink(mesh1: AbstractMesh, mesh2: AbstractMesh, pivot1: Vector3, pivot2: Vector3, options?: any): boolean {
-            var body1 = null,
-                body2 = null;
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-                if (registeredMesh.mesh === mesh1) {
-                    body1 = registeredMesh.body.body;
-                } else if (registeredMesh.mesh === mesh2) {
-                    body2 = registeredMesh.body.body;
-                }
-            }
-            if (!body1 || !body2) {
-                return false;
-            }
-            if (!options) {
-                options = {};
-            }
-
-            new OIMO.Link({
-                type: options.type,
-                body1: body1,
-                body2: body2,
-                min: options.min,
-                max: options.max,
-                axe1: options.axe1,
-                axe2: options.axe2,
-                pos1: [pivot1.x, pivot1.y, pivot1.z],
-                pos2: [pivot2.x, pivot2.y, pivot2.z],
-                collision: options.collision,
-                spring: options.spring,
-                world: this._world
-            });
-
-            return true;
-
-        }
-
-        public dispose(): void {
-            this._world.clear();
-            while (this._registeredMeshes.length) {
-                this.unregisterMesh(this._registeredMeshes[0].mesh);
-            }
-        }
-
-        public isSupported(): boolean {
-            return OIMO !== undefined;
-        }
-
-        public getWorldObject(): any {
-            return this._world;
-        }
-
-        public getPhysicsBodyOfMesh(mesh: AbstractMesh) {
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-                if (registeredMesh.mesh === mesh) {
-                    return registeredMesh.body;
-                }
-            }
-            return null;
-        }
-
-        private _getLastShape(body: any): any {
-            var lastShape = body.shapes;
-            while (lastShape.next) {
-                lastShape = lastShape.next;
-            }
-            return lastShape;
-        }
-
-        public runOneStep(time: number): void {
-            this._world.step();
-
-            // Update the position of all registered meshes
-            var i = this._registeredMeshes.length;
-            var m;
-            while (i--) {
-
-                var body = this._registeredMeshes[i].body.body;
-                var mesh = this._registeredMeshes[i].mesh;
-
-                if (!this._registeredMeshes[i].delta) {
-                    this._registeredMeshes[i].delta = Vector3.Zero();
-                }
-
-                if (!body.sleeping) {
-                    //TODO check that
-                    if (body.shapes.next) {
-                        var parentShape = this._getLastShape(body);
-                        mesh.position.x = parentShape.position.x * OIMO.WORLD_SCALE;
-                        mesh.position.y = parentShape.position.y * OIMO.WORLD_SCALE;
-                        mesh.position.z = parentShape.position.z * OIMO.WORLD_SCALE;
-                    } else {
-                        mesh.position.copyFrom(body.getPosition()).addInPlace(this._registeredMeshes[i].delta);
-
-                    }
-                    mesh.rotationQuaternion.copyFrom(body.getQuaternion());
-                    mesh.computeWorldMatrix();
-                }
-                
-                //check if the collide callback is set. 
-                if (mesh.onPhysicsCollide) {
-                    var meshUniqueName = mesh.uniqueId;
-                    var contact = this._world.contacts;
-                    while (contact !== null) {
-                        //is this body colliding with any other?
-                        if ((contact.body1.name == mesh.uniqueId || contact.body2.name == mesh.uniqueId) && contact.touching && !contact.body1.sleeping && !contact.body2.sleeping) {
-                            var otherUniqueId = contact.body1.name == mesh.uniqueId ? contact.body2.name : contact.body1.name;
-                            //get the mesh and execute the callback
-                            var otherMesh = mesh.getScene().getMeshByUniqueID(otherUniqueId);
-                            if (otherMesh)
-                                mesh.onPhysicsCollide(otherMesh, contact);
-                        }
-                        contact = contact.next;
-                    }
-                }
-            }
-        }
-    }*/
 }

+ 1 - 0
src/Physics/babylon.physicsEngine.ts

@@ -149,6 +149,7 @@
         isSupported(): boolean;
         setTransformationFromPhysicsBody(impostor: PhysicsImpostor);
         setPhysicsBodyTransformation(impostor: PhysicsImpostor, newPosition:Vector3, newRotation: Quaternion);
+        setVelocity(impostor: PhysicsImpostor, velocity: Vector3);
         dispose();
     }
 }

+ 7 - 0
src/Physics/babylon.physicsImpostor.js

@@ -48,6 +48,7 @@ var BABYLON;
             this._options.restitution = (_options.restitution === void 0) ? 0.2 : _options.restitution;
             this._physicsEngine = this._mesh.getScene().getPhysicsEngine();
             this._joints = [];
+            //If the mesh has a parent, don't initialize the physicsBody. Instead wait for the parent to do that.
             if (!this._mesh.parent) {
                 this._init();
             }
@@ -120,6 +121,12 @@ var BABYLON;
             this._options[paramName] = value;
             this._bodyUpdateRequired = true;
         };
+        PhysicsImpostor.prototype.setVelocity = function (velocity) {
+            this._physicsEngine.getPhysicsPlugin().setVelocity(this, velocity);
+        };
+        PhysicsImpostor.prototype.executeNativeFunction = function (func) {
+            func(this._physicsEngine.getPhysicsPlugin().world, this.physicsBody);
+        };
         PhysicsImpostor.prototype.registerBeforePhysicsStep = function (func) {
             this._onBeforePhysicsStepCallbacks.push(func);
         };

+ 20 - 11
src/Physics/babylon.physicsImpostor.ts

@@ -29,7 +29,7 @@ module BABYLON {
             otherImpostor: PhysicsImpostor
         }>;
 
-        constructor(private _mesh: AbstractMesh, public type: number, private _options: PhysicsImpostorParameters = {mass: 0}) {
+        constructor(private _mesh: AbstractMesh, public type: number, private _options: PhysicsImpostorParameters = { mass: 0 }) {
             //default options params
             this._options.mass = (_options.mass === void 0) ? 0 : _options.mass
             this._options.friction = (_options.friction === void 0) ? 0.2 : _options.friction
@@ -37,7 +37,7 @@ module BABYLON {
             this._physicsEngine = this._mesh.getScene().getPhysicsEngine();
             this._joints = [];
             //If the mesh has a parent, don't initialize the physicsBody. Instead wait for the parent to do that.
-            if(!this._mesh.parent) {
+            if (!this._mesh.parent) {
                 this._init();
             }
         }
@@ -48,7 +48,7 @@ module BABYLON {
             this._parent = this._parent || this._getPhysicsParent();
             if (!this.parent) {
                 this._physicsEngine.addImpostor(this);
-            } 
+            }
         }
 
         private _getPhysicsParent(): PhysicsImpostor {
@@ -105,11 +105,20 @@ module BABYLON {
         public getParam(paramName: string) {
             return this._options[paramName];
         }
+
         public setParam(paramName: string, value: number) {
             this._options[paramName] = value;
             this._bodyUpdateRequired = true;
         }
 
+        public setVelocity(velocity: Vector3) {
+            this._physicsEngine.getPhysicsPlugin().setVelocity(this, velocity);
+        }
+        
+        public executeNativeFunction(func: (world: any, physicsBody:any) => void) {
+            func(this._physicsEngine.getPhysicsPlugin().world, this.physicsBody);
+        }
+
         public registerBeforePhysicsStep(func: (impostor: PhysicsImpostor) => void): void {
             this._onBeforePhysicsStepCallbacks.push(func);
         }
@@ -156,14 +165,14 @@ module BABYLON {
         private _tmpRotationWithDelta: Quaternion = new Quaternion();
 
         public beforeStep = () => {
-            
+
             this.mesh.position.subtractToRef(this._deltaPosition, this._tmpPositionWithDelta);
             //conjugate deltaRotation
             this._tmpRotationWithDelta.copyFrom(this._deltaRotation);
             this._tmpRotationWithDelta.multiplyInPlace(this.mesh.rotationQuaternion);
-            
+
             this._physicsEngine.getPhysicsPlugin().setPhysicsBodyTransformation(this, this._tmpPositionWithDelta, this._tmpRotationWithDelta);
-            
+
             this._onBeforePhysicsStepCallbacks.forEach((func) => {
                 func(this);
             });
@@ -173,9 +182,9 @@ module BABYLON {
             this._onAfterPhysicsStepCallbacks.forEach((func) => {
                 func(this);
             });
-            
+
             this._physicsEngine.getPhysicsPlugin().setTransformationFromPhysicsBody(this);
-            
+
             this.mesh.position.addInPlace(this._deltaPosition)
             this.mesh.rotationQuaternion.multiplyInPlace(this._deltaRotation);
         }
@@ -198,7 +207,7 @@ module BABYLON {
             this._physicsEngine.getPhysicsPlugin().applyImpulse(this, force, contactPoint);
         }
 
-        public createJoint(otherImpostor: PhysicsImpostor, jointType:number,  jointData: PhysicsJointData) {
+        public createJoint(otherImpostor: PhysicsImpostor, jointType: number, jointData: PhysicsJointData) {
             var joint = new PhysicsJoint(jointType, jointData);
             this.addJoint(otherImpostor, joint);
         }
@@ -227,11 +236,11 @@ module BABYLON {
                 })
             }
         }
-        
+
         public setDeltaPosition(position: Vector3) {
             this._deltaPosition.copyFrom(position);
         }
-        
+
         public setDeltaRotation(rotation: Quaternion) {
             this._deltaRotation.copyFrom(rotation);
         }

+ 1 - 0
src/Physics/babylon.physicsJoint.ts

@@ -6,6 +6,7 @@ module BABYLON {
         connectedPivot?: Vector3;
         mainAxis?: Vector3,
         connectedAxis?: Vector3,
+        collision?: boolean //native in oimo, needs this - https://github.com/schteppe/cannon.js/blob/gh-pages/demos/collisionFilter.html in cannon
         //Native Oimo/Cannon/Energy data
         nativeParams?: any;
     }