浏览代码

New physics engine plugin system

David Catuhe 11 年之前
父节点
当前提交
77161cd70a

+ 4 - 0
Babylon/LensFlare/babylon.lensFlareSystem.js

@@ -43,6 +43,10 @@
             return this._scene;
         };
 
+        LensFlareSystem.prototype.getEmitter = function () {
+            return this._emitter;
+        };
+
         LensFlareSystem.prototype.getEmitterPosition = function () {
             return this._emitter.getAbsolutePosition ? this._emitter.getAbsolutePosition() : this._emitter.position;
         };

+ 6 - 1
Babylon/Math/babylon.math.js

@@ -237,6 +237,11 @@
             return result;
         };
 
+        Vector2.prototype.copyFrom = function (source) {
+            this.x = source.x;
+            this.y = source.y;
+        };
+
         Vector2.prototype.add = function (otherVector) {
             return new Vector2(this.x + otherVector.x, this.y + otherVector.y);
         };
@@ -1936,7 +1941,7 @@
                 return null;
             }
 
-            return new IntersectionInfo(bu, bv, Vector3.Dot(this._edge2, this._qvec) * invdet);
+            return new BABYLON.IntersectionInfo(bu, bv, Vector3.Dot(this._edge2, this._qvec) * invdet);
         };
 
         // Statics

+ 5 - 0
Babylon/Math/babylon.math.ts

@@ -223,6 +223,11 @@
             return result;
         }
 
+        public copyFrom(source: Vector2): void {
+            this.x = source.x;
+            this.y = source.y;
+        }
+
         public add(otherVector: Vector2): Vector2 {
             return new Vector2(this.x + otherVector.x, this.y + otherVector.y);
         }

+ 35 - 28
Babylon/Mesh/babylon.csg.js

@@ -1,4 +1,4 @@
-var BABYLON;
+var BABYLON;
 (function (BABYLON) {
     // Unique ID when we import meshes from Babylon to CSG
     var currentCSGMeshId = 0;
@@ -116,14 +116,18 @@ var BABYLON;
                     }
                     if (f.length >= 3) {
                         var poly = new Polygon(f, polygon.shared);
+
                         if (poly.plane)
                             front.push(poly);
                     }
+
                     if (b.length >= 3) {
-                        var poly = new Polygon(b, polygon.shared);
+                        poly = new Polygon(b, polygon.shared);
+
                         if (poly.plane)
                             back.push(poly);
                     }
+
                     break;
             }
         };
@@ -348,9 +352,22 @@ var BABYLON;
             return this.polygons;
         };
 
+        CSG.prototype.union = function (csg) {
+            var a = new Node(this.clone().polygons);
+            var b = new Node(csg.clone().polygons);
+            a.clipTo(b);
+            b.clipTo(a);
+            b.invert();
+            b.clipTo(a);
+            b.invert();
+            a.build(b.allPolygons());
+            return CSG.FromPolygons(a.allPolygons()).copyTransformAttributes(this);
+        };
+
         CSG.prototype.unionInPlace = function (csg) {
             var a = new Node(this.polygons);
             var b = new Node(csg.polygons);
+
             a.clipTo(b);
             b.clipTo(a);
             b.invert();
@@ -359,23 +376,26 @@ var BABYLON;
             a.build(b.allPolygons());
 
             this.polygons = a.allPolygons();
-        },
+        };
 
-        CSG.prototype.union = function (csg) {
+        CSG.prototype.subtract = function (csg) {
             var a = new Node(this.clone().polygons);
             var b = new Node(csg.clone().polygons);
+            a.invert();
             a.clipTo(b);
             b.clipTo(a);
             b.invert();
             b.clipTo(a);
             b.invert();
             a.build(b.allPolygons());
+            a.invert();
             return CSG.FromPolygons(a.allPolygons()).copyTransformAttributes(this);
         };
 
         CSG.prototype.subtractInPlace = function (csg) {
             var a = new Node(this.polygons);
             var b = new Node(csg.polygons);
+
             a.invert();
             a.clipTo(b);
             b.clipTo(a);
@@ -384,19 +404,18 @@ var BABYLON;
             b.invert();
             a.build(b.allPolygons());
             a.invert();
-            
+
             this.polygons = a.allPolygons();
-        },
+        };
 
-        CSG.prototype.subtract = function (csg) {
+        CSG.prototype.intersect = function (csg) {
             var a = new Node(this.clone().polygons);
             var b = new Node(csg.clone().polygons);
             a.invert();
-            a.clipTo(b);
             b.clipTo(a);
             b.invert();
+            a.clipTo(b);
             b.clipTo(a);
-            b.invert();
             a.build(b.allPolygons());
             a.invert();
             return CSG.FromPolygons(a.allPolygons()).copyTransformAttributes(this);
@@ -405,6 +424,7 @@ var BABYLON;
         CSG.prototype.intersectInPlace = function (csg) {
             var a = new Node(this.polygons);
             var b = new Node(csg.polygons);
+
             a.invert();
             b.clipTo(a);
             b.invert();
@@ -414,33 +434,20 @@ var BABYLON;
             a.invert();
 
             this.polygons = a.allPolygons();
-        },
-
-        CSG.prototype.intersect = function (csg) {
-            var a = new Node(this.clone().polygons);
-            var b = new Node(csg.clone().polygons);
-            a.invert();
-            b.clipTo(a);
-            b.invert();
-            a.clipTo(b);
-            b.clipTo(a);
-            a.build(b.allPolygons());
-            a.invert();
-            return CSG.FromPolygons(a.allPolygons()).copyTransformAttributes(this);
         };
 
         // Return a new BABYLON.CSG solid with solid and empty space switched. This solid is
         // not modified.
-        CSG.prototype.inverseInPlace = function () {
-            this.polygons.map(function (p) { p.flip(); });
-        }, 
-
         CSG.prototype.inverse = function () {
             var csg = this.clone();
-            csg.polygons.map(function (p) {
+            csg.inverseInPlace();
+            return csg;
+        };
+
+        CSG.prototype.inverseInPlace = function () {
+            this.polygons.map(function (p) {
                 p.flip();
             });
-            return csg;
         };
 
         // This is used to keep meshes transformations so they can be restored

+ 83 - 19
Babylon/Mesh/babylon.csg.ts

@@ -56,7 +56,7 @@
                 return null;
             }
 
-            var n = Vector3.Normalize(Vector3.Cross(c.subtract(a), b.subtract(a)));
+            var n = Vector3.Normalize(Vector3.Cross(v0, v1));
             return new Plane(n, Vector3.Dot(n, a));
         }
 
@@ -65,7 +65,7 @@
         }
 
         public flip() {
-            this.normal = this.normal.scale(-1);
+            this.normal.scaleInPlace(-1);
             this.w = -this.w;
         }
 
@@ -117,8 +117,20 @@
                             b.push(v.clone());
                         }
                     }
-                    if (f.length >= 3) front.push(new Polygon(f, polygon.shared));
-                    if (b.length >= 3) back.push(new Polygon(b, polygon.shared));
+                    if (f.length >= 3) {
+                        var poly = new Polygon(f, polygon.shared);
+
+                        if (poly.plane)
+                            front.push(poly);
+                    }
+
+                    if (b.length >= 3) {
+                        poly = new Polygon(b, polygon.shared);
+
+                        if (poly.plane)
+                            back.push(poly);
+                    }
+
                     break;
             }
         }
@@ -188,7 +200,9 @@
             for (var i = 0; i < this.polygons.length; i++) {
                 this.polygons[i].flip();
             }
-            this.plane.flip();
+            if (this.plane) {
+                this.plane.flip();
+            }
             if (this.front) {
                 this.front.invert();
             }
@@ -295,8 +309,8 @@
                         normal = new BABYLON.Vector3(normals[indices[i + j] * 3], normals[indices[i + j] * 3 + 1], normals[indices[i + j] * 3 + 2]);
                         uv = new BABYLON.Vector2(uvs[indices[i + j] * 2], uvs[indices[i + j] * 2 + 1]);
                         position = new BABYLON.Vector3(positions[indices[i + j] * 3], positions[indices[i + j] * 3 + 1], positions[indices[i + j] * 3 + 2]);
-                        position = BABYLON.Vector3.TransformCoordinates(position, matrix);
-                        normal = BABYLON.Vector3.TransformNormal(normal, matrix);
+                        BABYLON.Vector3.TransformCoordinatesToRef(position, matrix, position);
+                        BABYLON.Vector3.TransformNormalToRef(normal, matrix, normal);
 
                         vertex = new Vertex(position, normal, uv);
                         vertices.push(vertex);
@@ -352,6 +366,20 @@
             return CSG.FromPolygons(a.allPolygons()).copyTransformAttributes(this);
         }
 
+        public unionInPlace(csg: CSG): void {
+            var a = new Node(this.polygons);
+            var b = new Node(csg.polygons);
+
+            a.clipTo(b);
+            b.clipTo(a);
+            b.invert();
+            b.clipTo(a);
+            b.invert();
+            a.build(b.allPolygons());
+
+            this.polygons = a.allPolygons();
+        }
+
         public subtract(csg: CSG): CSG {
             var a = new Node(this.clone().polygons);
             var b = new Node(csg.clone().polygons);
@@ -366,6 +394,22 @@
             return CSG.FromPolygons(a.allPolygons()).copyTransformAttributes(this);
         }
 
+        public subtractInPlace(csg: CSG): void {
+            var a = new Node(this.polygons);
+            var b = new Node(csg.polygons);
+
+            a.invert();
+            a.clipTo(b);
+            b.clipTo(a);
+            b.invert();
+            b.clipTo(a);
+            b.invert();
+            a.build(b.allPolygons());
+            a.invert();
+
+            this.polygons = a.allPolygons();
+        }
+
         public intersect(csg: CSG): CSG {
             var a = new Node(this.clone().polygons);
             var b = new Node(csg.clone().polygons);
@@ -379,14 +423,33 @@
             return CSG.FromPolygons(a.allPolygons()).copyTransformAttributes(this);
         }
 
+        public intersectInPlace(csg: CSG): void {
+            var a = new Node(this.polygons);
+            var b = new Node(csg.polygons);
+
+            a.invert();
+            b.clipTo(a);
+            b.invert();
+            a.clipTo(b);
+            b.clipTo(a);
+            a.build(b.allPolygons());
+            a.invert();
+
+            this.polygons = a.allPolygons();
+        }
+
         // Return a new BABYLON.CSG solid with solid and empty space switched. This solid is
         // not modified.
         public inverse(): CSG {
             var csg = this.clone();
-            csg.polygons.map(p => { p.flip(); });
+            csg.inverseInPlace();
             return csg;
         }
 
+        public inverseInPlace(): void {
+            this.polygons.map(p => { p.flip(); });
+        }
+
         // This is used to keep meshes transformations so they can be restored
         // when we build back a Babylon Mesh
         // NB : All CSG operations are performed in world coordinates
@@ -410,16 +473,18 @@
                 indices = [],
                 normals = [],
                 uvs = [],
-                vertex, normal, uv,
+                vertex = BABYLON.Vector3.Zero(),
+                normal = BABYLON.Vector3.Zero(),
+                uv = BABYLON.Vector2.Zero(),
                 polygons = this.polygons,
-                polygonIndices = [0, 0, 0],
-                polygon,
+                polygonIndices = [0, 0, 0], polygon,
                 vertice_dict = {},
                 vertex_idx,
                 currentIndex = 0,
                 subMesh_dict = {},
                 subMesh_obj;
 
+
             if (keepSubMeshes) {
                 // Sort Polygons, since subMeshes are indices range
                 polygons.sort((a, b) => {
@@ -447,7 +512,6 @@
                 }
                 subMesh_obj = subMesh_dict[polygon.shared.meshId][polygon.shared.subMeshId];
 
-
                 for (var j = 2, jl = polygon.vertices.length; j < jl; j++) {
 
                     polygonIndices[0] = 0;
@@ -455,13 +519,13 @@
                     polygonIndices[2] = j;
 
                     for (var k = 0; k < 3; k++) {
-                        vertex = polygon.vertices[polygonIndices[k]].pos;
-                        normal = polygon.vertices[polygonIndices[k]].normal;
-                        uv = polygon.vertices[polygonIndices[k]].uv;
-                        vertex = new BABYLON.Vector3(vertex.x, vertex.y, vertex.z);
-                        normal = new BABYLON.Vector3(normal.x, normal.y, normal.z);
-                        vertex = BABYLON.Vector3.TransformCoordinates(vertex, matrix);
-                        normal = BABYLON.Vector3.TransformNormal(normal, matrix);
+                        vertex.copyFrom(polygon.vertices[polygonIndices[k]].pos);
+                        normal.copyFrom(polygon.vertices[polygonIndices[k]].normal);
+                        uv.copyFrom(polygon.vertices[polygonIndices[k]].uv);
+                        BABYLON.Vector3.TransformCoordinatesToRef(vertex, matrix, vertex);
+                        BABYLON.Vector3.TransformNormalToRef(normal, matrix, normal);
+
+
 
                         vertex_idx = vertice_dict[vertex.x + ',' + vertex.y + ',' + vertex.z];
 

+ 14 - 8
Babylon/Mesh/babylon.mesh.js

@@ -876,7 +876,7 @@ var BABYLON;
 
             // Physics
             if (this.getPhysicsImpostor() != BABYLON.PhysicsEngine.NoImpostor) {
-                this.setPhysicsState({ impostor: BABYLON.PhysicsEngine.NoImpostor });
+                this.setPhysicsState(BABYLON.PhysicsEngine.NoImpostor);
             }
 
             // Remove from scene
@@ -917,29 +917,35 @@ var BABYLON;
         };
 
         // Physics
-        Mesh.prototype.setPhysicsState = function (options) {
+        Mesh.prototype.setPhysicsState = function (impostor, options) {
             var physicsEngine = this.getScene().getPhysicsEngine();
 
             if (!physicsEngine) {
                 return;
             }
 
-            options.impostor = options.impostor || BABYLON.PhysicsEngine.NoImpostor;
+            if (impostor.impostor) {
+                // Old API
+                options = impostor;
+                impostor = impostor.impostor;
+            }
+
+            impostor = impostor || BABYLON.PhysicsEngine.NoImpostor;
             options.mass = options.mass || 0;
             options.friction = options.friction || 0.2;
             options.restitution = options.restitution || 0.9;
 
-            this._physicImpostor = options.impostor;
+            this._physicImpostor = impostor;
             this._physicsMass = options.mass;
             this._physicsFriction = options.friction;
             this._physicRestitution = options.restitution;
 
-            if (options.impostor === BABYLON.PhysicsEngine.NoImpostor) {
+            if (impostor === BABYLON.PhysicsEngine.NoImpostor) {
                 physicsEngine._unregisterMesh(this);
                 return;
             }
 
-            physicsEngine._registerMesh(this, options);
+            physicsEngine._registerMesh(this, impostor, options);
         };
 
         Mesh.prototype.getPhysicsImpostor = function () {
@@ -1172,8 +1178,8 @@ var BABYLON;
 
         // Tools
         Mesh.MinMax = function (meshes) {
-            var minVector;
-            var maxVector;
+            var minVector = null;
+            var maxVector = null;
             for (var i in meshes) {
                 var mesh = meshes[i];
                 var boundingBox = mesh.getBoundingInfo().boundingBox;

+ 18 - 12
Babylon/Mesh/babylon.mesh.ts

@@ -45,10 +45,10 @@
         private _absolutePosition = BABYLON.Vector3.Zero();
 
         // Physics
-        private _physicImpostor = PhysicsEngine.NoImpostor;
-        private _physicsMass: number;
-        private _physicsFriction: number;
-        private _physicRestitution: number;
+        public _physicImpostor = PhysicsEngine.NoImpostor;
+        public _physicsMass: number;
+        public _physicsFriction: number;
+        public _physicRestitution: number;
 
         // Private
         private _boundingInfo: BoundingInfo;
@@ -894,7 +894,7 @@
 
             // Physics
             if (this.getPhysicsImpostor() != PhysicsEngine.NoImpostor) {
-                this.setPhysicsState({ impostor: PhysicsEngine.NoImpostor });
+                this.setPhysicsState(PhysicsEngine.NoImpostor);
             }
 
             // Remove from scene
@@ -936,29 +936,35 @@
         }
 
         // Physics
-        public setPhysicsState(options): void {
+        public setPhysicsState(impostor?: any, options?: PhysicsBodyCreationOptions): void {
             var physicsEngine = this.getScene().getPhysicsEngine();
 
             if (!physicsEngine) {
                 return;
             }
 
-            options.impostor = options.impostor || PhysicsEngine.NoImpostor;
+            if (impostor.impostor) {
+                // Old API
+                options = impostor;
+                impostor = impostor.impostor;
+            }
+
+            impostor = impostor || PhysicsEngine.NoImpostor;
             options.mass = options.mass || 0;
             options.friction = options.friction || 0.2;
             options.restitution = options.restitution || 0.9;
 
-            this._physicImpostor = options.impostor;
+            this._physicImpostor = impostor;
             this._physicsMass = options.mass;
             this._physicsFriction = options.friction;
             this._physicRestitution = options.restitution;
 
-            if (options.impostor === BABYLON.PhysicsEngine.NoImpostor) {
+            if (impostor === BABYLON.PhysicsEngine.NoImpostor) {
                 physicsEngine._unregisterMesh(this);
                 return;
             }
 
-            physicsEngine._registerMesh(this, options);
+            physicsEngine._registerMesh(this, impostor, options);
         }
 
         public getPhysicsImpostor(): number {
@@ -1194,8 +1200,8 @@
 
         // Tools
         public static MinMax(meshes: Mesh[]): {min: Vector3; max: Vector3} {
-            var minVector;
-            var maxVector;
+            var minVector = null;
+            var maxVector = null;
             for (var i in meshes) {
                 var mesh = meshes[i];
                 var boundingBox = mesh.getBoundingInfo().boundingBox;

+ 290 - 0
Babylon/Physics/Plugins/babylon.cannonJSPlugin.js

@@ -0,0 +1,290 @@
+var BABYLON;
+(function (BABYLON) {
+    var CannonJSPlugin = (function () {
+        function CannonJSPlugin() {
+            this._registeredMeshes = [];
+            this._physicsMaterials = [];
+        }
+        CannonJSPlugin.prototype.initialize = function (iterations) {
+            if (typeof iterations === "undefined") { iterations = 10; }
+            this._world = new CANNON.World();
+            this._world.broadphase = new CANNON.NaiveBroadphase();
+            this._world.solver.iterations = iterations;
+        };
+
+        CannonJSPlugin.prototype._checkWithEpsilon = function (value) {
+            return value < BABYLON.PhysicsEngine.Epsilon ? BABYLON.PhysicsEngine.Epsilon : value;
+        };
+
+        CannonJSPlugin.prototype.runOneStep = function (delta) {
+            this._world.step(delta);
+
+            for (var index = 0; index < this._registeredMeshes.length; index++) {
+                var registeredMesh = this._registeredMeshes[index];
+
+                if (registeredMesh.isChild) {
+                    continue;
+                }
+
+                registeredMesh.mesh.position.x = registeredMesh.body.position.x;
+                registeredMesh.mesh.position.y = registeredMesh.body.position.z;
+                registeredMesh.mesh.position.z = registeredMesh.body.position.y;
+
+                if (!registeredMesh.mesh.rotationQuaternion) {
+                    registeredMesh.mesh.rotationQuaternion = new BABYLON.Quaternion(0, 0, 0, 1);
+                }
+
+                registeredMesh.mesh.rotationQuaternion.x = registeredMesh.body.quaternion.x;
+                registeredMesh.mesh.rotationQuaternion.y = registeredMesh.body.quaternion.z;
+                registeredMesh.mesh.rotationQuaternion.z = registeredMesh.body.quaternion.y;
+                registeredMesh.mesh.rotationQuaternion.w = -registeredMesh.body.quaternion.w;
+            }
+        };
+
+        CannonJSPlugin.prototype.setGravity = function (gravity) {
+            this._world.gravity.set(gravity.x, gravity.z, gravity.y);
+        };
+
+        CannonJSPlugin.prototype.registerMesh = function (mesh, impostor, options) {
+            this.unregisterMesh(mesh);
+
+            mesh.computeWorldMatrix(true);
+
+            switch (impostor) {
+                case BABYLON.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;
+
+                    return this._createSphere(Math.max(this._checkWithEpsilon(radiusX), this._checkWithEpsilon(radiusY), this._checkWithEpsilon(radiusZ)) / 2, mesh, options);
+                case BABYLON.PhysicsEngine.BoxImpostor:
+                    bbox = mesh.getBoundingInfo().boundingBox;
+                    var min = bbox.minimumWorld;
+                    var max = bbox.maximumWorld;
+                    var box = max.subtract(min).scale(0.5);
+                    return this._createBox(this._checkWithEpsilon(box.x), this._checkWithEpsilon(box.z), this._checkWithEpsilon(box.y), mesh, options);
+                case BABYLON.PhysicsEngine.PlaneImpostor:
+                    return this._createPlane(mesh, options);
+                case BABYLON.PhysicsEngine.MeshImpostor:
+                    var rawVerts = mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind);
+                    var rawFaces = mesh.getIndices();
+
+                    return this._createConvexPolyhedron(rawVerts, rawFaces, mesh, options);
+            }
+
+            return null;
+        };
+
+        CannonJSPlugin.prototype._createSphere = function (radius, mesh, options) {
+            var shape = new CANNON.Sphere(radius);
+
+            if (!options) {
+                return shape;
+            }
+
+            return this._createRigidBodyFromShape(shape, mesh, options.mass, options.friction, options.restitution);
+        };
+
+        CannonJSPlugin.prototype._createBox = function (x, y, z, mesh, options) {
+            var shape = new CANNON.Box(new CANNON.Vec3(x, z, y));
+
+            if (!options) {
+                return shape;
+            }
+
+            return this._createRigidBodyFromShape(shape, mesh, options.mass, options.friction, options.restitution);
+        };
+
+        CannonJSPlugin.prototype._createPlane = function (mesh, options) {
+            var shape = new CANNON.Plane();
+
+            if (!options) {
+                return shape;
+            }
+
+            return this._createRigidBodyFromShape(shape, mesh, options.mass, options.friction, options.restitution);
+        };
+
+        CannonJSPlugin.prototype._createConvexPolyhedron = function (rawVerts, rawFaces, mesh, options) {
+            var verts = [], faces = [];
+
+            mesh.computeWorldMatrix(true);
+
+            for (var i = 0; i < rawVerts.length; i += 3) {
+                var transformed = BABYLON.Vector3.Zero();
+
+                BABYLON.Vector3.TransformNormalFromFloatsToRef(rawVerts[i], rawVerts[i + 1], rawVerts[i + 2], mesh.getWorldMatrix(), transformed);
+                verts.push(new CANNON.Vec3(transformed.x, transformed.z, transformed.y));
+            }
+
+            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);
+
+            if (!options) {
+                return shape;
+            }
+
+            return this._createRigidBodyFromShape(shape, mesh, options.mass, options.friction, options.restitution);
+        };
+
+        CannonJSPlugin.prototype._addMaterial = function (friction, restitution) {
+            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();
+            currentMat.friction = friction;
+            currentMat.restitution = restitution;
+            this._physicsMaterials.push(currentMat);
+
+            for (index = 0; index < this._physicsMaterials.length; index++) {
+                mat = this._physicsMaterials[index];
+
+                var contactMaterial = new CANNON.ContactMaterial(mat, currentMat, mat.friction * currentMat.friction, mat.restitution * currentMat.restitution);
+                contactMaterial.contactEquationStiffness = 1e10;
+                contactMaterial.contactEquationRegularizationTime = 10;
+
+                this._world.addContactMaterial(contactMaterial);
+            }
+
+            return currentMat;
+        };
+
+        CannonJSPlugin.prototype._createRigidBodyFromShape = function (shape, mesh, mass, friction, restitution) {
+            var initialRotation = null;
+
+            if (mesh.rotationQuaternion) {
+                initialRotation = mesh.rotationQuaternion.clone();
+                mesh.rotationQuaternion = new BABYLON.Quaternion(0, 0, 0, 1);
+            }
+
+            var material = this._addMaterial(friction, restitution);
+            var body = new CANNON.RigidBody(mass, shape, material);
+
+            if (initialRotation) {
+                body.quaternion.x = initialRotation.x;
+                body.quaternion.z = initialRotation.y;
+                body.quaternion.y = initialRotation.z;
+                body.quaternion.w = -initialRotation.w;
+            }
+
+            body.position.set(mesh.position.x, mesh.position.z, mesh.position.y);
+            this._world.add(body);
+
+            this._registeredMeshes.push({ mesh: mesh, body: body, material: material });
+
+            return body;
+        };
+
+        CannonJSPlugin.prototype.registerMeshesAsCompound = function (parts, options) {
+            var compoundShape = new CANNON.Compound();
+
+            for (var index = 0; index < parts.length; index++) {
+                var mesh = parts[index].mesh;
+
+                var shape = this.registerMesh(mesh, parts[index].impostor);
+
+                if (index == 0) {
+                    compoundShape.addChild(shape, new CANNON.Vec3(0, 0, 0));
+                } else {
+                    compoundShape.addChild(shape, new CANNON.Vec3(mesh.position.x, mesh.position.z, mesh.position.y));
+                }
+            }
+
+            var initialMesh = parts[0].mesh;
+            var body = this._createRigidBodyFromShape(compoundShape, initialMesh, options.mass, options.friction, options.restitution);
+
+            body.parts = parts;
+
+            return body;
+        };
+
+        CannonJSPlugin.prototype._unbindBody = function (body) {
+            for (var index = 0; index < this._registeredMeshes.length; index++) {
+                var registeredMesh = this._registeredMeshes[index];
+
+                if (registeredMesh.body === body) {
+                    registeredMesh.body = null;
+                }
+            }
+        };
+
+        CannonJSPlugin.prototype.unregisterMesh = function (mesh) {
+            for (var index = 0; index < this._registeredMeshes.length; index++) {
+                var registeredMesh = this._registeredMeshes[index];
+
+                if (registeredMesh.mesh === mesh) {
+                    // Remove body
+                    if (registeredMesh.body) {
+                        this._world.remove(registeredMesh.body);
+
+                        this._unbindBody(registeredMesh.body);
+                    }
+
+                    this._registeredMeshes.splice(index, 1);
+                    return;
+                }
+            }
+        };
+
+        CannonJSPlugin.prototype.applyImpulse = function (mesh, force, contactPoint) {
+            var worldPoint = new CANNON.Vec3(contactPoint.x, contactPoint.z, contactPoint.y);
+            var impulse = new CANNON.Vec3(force.x, force.z, force.y);
+
+            for (var index = 0; index < this._registeredMeshes.length; index++) {
+                var registeredMesh = this._registeredMeshes[index];
+
+                if (registeredMesh.mesh === mesh) {
+                    registeredMesh.body.applyImpulse(impulse, worldPoint);
+                    return;
+                }
+            }
+        };
+
+        CannonJSPlugin.prototype.createLink = function (mesh1, mesh2, pivot1, pivot2) {
+            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;
+                } else if (registeredMesh.mesh === mesh2) {
+                    body2 = registeredMesh.body;
+                }
+            }
+
+            if (!body1 || !body2) {
+                return false;
+            }
+
+            var constraint = new CANNON.PointToPointConstraint(body1, new CANNON.Vec3(pivot1.x, pivot1.z, pivot1.y), body2, new CANNON.Vec3(pivot2.x, pivot2.z, pivot2.y));
+            this._world.addConstraint(constraint);
+
+            return true;
+        };
+
+        CannonJSPlugin.prototype.dispose = function () {
+            while (this._registeredMeshes.length) {
+                this.unregisterMesh(this._registeredMeshes[0].mesh);
+            }
+        };
+
+        CannonJSPlugin.prototype.isSupported = function () {
+            return window.CANNON !== undefined;
+        };
+        return CannonJSPlugin;
+    })();
+    BABYLON.CannonJSPlugin = CannonJSPlugin;
+})(BABYLON || (BABYLON = {}));
+//# sourceMappingURL=babylon.cannonJSPlugin.js.map

+ 292 - 0
Babylon/Physics/Plugins/babylon.cannonJSPlugin.ts

@@ -0,0 +1,292 @@
+module BABYLON {
+    declare var CANNON;
+    declare var window;
+
+    export class CannonJSPlugin {
+        public checkWithEpsilon: (value: number) => number;
+
+        private _world: any;
+        private _registeredMeshes = [];
+        private _physicsMaterials = [];
+
+        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 < BABYLON.PhysicsEngine.Epsilon ? BABYLON.PhysicsEngine.Epsilon : value;
+        }
+
+        public runOneStep(delta: number): void {
+            this._world.step(delta);
+
+            for (var index = 0; index < this._registeredMeshes.length; index++) {
+                var registeredMesh = this._registeredMeshes[index];
+
+                if (registeredMesh.isChild) {
+                    continue;
+                }
+
+                registeredMesh.mesh.position.x = registeredMesh.body.position.x;
+                registeredMesh.mesh.position.y = registeredMesh.body.position.z;
+                registeredMesh.mesh.position.z = registeredMesh.body.position.y;
+
+                if (!registeredMesh.mesh.rotationQuaternion) {
+                    registeredMesh.mesh.rotationQuaternion = new BABYLON.Quaternion(0, 0, 0, 1);
+                }
+
+                registeredMesh.mesh.rotationQuaternion.x = registeredMesh.body.quaternion.x;
+                registeredMesh.mesh.rotationQuaternion.y = registeredMesh.body.quaternion.z;
+                registeredMesh.mesh.rotationQuaternion.z = registeredMesh.body.quaternion.y;
+                registeredMesh.mesh.rotationQuaternion.w = -registeredMesh.body.quaternion.w;
+            }
+        }
+
+        public setGravity(gravity: Vector3): void {
+            this._world.gravity.set(gravity.x, gravity.z, gravity.y);
+        }
+
+        public registerMesh(mesh: Mesh, impostor: number, options?: PhysicsBodyCreationOptions): any {
+            this.unregisterMesh(mesh);
+
+            mesh.computeWorldMatrix(true);
+
+            switch (impostor) {
+                case BABYLON.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;
+
+                    return this._createSphere(Math.max(this._checkWithEpsilon(radiusX), this._checkWithEpsilon(radiusY), this._checkWithEpsilon(radiusZ)) / 2, mesh, options);
+                case BABYLON.PhysicsEngine.BoxImpostor:
+                    bbox = mesh.getBoundingInfo().boundingBox;
+                    var min = bbox.minimumWorld;
+                    var max = bbox.maximumWorld;
+                    var box = max.subtract(min).scale(0.5);
+                    return this._createBox(this._checkWithEpsilon(box.x), this._checkWithEpsilon(box.z), this._checkWithEpsilon(box.y), mesh, options);
+                case BABYLON.PhysicsEngine.PlaneImpostor:
+                    return this._createPlane(mesh, options);
+                case BABYLON.PhysicsEngine.MeshImpostor:
+                    var rawVerts = mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind);
+                    var rawFaces = mesh.getIndices();
+
+                    return this._createConvexPolyhedron(rawVerts, rawFaces, mesh, options);
+            }
+
+            return null;
+        }
+
+        private _createSphere(radius: number, mesh: Mesh, options?: PhysicsBodyCreationOptions): any {
+            var shape = new CANNON.Sphere(radius);
+
+            if (!options) {
+                return shape;
+            }
+
+            return this._createRigidBodyFromShape(shape, mesh, options.mass, options.friction, options.restitution);
+        }
+
+        private _createBox(x: number, y: number, z: number, mesh: Mesh, options?: PhysicsBodyCreationOptions): any {
+            var shape = new CANNON.Box(new CANNON.Vec3(x, z, y));
+
+            if (!options) {
+                return shape;
+            }
+
+            return this._createRigidBodyFromShape(shape, mesh, options.mass, options.friction, options.restitution);
+        }
+
+        private _createPlane(mesh: Mesh, options?: PhysicsBodyCreationOptions): any {
+            var shape = new CANNON.Plane();
+
+            if (!options) {
+                return shape;
+            }
+
+            return this._createRigidBodyFromShape(shape, mesh, options.mass, options.friction, options.restitution);
+        }
+
+        private _createConvexPolyhedron(rawVerts: number[], rawFaces: number[], mesh: Mesh, options?: PhysicsBodyCreationOptions): any {
+            var verts = [], faces = [];
+
+            mesh.computeWorldMatrix(true);
+
+            // Get vertices
+            for (var i = 0; i < rawVerts.length; i += 3) {
+                var transformed = BABYLON.Vector3.Zero();
+
+                BABYLON.Vector3.TransformNormalFromFloatsToRef(rawVerts[i], rawVerts[i + 1], rawVerts[i + 2], mesh.getWorldMatrix(), transformed);
+                verts.push(new CANNON.Vec3(transformed.x, transformed.z, transformed.y));
+            }
+
+            // 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);
+
+            if (!options) {
+                return shape;
+            }
+
+            return this._createRigidBodyFromShape(shape, mesh, options.mass, options.friction, options.restitution);
+        }
+
+        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();
+            currentMat.friction = friction;
+            currentMat.restitution = restitution;
+            this._physicsMaterials.push(currentMat);
+
+            for (index = 0; index < this._physicsMaterials.length; index++) {
+                mat = this._physicsMaterials[index];
+
+                var contactMaterial = new CANNON.ContactMaterial(mat, currentMat, mat.friction * currentMat.friction, mat.restitution * currentMat.restitution);
+                contactMaterial.contactEquationStiffness = 1e10;
+                contactMaterial.contactEquationRegularizationTime = 10;
+
+                this._world.addContactMaterial(contactMaterial);
+            }
+
+            return currentMat;
+        }
+
+        private _createRigidBodyFromShape(shape: any, mesh: Mesh, mass: number, friction: number, restitution: number): any {
+            var initialRotation: Quaternion = null;
+
+            if (mesh.rotationQuaternion) {
+                initialRotation = mesh.rotationQuaternion.clone();
+                mesh.rotationQuaternion = new BABYLON.Quaternion(0, 0, 0, 1);
+            }
+
+            var material = this._addMaterial(friction, restitution);
+            var body = new CANNON.RigidBody(mass, shape, material);
+
+            if (initialRotation) {
+                body.quaternion.x = initialRotation.x;
+                body.quaternion.z = initialRotation.y;
+                body.quaternion.y = initialRotation.z;
+                body.quaternion.w = -initialRotation.w;
+            }
+
+            body.position.set(mesh.position.x, mesh.position.z, mesh.position.y);
+            this._world.add(body);
+
+            this._registeredMeshes.push({ mesh: mesh, body: body, material: material });
+
+            return body;
+        }
+
+        public registerMeshesAsCompound(parts: PhysicsCompoundBodyPart[], options: PhysicsBodyCreationOptions): any {
+            var compoundShape = new CANNON.Compound();
+
+            for (var index = 0; index < parts.length; index++) {
+                var mesh = parts[index].mesh;
+
+                var shape = this.registerMesh(mesh, parts[index].impostor);
+
+                if (index == 0) { // Parent
+                    compoundShape.addChild(shape, new CANNON.Vec3(0, 0, 0));
+                } else {
+                    compoundShape.addChild(shape, new CANNON.Vec3(mesh.position.x, mesh.position.z, mesh.position.y));
+                }
+            }
+
+            var initialMesh = parts[0].mesh;
+            var body = this._createRigidBodyFromShape(compoundShape, initialMesh, options.mass, options.friction, options.restitution);
+
+            body.parts = parts;
+
+            return body;
+        }
+
+        private _unbindBody(body): void {
+            for (var index = 0; index < this._registeredMeshes.length; index++) {
+                var registeredMesh = this._registeredMeshes[index];
+
+                if (registeredMesh.body === body) {
+                    registeredMesh.body = null;
+                }
+            }
+        }
+
+        public unregisterMesh(mesh: Mesh): 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._world.remove(registeredMesh.body);
+
+                        this._unbindBody(registeredMesh.body);
+                    }
+
+                    this._registeredMeshes.splice(index, 1);
+                    return;
+                }
+            }
+        }
+
+        public applyImpulse(mesh: Mesh, force: Vector3, contactPoint: Vector3): void {
+            var worldPoint = new CANNON.Vec3(contactPoint.x, contactPoint.z, contactPoint.y);
+            var impulse = new CANNON.Vec3(force.x, force.z, force.y);
+
+            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 createLink(mesh1: Mesh, mesh2: Mesh, 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;
+                } else if (registeredMesh.mesh === mesh2) {
+                    body2 = registeredMesh.body;
+                }
+            }
+
+            if (!body1 || !body2) {
+                return false;
+            }
+
+            var constraint = new CANNON.PointToPointConstraint(body1, new CANNON.Vec3(pivot1.x, pivot1.z, pivot1.y), body2, new CANNON.Vec3(pivot2.x, pivot2.z, pivot2.y));
+            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;
+        }
+    }
+}

+ 19 - 231
Babylon/Physics/babylon.physicsEngine.js

@@ -1,15 +1,14 @@
 var BABYLON;
 (function (BABYLON) {
     var PhysicsEngine = (function () {
-        function PhysicsEngine(gravity, iterations) {
-            this.gravity = gravity;
-            this._world = new CANNON.World();
-            this._registeredMeshes = [];
-            this._physicsMaterials = [];
-            this._world.broadphase = new CANNON.NaiveBroadphase();
-            this._world.solver.iterations = iterations;
-            this._setGravity(gravity);
+        function PhysicsEngine(plugin) {
+            this._currentPlugin = plugin || new BABYLON.CannonJSPlugin();
         }
+        PhysicsEngine.prototype._initialize = function (gravity) {
+            this._currentPlugin.initialize();
+            this._setGravity(gravity);
+        };
+
         PhysicsEngine.prototype._runOneStep = function (delta) {
             if (delta > 0.1) {
                 delta = 0.1;
@@ -17,251 +16,40 @@
                 delta = 1.0 / 60.0;
             }
 
-            this._world.step(delta);
-
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-
-                if (registeredMesh.isChild) {
-                    continue;
-                }
-
-                registeredMesh.mesh.position.x = registeredMesh.body.position.x;
-                registeredMesh.mesh.position.y = registeredMesh.body.position.z;
-                registeredMesh.mesh.position.z = registeredMesh.body.position.y;
-
-                if (!registeredMesh.mesh.rotationQuaternion) {
-                    registeredMesh.mesh.rotationQuaternion = new BABYLON.Quaternion(0, 0, 0, 1);
-                }
-
-                registeredMesh.mesh.rotationQuaternion.x = registeredMesh.body.quaternion.x;
-                registeredMesh.mesh.rotationQuaternion.y = registeredMesh.body.quaternion.z;
-                registeredMesh.mesh.rotationQuaternion.z = registeredMesh.body.quaternion.y;
-                registeredMesh.mesh.rotationQuaternion.w = -registeredMesh.body.quaternion.w;
-            }
-        };
-
-        PhysicsEngine.prototype._addMaterial = function (friction, restitution) {
-            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();
-            currentMat.friction = friction;
-            currentMat.restitution = restitution;
-            this._physicsMaterials.push(currentMat);
-
-            for (index = 0; index < this._physicsMaterials.length; index++) {
-                mat = this._physicsMaterials[index];
-
-                var contactMaterial = new CANNON.ContactMaterial(mat, currentMat, mat.friction * currentMat.friction, mat.restitution * currentMat.restitution);
-                contactMaterial.contactEquationStiffness = 1e10;
-                contactMaterial.contactEquationRegularizationTime = 10;
-
-                this._world.addContactMaterial(contactMaterial);
-            }
-
-            return currentMat;
+            this._currentPlugin.runOneStep(delta);
         };
 
         PhysicsEngine.prototype._setGravity = function (gravity) {
             this.gravity = gravity || new BABYLON.Vector3(0, -9.82, 0);
-            this._world.gravity.set(this.gravity.x, this.gravity.z, this.gravity.y);
+            this._currentPlugin.setGravity(this.gravity);
         };
 
-        PhysicsEngine.prototype._checkWithEpsilon = function (value) {
-            return value < BABYLON.PhysicsEngine.Epsilon ? BABYLON.PhysicsEngine.Epsilon : value;
+        PhysicsEngine.prototype._registerMesh = function (mesh, impostor, options) {
+            return this._currentPlugin.registerMesh(mesh, impostor, options);
         };
 
-        PhysicsEngine.prototype._registerMesh = function (mesh, options, onlyShape) {
-            var shape = null;
-            var initialRotation;
-
-            if (mesh.rotationQuaternion) {
-                initialRotation = mesh.rotationQuaternion.clone();
-                mesh.rotationQuaternion = new BABYLON.Quaternion(0, 0, 0, 1);
-            }
-
-            this._unregisterMesh(mesh);
-
-            mesh.computeWorldMatrix(true);
-
-            switch (options.impostor) {
-                case BABYLON.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;
-
-                    shape = new CANNON.Sphere(Math.max(this._checkWithEpsilon(radiusX), this._checkWithEpsilon(radiusY), this._checkWithEpsilon(radiusZ)) / 2);
-                    break;
-                case BABYLON.PhysicsEngine.BoxImpostor:
-                    bbox = mesh.getBoundingInfo().boundingBox;
-                    var min = bbox.minimumWorld;
-                    var max = bbox.maximumWorld;
-                    var box = max.subtract(min).scale(0.5);
-                    shape = new CANNON.Box(new CANNON.Vec3(this._checkWithEpsilon(box.x), this._checkWithEpsilon(box.z), this._checkWithEpsilon(box.y)));
-                    break;
-                case BABYLON.PhysicsEngine.PlaneImpostor:
-                    shape = new CANNON.Plane();
-                    break;
-                case BABYLON.PhysicsEngine.MeshImpostor:
-                    var rawVerts = mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind);
-                    var rawFaces = mesh.getIndices();
-
-                    var verts = [], faces = [];
-
-                    mesh.computeWorldMatrix(true);
-
-                    for (var i = 0; i < rawVerts.length; i += 3) {
-                        var transformed = BABYLON.Vector3.Zero();
-
-                        BABYLON.Vector3.TransformNormalFromFloatsToRef(rawVerts[i], rawVerts[i + 1], rawVerts[i + 2], mesh.getWorldMatrix(), transformed);
-                        verts.push(new CANNON.Vec3(transformed.x, transformed.z, transformed.y));
-                    }
-
-                    for (var j = 0; j < rawFaces.length; j += 3) {
-                        faces.push([rawFaces[j], rawFaces[j + 2], rawFaces[j + 1]]);
-                    }
-
-                    // Construct polyhedron
-                    shape = new CANNON.ConvexPolyhedron(verts, faces);
-                    break;
-            }
-
-            if (onlyShape) {
-                return shape;
-            }
-
-            var material = this._addMaterial(options.friction, options.restitution);
-            var body = new CANNON.RigidBody(options.mass, shape, material);
-
-            if (initialRotation) {
-                body.quaternion.x = initialRotation.x;
-                body.quaternion.z = initialRotation.y;
-                body.quaternion.y = initialRotation.z;
-                body.quaternion.w = -initialRotation.w;
-            }
-
-            body.position.set(mesh.position.x, mesh.position.z, mesh.position.y);
-            this._world.add(body);
-
-            this._registeredMeshes.push({ mesh: mesh, body: body, material: material });
-
-            return body;
-        };
-
-        PhysicsEngine.prototype._registerCompound = function (options) {
-            var compoundShape = new CANNON.Compound();
-            var initialMesh = options.parts[0].mesh;
-            var initialPosition = initialMesh.position;
-
-            for (var index = 0; index < options.parts.length; index++) {
-                var mesh = options.parts[index].mesh;
-
-                var shape = this._registerMesh(mesh, options.parts[index], true);
-
-                if (index == 0) {
-                    compoundShape.addChild(shape, new CANNON.Vec3(0, 0, 0));
-                } else {
-                    compoundShape.addChild(shape, new CANNON.Vec3(mesh.position.x, mesh.position.z, mesh.position.y));
-                }
-            }
-
-            var material = this._addMaterial(options.friction, options.restitution);
-            var body = new CANNON.RigidBody(options.mass, compoundShape, material);
-
-            body.position.set(initialPosition.x, initialPosition.z, initialPosition.y);
-            this._world.add(body);
-
-            for (index = 0; index < options.parts.length; index++) {
-                mesh = options.parts[index].mesh;
-                this._registeredMeshes.push({ mesh: mesh, body: body, material: material, isChild: index != 0 });
-            }
-
-            body.parts = options.parts;
-
-            return body;
-        };
-
-        PhysicsEngine.prototype._unbindBody = function (body) {
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-
-                if (registeredMesh.body === body) {
-                    registeredMesh.body = null;
-                }
-            }
+        PhysicsEngine.prototype._registerMeshesAsCompound = function (parts, options) {
+            return this._currentPlugin.registerMeshesAsCompound(parts, options);
         };
 
         PhysicsEngine.prototype._unregisterMesh = function (mesh) {
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-
-                if (registeredMesh.mesh === mesh) {
-                    // Remove body
-                    if (registeredMesh.body) {
-                        this._world.remove(registeredMesh.body);
-
-                        this._unbindBody(registeredMesh.body);
-                    }
-
-                    this._registeredMeshes.splice(index, 1);
-                    return;
-                }
-            }
+            this._currentPlugin.unregisterMesh(mesh);
         };
 
         PhysicsEngine.prototype._applyImpulse = function (mesh, force, contactPoint) {
-            var worldPoint = new CANNON.Vec3(contactPoint.x, contactPoint.z, contactPoint.y);
-            var impulse = new CANNON.Vec3(force.x, force.z, force.y);
-
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-
-                if (registeredMesh.mesh === mesh) {
-                    registeredMesh.body.applyImpulse(impulse, worldPoint);
-                    return;
-                }
-            }
+            this._currentPlugin.applyImpulse(mesh, force, contactPoint);
         };
 
         PhysicsEngine.prototype._createLink = function (mesh1, mesh2, pivot1, pivot2) {
-            var body1, body2;
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-
-                if (registeredMesh.mesh === mesh1) {
-                    body1 = registeredMesh.body;
-                } else if (registeredMesh.mesh === mesh2) {
-                    body2 = registeredMesh.body;
-                }
-            }
-
-            if (!body1 || !body2) {
-                return;
-            }
-
-            var constraint = new CANNON.PointToPointConstraint(body1, new CANNON.Vec3(pivot1.x, pivot1.z, pivot1.y), body2, new CANNON.Vec3(pivot2.x, pivot2.z, pivot2.y));
-            this._world.addConstraint(constraint);
+            return this._currentPlugin.createLink(mesh1, mesh2, pivot1, pivot2);
         };
 
         PhysicsEngine.prototype.dispose = function () {
-            while (this._registeredMeshes.length) {
-                this._unregisterMesh(this._registeredMeshes[0].mesh);
-            }
+            this._currentPlugin.dispose();
         };
 
-        // Statics
-        PhysicsEngine.IsSupported = function () {
-            return window.CANNON !== undefined;
+        PhysicsEngine.prototype.isSupported = function () {
+            return this._currentPlugin.isSupported();
         };
 
         PhysicsEngine.NoImpostor = 0;

+ 46 - 233
Babylon/Physics/babylon.physicsEngine.ts

@@ -1,16 +1,41 @@
 module BABYLON {
     declare var CANNON;
-    declare var window;
+
+    export interface PhysicsEnginePlugin {
+        initialize(iterations?: number);
+        setGravity(gravity: Vector3): void;
+        runOneStep(delta: number): void;
+        registerMesh(mesh: Mesh, impostor: number, options: PhysicsBodyCreationOptions): any;
+        registerMeshesAsCompound(parts: PhysicsCompoundBodyPart[], options: PhysicsBodyCreationOptions): any;
+        unregisterMesh(mesh: Mesh);
+        applyImpulse(mesh: Mesh, force: Vector3, contactPoint: Vector3): void;
+        createLink(mesh1: Mesh, mesh2: Mesh, pivot1: Vector3, pivot2: Vector3): boolean;
+        dispose(): void;
+        isSupported(): boolean;
+    }
+
+    export interface PhysicsBodyCreationOptions {
+        mass: number;
+        friction: number;
+        restitution: number;
+    }
+
+    export interface PhysicsCompoundBodyPart {
+        mesh: Mesh;
+        impostor: number;
+    }
 
     export class PhysicsEngine {
-        private _world = new CANNON.World();
+        public gravity: Vector3;
+
+        private _currentPlugin: PhysicsEnginePlugin;
 
-        private _registeredMeshes = [];
-        private _physicsMaterials = [];
+        constructor(plugin?: PhysicsEnginePlugin) {
+            this._currentPlugin = plugin || new CannonJSPlugin();
+        }
 
-        constructor(public gravity: Vector3, iterations: number) {
-            this._world.broadphase = new CANNON.NaiveBroadphase();
-            this._world.solver.iterations = iterations;
+        public _initialize(gravity?: Vector3) {
+            this._currentPlugin.initialize();
             this._setGravity(gravity);
         }
 
@@ -21,255 +46,43 @@
                 delta = 1.0 / 60.0;
             }
 
-            this._world.step(delta);
-
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-
-                if (registeredMesh.isChild) {
-                    continue;
-                }
-
-                registeredMesh.mesh.position.x = registeredMesh.body.position.x;
-                registeredMesh.mesh.position.y = registeredMesh.body.position.z;
-                registeredMesh.mesh.position.z = registeredMesh.body.position.y;
-
-                if (!registeredMesh.mesh.rotationQuaternion) {
-                    registeredMesh.mesh.rotationQuaternion = new BABYLON.Quaternion(0, 0, 0, 1);
-                }
-
-                registeredMesh.mesh.rotationQuaternion.x = registeredMesh.body.quaternion.x;
-                registeredMesh.mesh.rotationQuaternion.y = registeredMesh.body.quaternion.z;
-                registeredMesh.mesh.rotationQuaternion.z = registeredMesh.body.quaternion.y;
-                registeredMesh.mesh.rotationQuaternion.w = -registeredMesh.body.quaternion.w;
-            }
-        }
-
-        public _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();
-            currentMat.friction = friction;
-            currentMat.restitution = restitution;
-            this._physicsMaterials.push(currentMat);
-
-            for (index = 0; index < this._physicsMaterials.length; index++) {
-                mat = this._physicsMaterials[index];
-
-                var contactMaterial = new CANNON.ContactMaterial(mat, currentMat, mat.friction * currentMat.friction, mat.restitution * currentMat.restitution);
-                contactMaterial.contactEquationStiffness = 1e10;
-                contactMaterial.contactEquationRegularizationTime = 10;
-
-                this._world.addContactMaterial(contactMaterial);
-            }
-
-            return currentMat;
+            this._currentPlugin.runOneStep(delta);
         }
 
         public _setGravity(gravity: Vector3): void {
             this.gravity = gravity || new BABYLON.Vector3(0, -9.82, 0);
-            this._world.gravity.set(this.gravity.x, this.gravity.z, this.gravity.y);
+            this._currentPlugin.setGravity(this.gravity);
         }
 
-        public _checkWithEpsilon(value: number): number {
-            return value < BABYLON.PhysicsEngine.Epsilon ? BABYLON.PhysicsEngine.Epsilon : value;
+        public _registerMesh(mesh: Mesh, impostor: number, options: PhysicsBodyCreationOptions): any {
+            return this._currentPlugin.registerMesh(mesh, impostor, options);
         }
 
-        public _registerMesh(mesh: Mesh, options, onlyShape?: boolean): void {
-            var shape = null;
-            var initialRotation;
-
-            if (mesh.rotationQuaternion) {
-                initialRotation = mesh.rotationQuaternion.clone();
-                mesh.rotationQuaternion = new BABYLON.Quaternion(0, 0, 0, 1);
-            }
-
-            this._unregisterMesh(mesh);
-
-            mesh.computeWorldMatrix(true);
-
-            switch (options.impostor) {
-                case BABYLON.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;
-
-                    shape = new CANNON.Sphere(Math.max(this._checkWithEpsilon(radiusX), this._checkWithEpsilon(radiusY), this._checkWithEpsilon(radiusZ)) / 2);
-                    break;
-                case BABYLON.PhysicsEngine.BoxImpostor:
-                    bbox = mesh.getBoundingInfo().boundingBox;
-                    var min = bbox.minimumWorld;
-                    var max = bbox.maximumWorld;
-                    var box = max.subtract(min).scale(0.5);
-                    shape = new CANNON.Box(new CANNON.Vec3(this._checkWithEpsilon(box.x), this._checkWithEpsilon(box.z), this._checkWithEpsilon(box.y)));
-                    break;
-                case BABYLON.PhysicsEngine.PlaneImpostor:
-                    shape = new CANNON.Plane();
-                    break;
-                case BABYLON.PhysicsEngine.MeshImpostor:
-                    var rawVerts = mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind);
-                    var rawFaces = mesh.getIndices();
-
-                    var verts = [], faces = [];
-
-                    mesh.computeWorldMatrix(true);
-
-                    // Get vertices
-                    for (var i = 0; i < rawVerts.length; i += 3) {
-                        var transformed = BABYLON.Vector3.Zero();
-
-                        BABYLON.Vector3.TransformNormalFromFloatsToRef(rawVerts[i], rawVerts[i + 1], rawVerts[i + 2], mesh.getWorldMatrix(), transformed);
-                        verts.push(new CANNON.Vec3(transformed.x, transformed.z, transformed.y));
-                    }
-
-                    // Get faces
-                    for (var j = 0; j < rawFaces.length; j += 3) {
-                        faces.push([rawFaces[j], rawFaces[j + 2], rawFaces[j + 1]]);
-                    }
-
-                    // Construct polyhedron
-                    shape = new CANNON.ConvexPolyhedron(verts, faces);
-                    break;
-            }
-
-            if (onlyShape) {
-                return shape;
-            }
-
-            var material = this._addMaterial(options.friction, options.restitution);
-            var body = new CANNON.RigidBody(options.mass, shape, material);
-
-            if (initialRotation) {
-                body.quaternion.x = initialRotation.x;
-                body.quaternion.z = initialRotation.y;
-                body.quaternion.y = initialRotation.z;
-                body.quaternion.w = -initialRotation.w;
-            }
-
-            body.position.set(mesh.position.x, mesh.position.z, mesh.position.y);
-            this._world.add(body);
-
-            this._registeredMeshes.push({ mesh: mesh, body: body, material: material });
-
-            return body;
-        }
-
-        public _registerCompound(options): any {
-            var compoundShape = new CANNON.Compound();
-            var initialMesh = options.parts[0].mesh;
-            var initialPosition = initialMesh.position;
-
-            for (var index = 0; index < options.parts.length; index++) {
-                var mesh = options.parts[index].mesh;
-
-                var shape = this._registerMesh(mesh, options.parts[index], true);
-
-                if (index == 0) { // Parent
-                    compoundShape.addChild(shape, new CANNON.Vec3(0, 0, 0));
-                } else {
-                    compoundShape.addChild(shape, new CANNON.Vec3(mesh.position.x, mesh.position.z, mesh.position.y));
-                }
-            }
-
-            var material = this._addMaterial(options.friction, options.restitution);
-            var body = new CANNON.RigidBody(options.mass, compoundShape, material);
-
-            body.position.set(initialPosition.x, initialPosition.z, initialPosition.y);
-            this._world.add(body);
-
-            for (index = 0; index < options.parts.length; index++) {
-                mesh = options.parts[index].mesh;
-                this._registeredMeshes.push({ mesh: mesh, body: body, material: material, isChild: index != 0 });
-            }
-
-            body.parts = options.parts;
-
-            return body;
-        }
-
-        public _unbindBody(body): void {
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-
-                if (registeredMesh.body === body) {
-                    registeredMesh.body = null;
-                }
-            }
+        public _registerMeshesAsCompound(parts: PhysicsCompoundBodyPart[], options: PhysicsBodyCreationOptions): any {
+            return this._currentPlugin.registerMeshesAsCompound(parts, options);
         }
 
         public _unregisterMesh(mesh: Mesh): 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._world.remove(registeredMesh.body);
-
-                        this._unbindBody(registeredMesh.body);
-                    }
-
-                    this._registeredMeshes.splice(index, 1);
-                    return;
-                }
-            }
+            this._currentPlugin.unregisterMesh(mesh);
         }
 
         public _applyImpulse(mesh: Mesh, force: Vector3, contactPoint: Vector3): void {
-            var worldPoint = new CANNON.Vec3(contactPoint.x, contactPoint.z, contactPoint.y);
-            var impulse = new CANNON.Vec3(force.x, force.z, force.y);
-
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-
-                if (registeredMesh.mesh === mesh) {
-                    registeredMesh.body.applyImpulse(impulse, worldPoint);
-                    return;
-                }
-            }
+            this._currentPlugin.applyImpulse(mesh, force, contactPoint);
         }
 
-        public _createLink(mesh1: Mesh, mesh2: Mesh, pivot1: Vector3, pivot2: Vector3): void {
-            var body1, body2;
-            for (var index = 0; index < this._registeredMeshes.length; index++) {
-                var registeredMesh = this._registeredMeshes[index];
-
-                if (registeredMesh.mesh === mesh1) {
-                    body1 = registeredMesh.body;
-                } else if (registeredMesh.mesh === mesh2) {
-                    body2 = registeredMesh.body;
-                }
-            }
-
-            if (!body1 || !body2) {
-                return;
-            }
-
-            var constraint = new CANNON.PointToPointConstraint(body1, new CANNON.Vec3(pivot1.x, pivot1.z, pivot1.y), body2, new CANNON.Vec3(pivot2.x, pivot2.z, pivot2.y));
-            this._world.addConstraint(constraint);
+        public _createLink(mesh1: Mesh, mesh2: Mesh, pivot1: Vector3, pivot2: Vector3): boolean {
+            return this._currentPlugin.createLink(mesh1, mesh2, pivot1, pivot2);
         }
 
         public dispose(): void {
-            while (this._registeredMeshes.length) {
-                this._unregisterMesh(this._registeredMeshes[0].mesh);
-            }
+            this._currentPlugin.dispose();
         }
 
-        // Statics
-        public static IsSupported(): boolean {
-            return window.CANNON !== undefined;
+        public isSupported(): boolean {
+            return this._currentPlugin.isSupported();
         }
 
+        // Statics
         public static NoImpostor = 0;
         public static SphereImpostor = 1;
         public static BoxImpostor = 2;

+ 17 - 10
Babylon/babylon.scene.js

@@ -1009,16 +1009,19 @@
             return this._physicsEngine;
         };
 
-        Scene.prototype.enablePhysics = function (gravity, iterations) {
+        Scene.prototype.enablePhysics = function (gravity, plugin) {
             if (this._physicsEngine) {
                 return true;
             }
 
-            if (!BABYLON.PhysicsEngine.IsSupported()) {
+            this._physicsEngine = new BABYLON.PhysicsEngine(plugin);
+
+            if (!this._physicsEngine.isSupported()) {
+                this._physicsEngine = null;
                 return false;
             }
 
-            this._physicsEngine = new BABYLON.PhysicsEngine(gravity, iterations || 10);
+            this._physicsEngine._initialize(gravity);
 
             return true;
         };
@@ -1044,22 +1047,26 @@
             this._physicsEngine._setGravity(gravity);
         };
 
-        //ANY
-        Scene.prototype.createCompoundImpostor = function (options) {
+        Scene.prototype.createCompoundImpostor = function (parts, options) {
+            if (parts.parts) {
+                options = parts;
+                parts = parts.parts;
+            }
+
             if (!this._physicsEngine) {
                 return null;
             }
 
-            for (var index = 0; index < options.parts.length; index++) {
-                var mesh = options.parts[index].mesh;
+            for (var index = 0; index < parts.length; index++) {
+                var mesh = parts[index].mesh;
 
-                mesh._physicImpostor = options.parts[index].impostor;
-                mesh._physicsMass = options.mass / options.parts.length;
+                mesh._physicImpostor = parts[index].impostor;
+                mesh._physicsMass = options.mass / parts.length;
                 mesh._physicsFriction = options.friction;
                 mesh._physicRestitution = options.restitution;
             }
 
-            return this._physicsEngine._registerCompound(options);
+            return this._physicsEngine._registerMeshesAsCompound(parts, options);
         };
 
         //ANY

+ 18 - 11
Babylon/babylon.scene.ts

@@ -1072,16 +1072,19 @@
             return this._physicsEngine;
         }
 
-        public enablePhysics(gravity: Vector3, iterations: number): boolean {
+        public enablePhysics(gravity: Vector3, plugin?: PhysicsEnginePlugin): boolean {
             if (this._physicsEngine) {
                 return true;
             }
 
-            if (!PhysicsEngine.IsSupported()) {
+            this._physicsEngine = new BABYLON.PhysicsEngine(plugin);
+
+            if (!this._physicsEngine.isSupported()) {
+                this._physicsEngine = null;
                 return false;
             }
 
-            this._physicsEngine = new BABYLON.PhysicsEngine(gravity, iterations || 10);
+            this._physicsEngine._initialize(gravity);
 
             return true;
         }
@@ -1107,26 +1110,30 @@
             this._physicsEngine._setGravity(gravity);
         }
 
-        //ANY
-        public createCompoundImpostor(options): any {
+        public createCompoundImpostor(parts: any, options: PhysicsBodyCreationOptions): any {
+            if (parts.parts) { // Old API
+                options = parts;
+                parts = parts.parts;
+            }
+
             if (!this._physicsEngine) {
                 return null;
             }
 
-            for (var index = 0; index < options.parts.length; index++) {
-                var mesh = options.parts[index].mesh;
+            for (var index = 0; index < parts.length; index++) {
+                var mesh = parts[index].mesh;
 
-                mesh._physicImpostor = options.parts[index].impostor;
-                mesh._physicsMass = options.mass / options.parts.length;
+                mesh._physicImpostor = parts[index].impostor;
+                mesh._physicsMass = options.mass / parts.length;
                 mesh._physicsFriction = options.friction;
                 mesh._physicRestitution = options.restitution;
             }
 
-            return this._physicsEngine._registerCompound(options);
+            return this._physicsEngine._registerMeshesAsCompound(parts, options);
         }
 
         //ANY
-        public deleteCompoundImpostor(compound): void {
+        public deleteCompoundImpostor(compound: any): void {
             for (var index = 0; index < compound.parts.length; index++) {
                 var mesh = compound.parts[index].mesh;
                 mesh._physicImpostor = BABYLON.PhysicsEngine.NoImpostor;

+ 1 - 0
Tools/BuildOurOwnBabylonJS/BuildOurOwnBabylonJS/babylonJS.xml

@@ -11,6 +11,7 @@
   <script src="Babylon/Cameras/Controllers/babylon.inputController.js"></script>
   <script src="Babylon/Mesh/babylon.csg.js"></script>
   <script src="Babylon/Tools/babylon.sceneSerializer.js"></script>
+  <script src="Babylon/Physics/Plugins/babylon.cannonJSPlugin.js"></script>
   <script src="Babylon/Physics/babylon.physicsEngine.js"></script>
   <script src="Babylon/Tools/babylon.filesInput.js"></script>
   <script src="Babylon/Collisions/babylon.pickingInfo.js"></script>

二进制
Tools/BuildOurOwnBabylonJS/BuildOurOwnBabylonJS/executables/JSKompactor.exe


文件差异内容过多而无法显示
+ 2 - 2
babylon.1.12-beta.js