瀏覽代碼

- fix physics debug view rogue meshes by adding mesh.getFloatBuffer(Type.Position).clear()
- make CollisionShapeFactory use not world translation but translation relative to given parent
- add CollisionShapeFactory test


git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@7060 75d07b2b-3a1a-0410-a2c5-0572b91ccdca

nor..67 14 年之前
父節點
當前提交
e0e539c8bd

+ 0 - 14
engine/src/jbullet/com/jme3/bullet/control/RigidBodyControl.java

@@ -129,23 +129,9 @@ public class RigidBodyControl extends PhysicsRigidBody implements PhysicsControl
             }
         }
         if (mass > 0) {
-            Node parent = spatial.getParent();
-            if (parent != null) {
-                spatial.removeFromParent();
-            }
             collisionShape = CollisionShapeFactory.createDynamicMeshShape(spatial);
-            if (parent != null) {
-                parent.attachChild(spatial);
-            }
         } else {
-            Node parent = spatial.getParent();
-            if (parent != null) {
-                spatial.removeFromParent();
-            }
             collisionShape = CollisionShapeFactory.createMeshShape(spatial);
-            if (parent != null) {
-                parent.attachChild(spatial);
-            }
         }
     }
 

+ 58 - 37
engine/src/jbullet/com/jme3/bullet/util/CollisionShapeFactory.java

@@ -40,6 +40,8 @@ import com.jme3.bullet.collision.shapes.HullCollisionShape;
 import com.jme3.bullet.collision.shapes.MeshCollisionShape;
 import com.jme3.bullet.collision.shapes.infos.ChildCollisionShape;
 import com.jme3.math.Matrix3f;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Transform;
 import com.jme3.math.Vector3f;
 import com.jme3.scene.Geometry;
 import com.jme3.scene.Mesh;
@@ -55,25 +57,55 @@ import java.util.LinkedList;
  */
 public class CollisionShapeFactory {
 
-    private static CompoundCollisionShape createCompoundShape(
+    /**
+     * returns the correct transform for a collisionshape in relation
+     * to the ancestor for which the collisionshape is generated
+     * @param spat
+     * @param parent
+     * @return
+     */
+    private static Transform getTransform(Spatial spat, Spatial parent) {
+        Transform shapeTransform = new Transform();
+        Spatial parentNode = spat.getParent() != null ? spat.getParent() : spat;
+        Spatial currentSpatial = spat;
+        //if we have parents combine their transforms
+        while (parentNode != null) {
+            if (parent == currentSpatial) {
+                //real parent -> only apply scale, not transform
+                Transform trans = new Transform();
+                trans.setScale(currentSpatial.getLocalScale());
+                shapeTransform.combineWithParent(trans);
+                parentNode = null;
+            } else {
+                shapeTransform.combineWithParent(currentSpatial.getLocalTransform());
+                parentNode = currentSpatial.getParent();
+                currentSpatial = parentNode;
+            }
+        }
+        return shapeTransform;
+    }
+
+    private static CompoundCollisionShape createCompoundShape(Node realRootNode,
             Node rootNode, CompoundCollisionShape shape, boolean meshAccurate, boolean dynamic) {
         for (Spatial spatial : rootNode.getChildren()) {
             if (spatial instanceof Node) {
-                createCompoundShape((Node) spatial, shape, meshAccurate, dynamic);
+                createCompoundShape(realRootNode, (Node) spatial, shape, meshAccurate, dynamic);
             } else if (spatial instanceof Geometry) {
                 if (meshAccurate) {
                     CollisionShape childShape = dynamic
-                            ? createSingleDynamicMeshShape((Geometry) spatial)
-                            : createSingleMeshShape((Geometry) spatial);
+                            ? createSingleDynamicMeshShape((Geometry) spatial, realRootNode)
+                            : createSingleMeshShape((Geometry) spatial, realRootNode);
                     if (childShape != null) {
+                        Transform trans = getTransform(spatial, realRootNode);
                         shape.addChildShape(childShape,
-                                spatial.getWorldTranslation(),
-                                spatial.getWorldRotation().toRotationMatrix());
+                                trans.getTranslation(),
+                                trans.getRotation().toRotationMatrix());
                     }
                 } else {
-                    shape.addChildShape(createSingleBoxShape(spatial),
-                            spatial.getWorldTranslation(),
-                            spatial.getWorldRotation().toRotationMatrix());
+                    Transform trans = getTransform(spatial, realRootNode);
+                    shape.addChildShape(createSingleBoxShape(spatial, realRootNode),
+                            trans.getTranslation(),
+                            trans.getRotation().toRotationMatrix());
                 }
             }
         }
@@ -82,7 +114,7 @@ public class CollisionShapeFactory {
 
     private static CompoundCollisionShape createCompoundShape(
             Node rootNode, CompoundCollisionShape shape, boolean meshAccurate) {
-        return createCompoundShape(rootNode, shape, meshAccurate, false);
+        return createCompoundShape(rootNode, rootNode, shape, meshAccurate, false);
     }
 
     /**
@@ -106,30 +138,17 @@ public class CollisionShapeFactory {
 
     /**
      * This type of collision shape is mesh-accurate and meant for immovable "world objects".
-     * Examples include terrain, houses or whole shooter levels.<br>
-     * Objects with "mesh" type collision shape will not collide with each other.
-     * @return A MeshCollisionShape or a CompoundCollisionShape with MeshCollisionShapes as children if the supplied spatial is a Node.
+     * Examples include terrain, houses or whole shooter levels.<br/>
+     * Objects with "mesh" type collision shape will not collide with each other.<br/>
+     * Creates a HeightfieldCollisionShape if the supplied spatial is a TerrainQuad.
+     * @return A MeshCollisionShape or a CompoundCollisionShape with MeshCollisionShapes as children if the supplied spatial is a Node. A HeightieldCollisionShape if a TerrainQuad was supplied.
      */
     public static CollisionShape createMeshShape(Spatial spatial) {
         if (spatial instanceof TerrainQuad) {
             TerrainQuad terrain = (TerrainQuad) spatial;
             return new HeightfieldCollisionShape(terrain.getHeightMap(), terrain.getLocalScale());
-            //BELOW: the old way, keeping it here for a little bit as a reference (and so it gets into version control so I can always access it)
-		/*Map<TerrainPatch,Vector3f> all = new HashMap<TerrainPatch,Vector3f>();
-            terrain.getAllTerrainPatchesWithTranslation(all, terrain.getLocalTranslation());
-            
-            Node node = new Node();
-            
-            for (Entry<TerrainPatch,Vector3f> entry : all.entrySet()) {
-            TerrainPatch tp = entry.getKey();
-            Vector3f trans = entry.getValue();
-            PhysicsNode n = new PhysicsNode(new HeightfieldCollisionShape(tp.getHeightmap(), trans, tp.getLocalScale()), 0 );
-            n.setLocalTranslation(trans);
-            node.attachChild(n);
-            }*/
-
         } else if (spatial instanceof Geometry) {
-            return createSingleMeshShape((Geometry) spatial);
+            return createSingleMeshShape((Geometry) spatial, spatial);
         } else if (spatial instanceof Node) {
             return createMeshCompoundShape((Node) spatial);
         } else {
@@ -144,9 +163,9 @@ public class CollisionShapeFactory {
      */
     public static CollisionShape createDynamicMeshShape(Spatial spatial) {
         if (spatial instanceof Geometry) {
-            return createSingleDynamicMeshShape((Geometry) spatial);
+            return createSingleDynamicMeshShape((Geometry) spatial, spatial);
         } else if (spatial instanceof Node) {
-            return createCompoundShape((Node) spatial, new CompoundCollisionShape(), true, true);
+            return createCompoundShape((Node) spatial, (Node) spatial, new CompoundCollisionShape(), true, true);
         } else {
             throw new IllegalArgumentException("Supplied spatial must either be Node or Geometry!");
         }
@@ -155,7 +174,7 @@ public class CollisionShapeFactory {
 
     public static CollisionShape createBoxShape(Spatial spatial) {
         if (spatial instanceof Geometry) {
-            return createSingleBoxShape((Geometry) spatial);
+            return createSingleBoxShape((Geometry) spatial, spatial);
         } else if (spatial instanceof Node) {
             return createBoxCompoundShape((Node) spatial);
         } else {
@@ -168,11 +187,12 @@ public class CollisionShapeFactory {
      * Examples include terrain, houses or whole shooter levels.<br>
      * Objects with "mesh" type collision shape will not collide with each other.
      */
-    public static MeshCollisionShape createSingleMeshShape(Geometry geom) {
+    private static MeshCollisionShape createSingleMeshShape(Geometry geom, Spatial parent) {
         Mesh mesh = geom.getMesh();
+        Transform trans = getTransform(geom, parent);
         if (mesh != null) {
             MeshCollisionShape mColl = new MeshCollisionShape(mesh);
-            mColl.setScale(geom.getWorldScale());
+            mColl.setScale(trans.getScale());
             return mColl;
         } else {
             return null;
@@ -184,8 +204,9 @@ public class CollisionShapeFactory {
      * @param spatial
      * @return BoxCollisionShape with the size of the spatials BoundingBox
      */
-    public static BoxCollisionShape createSingleBoxShape(Spatial spatial) {
+    private static BoxCollisionShape createSingleBoxShape(Spatial spatial, Spatial parent) {
         spatial.setModelBound(new BoundingBox());
+        //TODO: using world bound here instead of "local world" bound...
         BoxCollisionShape shape = new BoxCollisionShape(
                 ((BoundingBox) spatial.getWorldBound()).getExtent(new Vector3f()));
         return shape;
@@ -194,11 +215,12 @@ public class CollisionShapeFactory {
     /**
      * This method creates a hull collision shape for the given mesh.<br>
      */
-    public static HullCollisionShape createSingleDynamicMeshShape(Geometry geom) {
+    private static HullCollisionShape createSingleDynamicMeshShape(Geometry geom, Spatial parent) {
         Mesh mesh = geom.getMesh();
+        Transform trans = getTransform(geom, parent);
         if (mesh != null) {
             HullCollisionShape dynamicShape = new HullCollisionShape(mesh);
-            dynamicShape.setScale(geom.getWorldScale());
+            dynamicShape.setScale(trans.getScale());
             return dynamicShape;
         } else {
             return null;
@@ -219,5 +241,4 @@ public class CollisionShapeFactory {
             compoundShape.addChildShape(child, location.add(vector), rotation);
         }
     }
-
 }

+ 3 - 1
engine/src/jbullet/com/jme3/bullet/util/Converter.java

@@ -247,6 +247,8 @@ public class Converter {
         for (int i = 0; i < indicesLength; i++) {
             jBulletIndexedMesh.triangleIndexBase.putInt(indices.get(i));
         }
+        vertices.rewind();
+        vertices.clear();
 
         return jBulletIndexedMesh;
     }
@@ -267,9 +269,9 @@ public class Converter {
         for (int i = 0; i < mesh.numVertices * 3; i++) {
             vertices.put(i, mesh.vertexBase.getFloat(i * 4));
         }
-        jmeMesh.getFloatBuffer(Type.Position).clear();
         jmeMesh.updateCounts();
         jmeMesh.updateBound();
+        jmeMesh.getFloatBuffer(Type.Position).clear();
 
         return jmeMesh;
     }

+ 2 - 0
engine/src/jbullet/com/jme3/bullet/util/DebugShapeFactory.java

@@ -125,11 +125,13 @@ public class DebugShapeFactory {
         if(shape.getCShape() instanceof ConvexShape){
             mesh=new Mesh();
             mesh.setBuffer(Type.Position, 3, getVertices((ConvexShape)shape.getCShape()));
+            mesh.getFloatBuffer(Type.Position).clear();
         }
         else if(shape.getCShape() instanceof ConcaveShape)
         {
             mesh=new Mesh();
             mesh.setBuffer(Type.Position, 3, getVertices((ConcaveShape)shape.getCShape()));
+            mesh.getFloatBuffer(Type.Position).clear();
         }
         return mesh;
     }

+ 138 - 0
engine/src/test/jme3test/bullet/TestCollisionShapeFactory.java

@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2009-2010 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *   may be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.bullet;
+
+import com.jme3.bullet.BulletAppState;
+import com.jme3.app.SimpleApplication;
+import com.jme3.bullet.PhysicsSpace;
+import com.jme3.bullet.control.RigidBodyControl;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.FastMath;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.shape.Box;
+import com.jme3.scene.shape.Cylinder;
+import com.jme3.scene.shape.Torus;
+
+/**
+ * This is a basic Test of jbullet-jme functions
+ *
+ * @author normenhansen
+ */
+public class TestCollisionShapeFactory extends SimpleApplication {
+
+    private BulletAppState bulletAppState;
+    private Material mat1;
+    private Material mat2;
+    private Material mat3;
+
+    public static void main(String[] args) {
+        TestCollisionShapeFactory app = new TestCollisionShapeFactory();
+        app.start();
+    }
+
+    @Override
+    public void simpleInitApp() {
+        bulletAppState = new BulletAppState();
+        stateManager.attach(bulletAppState);
+        bulletAppState.getPhysicsSpace().enableDebug(assetManager);
+        createMaterial();
+
+        Node node = new Node("node1");
+        attachRandomGeometry(node, mat1);
+        randomizeTransform(node);
+
+        Node node2 = new Node("node2");
+        attachRandomGeometry(node2, mat2);
+        randomizeTransform(node2);
+
+        node.attachChild(node2);
+        rootNode.attachChild(node);
+
+        RigidBodyControl control = new RigidBodyControl(0);
+        node.addControl(control);
+        getPhysicsSpace().add(control);
+
+        //test single geometry too
+        Geometry myGeom = new Geometry("cylinder", new Cylinder(16, 16, 0.5f, 1));
+        myGeom.setMaterial(mat3);
+        randomizeTransform(myGeom);
+        rootNode.attachChild(myGeom);
+        RigidBodyControl control3 = new RigidBodyControl(0);
+        myGeom.addControl(control3);
+        getPhysicsSpace().add(control3);
+    }
+
+    private void attachRandomGeometry(Node node, Material mat) {
+        Box box = new Box(0.25f, 0.25f, 0.25f);
+        Torus torus = new Torus(16, 16, 0.2f, 0.8f);
+        Geometry[] boxes = new Geometry[]{
+            new Geometry("box1", box),
+            new Geometry("box2", box),
+            new Geometry("box3", box),
+            new Geometry("torus1", torus),
+            new Geometry("torus2", torus),
+            new Geometry("torus3", torus)
+        };
+        for (int i = 0; i < boxes.length; i++) {
+            Geometry geometry = boxes[i];
+            geometry.setLocalTranslation((float) Math.random() * 10 -10, (float) Math.random() * 10 -10, (float) Math.random() * 10 -10);
+            geometry.setLocalRotation(new Quaternion().fromAngles((float) Math.random() * FastMath.PI, (float) Math.random() * FastMath.PI, (float) Math.random() * FastMath.PI));
+            geometry.setLocalScale((float) Math.random() * 10 -10, (float) Math.random() * 10 -10, (float) Math.random() * 10 -10);
+            geometry.setMaterial(mat);
+            node.attachChild(geometry);
+        }
+    }
+
+    private void randomizeTransform(Spatial spat){
+        spat.setLocalTranslation((float) Math.random() * 10, (float) Math.random() * 10, (float) Math.random() * 10);
+        spat.setLocalTranslation((float) Math.random() * 10, (float) Math.random() * 10, (float) Math.random() * 10);
+        spat.setLocalScale((float) Math.random() * 2, (float) Math.random() * 2, (float) Math.random() * 2);
+    }
+
+    private void createMaterial() {
+        mat1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+        mat1.setColor("Color", ColorRGBA.Green);
+        mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+        mat2.setColor("Color", ColorRGBA.Red);
+        mat3 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+        mat3.setColor("Color", ColorRGBA.Yellow);
+    }
+
+    private PhysicsSpace getPhysicsSpace() {
+        return bulletAppState.getPhysicsSpace();
+    }
+}