Procházet zdrojové kódy

Merge pull request #196 from Bebul/collideWithOptimization

Collide with optimization
Kirill Vainer před 10 roky
rodič
revize
5508dc05f5

+ 45 - 0
jme3-core/src/main/java/com/jme3/bounding/BoundingBox.java

@@ -761,6 +761,35 @@ public class BoundingBox extends BoundingVolume {
         }
     }
 
+    private int collideWithRay(Ray ray) {
+        TempVars vars = TempVars.get();
+        try {    
+            Vector3f diff = vars.vect1.set(ray.origin).subtractLocal(center);
+            Vector3f direction = vars.vect2.set(ray.direction);
+
+            //float[] t = {0f, Float.POSITIVE_INFINITY};
+            float[] t = vars.fWdU; // use one of the tempvars arrays
+            t[0] = 0;
+            t[1] = Float.POSITIVE_INFINITY;  
+
+            float saveT0 = t[0], saveT1 = t[1];
+            boolean notEntirelyClipped = clip(+direction.x, -diff.x - xExtent, t)
+                    && clip(-direction.x, +diff.x - xExtent, t)
+                    && clip(+direction.y, -diff.y - yExtent, t)
+                    && clip(-direction.y, +diff.y - yExtent, t)
+                    && clip(+direction.z, -diff.z - zExtent, t)
+                    && clip(-direction.z, +diff.z - zExtent, t);
+
+            if (notEntirelyClipped && (t[0] != saveT0 || t[1] != saveT1)) {
+                if (t[1] > t[0]) return 2;
+                else return 1;
+            }
+            return 0;
+        } finally {
+            vars.release();
+        }
+    }
+    
     public int collideWith(Collidable other, CollisionResults results) {
         if (other instanceof Ray) {
             Ray ray = (Ray) other;
@@ -777,6 +806,22 @@ public class BoundingBox extends BoundingVolume {
             throw new UnsupportedCollisionException("With: " + other.getClass().getSimpleName());
         }
     }
+    
+    @Override
+    public int collideWith(Collidable other) {
+        if (other instanceof Ray) {
+            Ray ray = (Ray) other;
+            return collideWithRay(ray);
+        } else if (other instanceof Triangle) {
+            Triangle t = (Triangle) other;
+            if (intersects(t.get1(), t.get2(), t.get3())) {
+                return 1;
+            }
+            return 0;
+        } else {
+            throw new UnsupportedCollisionException("With: " + other.getClass().getSimpleName());
+        }
+    }
 
     /**
      * C code ported from <a href="http://www.cs.lth.se/home/Tomas_Akenine_Moller/code/tribox3.txt">

+ 41 - 1
jme3-core/src/main/java/com/jme3/bounding/BoundingSphere.java

@@ -792,7 +792,35 @@ public class BoundingSphere extends BoundingVolume {
             return 1;
         }
     }
- 
+
+    private int collideWithRay(Ray ray) {
+        TempVars vars = TempVars.get();
+
+        Vector3f diff = vars.vect1.set(ray.getOrigin()).subtractLocal(
+                center);
+        float a = diff.dot(diff) - (getRadius() * getRadius());
+        float a1, discr;
+        if (a <= 0.0) {
+            // inside sphere
+            vars.release();
+            return 1;
+        }
+
+        a1 = ray.direction.dot(diff);
+        vars.release();
+        if (a1 >= 0.0) {
+            return 0;
+        }
+
+        discr = a1 * a1 - a;
+        if (discr < 0.0) {
+            return 0;
+        } else if (discr >= FastMath.ZERO_TOLERANCE) {
+            return 2;
+        }
+        return 1;
+    }
+    
     private int collideWithTri(Triangle tri, CollisionResults results) {
         TempVars tvars = TempVars.get();
         try {
@@ -991,6 +1019,18 @@ public class BoundingSphere extends BoundingVolume {
         }
     }
 
+    @Override public int collideWith(Collidable other) {
+        if (other instanceof Ray) {
+            Ray ray = (Ray) other;
+            return collideWithRay(ray);
+        } else if (other instanceof Triangle){
+            return super.collideWith(other);
+        } else {
+            throw new UnsupportedCollisionException();
+        }
+    }
+
+    
     @Override
     public boolean contains(Vector3f point) {
         return center.distanceSquared(point) < (getRadius() * getRadius());

+ 11 - 0
jme3-core/src/main/java/com/jme3/bounding/BoundingVolume.java

@@ -32,10 +32,12 @@
 package com.jme3.bounding;
 
 import com.jme3.collision.Collidable;
+import com.jme3.collision.CollisionResults;
 import com.jme3.export.JmeExporter;
 import com.jme3.export.JmeImporter;
 import com.jme3.export.Savable;
 import com.jme3.math.*;
+import com.jme3.util.TempVars;
 import java.io.IOException;
 import java.nio.FloatBuffer;
 
@@ -322,6 +324,15 @@ public abstract class BoundingVolume implements Savable, Cloneable, Collidable {
     public void read(JmeImporter e) throws IOException {
         center = (Vector3f) e.getCapsule(this).readSavable("center", Vector3f.ZERO.clone());
     }
+    
+    public int collideWith(Collidable other) {
+        TempVars tempVars = TempVars.get();
+        CollisionResults tempResults = tempVars.collisionResults;
+        tempResults.clear();
+        int retval = collideWith(other, tempResults);
+        tempVars.release();
+        return retval;
+    }
  
 }
 

+ 13 - 0
jme3-core/src/main/java/com/jme3/scene/Node.java

@@ -39,6 +39,7 @@ import com.jme3.export.JmeImporter;
 import com.jme3.export.Savable;
 import com.jme3.material.Material;
 import com.jme3.util.SafeArrayList;
+import com.jme3.util.TempVars;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
@@ -565,6 +566,18 @@ public class Node extends Spatial implements Savable {
 
     public int collideWith(Collidable other, CollisionResults results){
         int total = 0;
+        
+        // optimization: try collideWith BoundingVolume to avoid possibly redundant tests on children
+        // number 4 in condition is somewhat arbitrary. When there is only one child, the boundingVolume test is redundant at all. 
+        // The idea is when there are few children, it can be too expensive to test boundingVolume first.
+        if (children.size() > 4)
+        {
+          BoundingVolume bv = this.getWorldBound();
+          if (bv==null) return 0;
+
+          // collideWith without CollisionResults parameter used to avoid allocation when possible
+          if (bv.collideWith(other) == 0) return 0;
+        }
         for (Spatial child : children.getArray()){
             total += child.collideWith(other, results);
         }