瀏覽代碼

add cloth

Guide 6 年之前
父節點
當前提交
5e05b45655
共有 1 個文件被更改,包括 91 次插入7 次删除
  1. 91 7
      src/Physics/Plugins/ammoJSPlugin.ts

+ 91 - 7
src/Physics/Plugins/ammoJSPlugin.ts

@@ -45,6 +45,7 @@ export class AmmoJSPlugin implements IPhysicsEnginePlugin {
     private _tmpAmmoVectorA: any;
     private _tmpAmmoVectorB: any;
     private _tmpAmmoVectorC: any;
+    private _tmpAmmoVectorD: any;
     private _tmpContactCallbackResult = false;
 
     private static readonly DISABLE_COLLISION_FLAG = 4;
@@ -96,6 +97,7 @@ export class AmmoJSPlugin implements IPhysicsEnginePlugin {
         this._tmpAmmoVectorA = new this.bjsAMMO.btVector3(0, 0, 0);
         this._tmpAmmoVectorB = new this.bjsAMMO.btVector3(0, 0, 0);
         this._tmpAmmoVectorC = new this.bjsAMMO.btVector3(0, 0, 0);
+        this._tmpAmmoVectorD = new this.bjsAMMO.btVector3(0, 0, 0);
     }
 
     /**
@@ -526,13 +528,12 @@ export class AmmoJSPlugin implements IPhysicsEnginePlugin {
     }
 
     /**
-     * Create an impostor's soft body
      * Initialise the soft body vertices to match its object's (mesh) vertices
      * Softbody vertices (nodes) are in world space and to match this
      * The object's position and rotation is set to zero and so its vertices are also then set in world space
      * @param impostor to create the softbody for
      */
-    private _createSoftbody(impostor: PhysicsImpostor) {
+    private _softVertexData(impostor: PhysicsImpostor) : VertexData {
         var object = impostor.object;
         if (object && object.getIndices && object.getWorldMatrix && object.getChildMeshes) {
             var indices = object.getIndices();
@@ -548,8 +549,6 @@ export class AmmoJSPlugin implements IPhysicsEnginePlugin {
                 vertexNormals = [];
             }
             object.computeWorldMatrix(false);
-            var triPoints = [];
-            var triNorms = [];
             var newPoints = [];
             var newNorms = [];
             for (var i = 0; i < vertexPositions.length; i += 3) {
@@ -557,8 +556,6 @@ export class AmmoJSPlugin implements IPhysicsEnginePlugin {
                     var n = new Vector3(vertexNormals[i], vertexNormals[i + 1], vertexNormals[i + 2]);
                     v = Vector3.TransformCoordinates(v, object.getWorldMatrix());
                     n = Vector3.TransformNormal(n, object.getWorldMatrix());
-                    triPoints.push(v.x, v.y, -v.z);
-                    triNorms.push(n.x, n.y, -n.z);
                     newPoints.push(v.x, v.y, v.z);
                     newNorms.push(n.x, n.y, n.z);
             }
@@ -580,10 +577,39 @@ export class AmmoJSPlugin implements IPhysicsEnginePlugin {
             object.rotation = Vector3.Zero();
             object.computeWorldMatrix(true);
 
-            if (vertexPositions.length === 0) {
+            return vertex_data;
+        }
+        return VertexData.ExtractFromMesh(<Mesh>object);
+    }
+
+    /**
+     * Create an impostor's soft body
+     * @param impostor to create the softbody for
+     */
+    private _createSoftbody(impostor: PhysicsImpostor) {
+        var object = impostor.object;
+        if (object && object.getIndices) {
+            var indices = object.getIndices();
+            if (!indices) {
+                indices = [];
+            }
+            
+            var vertex_data = this._softVertexData(impostor);
+            var vertexPositions = vertex_data.positions;
+            var vertexNormals = vertex_data.normals;
+
+            if (vertexPositions === null  || vertexNormals === null) {
                 return new Ammo.btCompoundShape();
             }
             else {
+                var triPoints = [];
+                var triNorms = [];
+                for (var i = 0; i < vertexPositions.length; i += 3) {
+                    var v = new Vector3(vertexPositions[i], vertexPositions[i + 1], vertexPositions[i + 2]);
+                    var n = new Vector3(vertexNormals[i], vertexNormals[i + 1], vertexNormals[i + 2]);
+                    triPoints.push(v.x, v.y, -v.z);
+                    triNorms.push(n.x, n.y, -n.z);
+                }
                 var softBody = new Ammo.btSoftBodyHelpers().CreateFromTriMesh(
                     this.world.getWorldInfo(),
                     triPoints,
@@ -609,6 +635,60 @@ export class AmmoJSPlugin implements IPhysicsEnginePlugin {
         }
     }
 
+    /**
+     * Create cloth for an impostor
+     * @param impostor to create the softbody for
+     */
+    private _createCloth(impostor: PhysicsImpostor) {
+        var object = impostor.object;
+        if (object && object.getIndices) {
+            var indices = object.getIndices();
+            if (!indices) {
+                indices = [];
+            }
+            
+            var vertex_data = this._softVertexData(impostor);
+            var vertexPositions = vertex_data.positions;
+            var vertexNormals = vertex_data.normals;
+
+            if (vertexPositions === null  || vertexNormals === null) {
+                return new Ammo.btCompoundShape();
+            }
+            else {
+                var len = vertexPositions.length;
+                var segments = Math.sqrt(len / 3);
+                //cornerSum is 0 when object is a plane
+                var cornerSum = vertexPositions[0] + vertexPositions[3] + vertexPositions[6] + vertexPositions[9];
+                if (Math.abs(cornerSum) < Math.pow(10, -10)) {
+                    this._tmpAmmoVectorA.setValue(vertexPositions[0], vertexPositions[1], -vertexPositions[2]);
+                    this._tmpAmmoVectorB.setValue(vertexPositions[3], vertexPositions[4], -vertexPositions[5]);
+                    this._tmpAmmoVectorC.setValue(vertexPositions[6], vertexPositions[7], -vertexPositions[8]);
+                    this._tmpAmmoVectorD.setValue(vertexPositions[9], vertexPositions[10], -vertexPositions[11]);
+                }
+                else { // object is ground
+                    this._tmpAmmoVectorA.setValue(vertexPositions[0], vertexPositions[1], -vertexPositions[2]);
+                    this._tmpAmmoVectorB.setValue(vertexPositions[3 * segments] , vertexPositions[3* segments + 1] , -vertexPositions[3*segments + 2]);
+                    this._tmpAmmoVectorC.setValue(vertexPositions[len - 3] , vertexPositions[len - 2] , -vertexPositions[len - 1]);
+                    this._tmpAmmoVectorD.setValue(vertexPositions[len - 3 - 3 * segments] , vertexPositions[len - 2 - 3 * segments] , -vertexPositions[len - 1 - 3 * segments]);
+                }               
+
+                var clothBody = new Ammo.btSoftBodyHelpers().CreatePatch(
+                    this.world.getWorldInfo(),
+                    this._tmpAmmoVectorA,
+                    this._tmpAmmoVectorB,
+                    this._tmpAmmoVectorC,
+                    this._tmpAmmoVectorD,
+                    segments,
+                    segments,
+                    0,
+                    true
+                );
+                clothBody.get_m_cfg().set_collisions(0x11);
+                return clothBody;
+            }
+        }
+    }
+
     private _createShape(impostor: PhysicsImpostor, ignoreChildren = false) {
         var object = impostor.object;
 
@@ -691,6 +771,10 @@ export class AmmoJSPlugin implements IPhysicsEnginePlugin {
                 // Only usable with a mesh that has sufficient and shared vertices
                 returnValue = this._createSoftbody(impostor);
                 break;
+            case PhysicsImpostor.ClothImpostor:
+                // Only usable with a mesh that has sufficient and shared vertices
+                returnValue = this._createCloth(impostor);
+                break;
             default:
                 Logger.Warn("The impostor type is not currently supported by the ammo plugin.");
                 break;