per discussion at http://hub.jmonkeyengine.org/forum/topic/proposed-removal-of-octree-and-related-files git-svn-id: https://jmonkeyengine.googlecode.com/svn/branches/gradle-restructure@11092 75d07b2b-3a1a-0410-a2c5-0572b91ccdcaexperimental
parent
5b530da4d3
commit
5134c6052c
@ -1,169 +0,0 @@ |
||||
/* |
||||
* Copyright (c) 2009-2012 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 jme3tools.optimize; |
||||
|
||||
import com.jme3.bounding.BoundingBox; |
||||
import com.jme3.renderer.Camera; |
||||
import com.jme3.scene.Geometry; |
||||
import java.util.Set; |
||||
|
||||
public class FastOctnode { |
||||
|
||||
int offset; |
||||
int length; |
||||
FastOctnode child; |
||||
FastOctnode next; |
||||
|
||||
private static final BoundingBox tempBox = new BoundingBox(); |
||||
|
||||
public int getSide(){ |
||||
return ((offset & 0xE0000000) >> 29) & 0x7; |
||||
} |
||||
|
||||
public void setSide(int side){ |
||||
offset &= 0x1FFFFFFF; |
||||
offset |= (side << 29); |
||||
} |
||||
|
||||
public void setOffset(int offset){ |
||||
if (offset < 0 || offset > 20000000){ |
||||
throw new IllegalArgumentException(); |
||||
} |
||||
|
||||
this.offset &= 0xE0000000; |
||||
this.offset |= offset; |
||||
} |
||||
|
||||
public int getOffset(){ |
||||
return this.offset & 0x1FFFFFFF; |
||||
} |
||||
|
||||
private void generateRenderSetNoCheck(Geometry[] globalGeomList, Set<Geometry> renderSet, Camera cam){ |
||||
if (length != 0){ |
||||
int start = getOffset(); |
||||
int end = start + length; |
||||
for (int i = start; i < end; i++){ |
||||
renderSet.add(globalGeomList[i]); |
||||
} |
||||
} |
||||
|
||||
if (child == null) |
||||
return; |
||||
|
||||
FastOctnode node = child; |
||||
while (node != null){ |
||||
node.generateRenderSetNoCheck(globalGeomList, renderSet, cam); |
||||
node = node.next; |
||||
} |
||||
} |
||||
|
||||
private static void findChildBound(BoundingBox bbox, int side){ |
||||
float extent = bbox.getXExtent() * 0.5f; |
||||
bbox.getCenter().set(bbox.getCenter().x + extent * Octnode.extentMult[side].x, |
||||
bbox.getCenter().y + extent * Octnode.extentMult[side].y, |
||||
bbox.getCenter().z + extent * Octnode.extentMult[side].z); |
||||
bbox.setXExtent(extent); |
||||
bbox.setYExtent(extent); |
||||
bbox.setZExtent(extent); |
||||
} |
||||
|
||||
public void generateRenderSet(Geometry[] globalGeomList, Set<Geometry> renderSet, Camera cam, BoundingBox parentBox, boolean isRoot){ |
||||
tempBox.setCenter(parentBox.getCenter()); |
||||
tempBox.setXExtent(parentBox.getXExtent()); |
||||
tempBox.setYExtent(parentBox.getYExtent()); |
||||
tempBox.setZExtent(parentBox.getZExtent()); |
||||
|
||||
if (!isRoot){ |
||||
findChildBound(tempBox, getSide()); |
||||
} |
||||
|
||||
tempBox.setCheckPlane(0); |
||||
cam.setPlaneState(0); |
||||
Camera.FrustumIntersect result = cam.contains(tempBox); |
||||
if (result != Camera.FrustumIntersect.Outside){ |
||||
if (length != 0){ |
||||
int start = getOffset(); |
||||
int end = start + length; |
||||
for (int i = start; i < end; i++){ |
||||
renderSet.add(globalGeomList[i]); |
||||
} |
||||
} |
||||
|
||||
if (child == null) |
||||
return; |
||||
|
||||
FastOctnode node = child; |
||||
|
||||
float x = tempBox.getCenter().x; |
||||
float y = tempBox.getCenter().y; |
||||
float z = tempBox.getCenter().z; |
||||
float ext = tempBox.getXExtent(); |
||||
|
||||
while (node != null){ |
||||
if (result == Camera.FrustumIntersect.Inside){ |
||||
node.generateRenderSetNoCheck(globalGeomList, renderSet, cam); |
||||
}else{ |
||||
node.generateRenderSet(globalGeomList, renderSet, cam, tempBox, false); |
||||
} |
||||
|
||||
tempBox.getCenter().set(x,y,z); |
||||
tempBox.setXExtent(ext); |
||||
tempBox.setYExtent(ext); |
||||
tempBox.setZExtent(ext); |
||||
|
||||
node = node.next; |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public String toString(){ |
||||
return "OCTNode[O=" + getOffset() + ", L=" + length + |
||||
", S=" + getSide() + "]"; |
||||
} |
||||
|
||||
public String toStringVerbose(int indent){ |
||||
String str = "------------------".substring(0,indent) + toString() + "\n"; |
||||
if (child == null) |
||||
return str; |
||||
|
||||
FastOctnode children = child; |
||||
while (children != null){ |
||||
str += children.toStringVerbose(indent+1); |
||||
children = children.next; |
||||
} |
||||
|
||||
return str; |
||||
} |
||||
|
||||
} |
@ -1,80 +0,0 @@ |
||||
/* |
||||
* Copyright (c) 2009-2012 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 jme3tools.optimize; |
||||
|
||||
import com.jme3.math.Vector3f; |
||||
|
||||
public final class OCTTriangle { |
||||
|
||||
private final Vector3f pointa = new Vector3f(); |
||||
private final Vector3f pointb = new Vector3f(); |
||||
private final Vector3f pointc = new Vector3f(); |
||||
private final int index; |
||||
private final int geomIndex; |
||||
|
||||
public OCTTriangle(Vector3f p1, Vector3f p2, Vector3f p3, int index, int geomIndex) { |
||||
pointa.set(p1); |
||||
pointb.set(p2); |
||||
pointc.set(p3); |
||||
this.index = index; |
||||
this.geomIndex = geomIndex; |
||||
} |
||||
|
||||
public int getGeometryIndex() { |
||||
return geomIndex; |
||||
} |
||||
|
||||
public int getTriangleIndex() { |
||||
return index; |
||||
} |
||||
|
||||
public Vector3f get1(){ |
||||
return pointa; |
||||
} |
||||
|
||||
public Vector3f get2(){ |
||||
return pointb; |
||||
} |
||||
|
||||
public Vector3f get3(){ |
||||
return pointc; |
||||
} |
||||
|
||||
public Vector3f getNormal(){ |
||||
Vector3f normal = new Vector3f(pointb); |
||||
normal.subtractLocal(pointa).crossLocal(pointc.x-pointa.x, pointc.y-pointa.y, pointc.z-pointa.z); |
||||
normal.normalizeLocal(); |
||||
return normal; |
||||
} |
||||
|
||||
} |
@ -1,317 +0,0 @@ |
||||
/* |
||||
* Copyright (c) 2009-2012 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 jme3tools.optimize; |
||||
|
||||
import com.jme3.bounding.BoundingBox; |
||||
import com.jme3.collision.CollisionResult; |
||||
import com.jme3.collision.CollisionResults; |
||||
import com.jme3.material.Material; |
||||
import com.jme3.math.Matrix4f; |
||||
import com.jme3.math.Ray; |
||||
import com.jme3.math.Triangle; |
||||
import com.jme3.math.Vector3f; |
||||
import com.jme3.renderer.Camera; |
||||
import com.jme3.renderer.queue.RenderQueue; |
||||
import com.jme3.renderer.queue.RenderQueue.Bucket; |
||||
import com.jme3.scene.Geometry; |
||||
import com.jme3.scene.debug.WireBox; |
||||
import java.util.*; |
||||
|
||||
public class Octnode { |
||||
|
||||
static final Vector3f[] extentMult = new Vector3f[] |
||||
{ |
||||
new Vector3f( 1, 1, 1), // right top forw
|
||||
new Vector3f(-1, 1, 1), // left top forw
|
||||
new Vector3f( 1,-1, 1), // right bot forw
|
||||
new Vector3f(-1,-1, 1), // left bot forw
|
||||
new Vector3f( 1, 1,-1), // right top back
|
||||
new Vector3f(-1, 1,-1), // left top back
|
||||
new Vector3f( 1,-1,-1), // right bot back
|
||||
new Vector3f(-1,-1,-1) // left bot back
|
||||
}; |
||||
|
||||
final BoundingBox bbox; |
||||
final ArrayList<OCTTriangle> tris; |
||||
Geometry[] geoms; |
||||
final Octnode[] children = new Octnode[8]; |
||||
boolean leaf = false; |
||||
FastOctnode fastNode; |
||||
|
||||
public Octnode(BoundingBox bbox, ArrayList<OCTTriangle> tris){ |
||||
this.bbox = bbox; |
||||
this.tris = tris; |
||||
} |
||||
|
||||
private BoundingBox getChildBound(int side){ |
||||
float extent = bbox.getXExtent() * 0.5f; |
||||
Vector3f center = new Vector3f(bbox.getCenter().x + extent * extentMult[side].x, |
||||
bbox.getCenter().y + extent * extentMult[side].y, |
||||
bbox.getCenter().z + extent * extentMult[side].z); |
||||
return new BoundingBox(center, extent, extent, extent); |
||||
} |
||||
|
||||
private float getAdditionCost(BoundingBox bbox, OCTTriangle t){ |
||||
if (bbox.intersects(t.get1(), t.get2(), t.get3())){ |
||||
float d1 = bbox.distanceToEdge(t.get1()); |
||||
float d2 = bbox.distanceToEdge(t.get2()); |
||||
float d3 = bbox.distanceToEdge(t.get3()); |
||||
return d1 + d2 + d3; |
||||
} |
||||
return Float.POSITIVE_INFINITY; |
||||
} |
||||
|
||||
private void expandBoxToContainTri(BoundingBox bbox, OCTTriangle t){ |
||||
Vector3f min = bbox.getMin(null); |
||||
Vector3f max = bbox.getMax(null); |
||||
BoundingBox.checkMinMax(min, max, t.get1()); |
||||
BoundingBox.checkMinMax(min, max, t.get2()); |
||||
BoundingBox.checkMinMax(min, max, t.get3()); |
||||
bbox.setMinMax(min, max); |
||||
} |
||||
|
||||
private boolean contains(BoundingBox bbox, OCTTriangle t){ |
||||
if (bbox.contains(t.get1()) && |
||||
bbox.contains(t.get2()) && |
||||
bbox.contains(t.get3())){ |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
public void subdivide(int depth, int maxDepth, float maxVolume, int minTrisPerNode){ |
||||
if (tris == null || depth > maxDepth || bbox.getVolume() < maxVolume || tris.size() < minTrisPerNode){ |
||||
// no need to subdivide anymore
|
||||
leaf = true; |
||||
return; |
||||
} |
||||
|
||||
ArrayList<OCTTriangle> keepTris = new ArrayList<OCTTriangle>(); |
||||
ArrayList[] trisForChild = new ArrayList[8]; |
||||
BoundingBox[] boxForChild = new BoundingBox[8]; |
||||
// create boxes for children
|
||||
for (int i = 0; i < 8; i++){ |
||||
boxForChild[i] = getChildBound(i); |
||||
trisForChild[i] = new ArrayList<Triangle>(); |
||||
} |
||||
|
||||
for (OCTTriangle t : tris){ |
||||
float lowestCost = Float.POSITIVE_INFINITY; |
||||
int lowestIndex = -1; |
||||
int numIntersecting = 0; |
||||
for (int i = 0; i < 8; i++){ |
||||
BoundingBox childBox = boxForChild[i]; |
||||
float cost = getAdditionCost(childBox, t); |
||||
if (cost < lowestCost){ |
||||
lowestCost = cost; |
||||
lowestIndex = i; |
||||
numIntersecting++; |
||||
} |
||||
} |
||||
if (numIntersecting < 8 && lowestIndex > -1){ |
||||
trisForChild[lowestIndex].add(t); |
||||
expandBoxToContainTri(boxForChild[lowestIndex], t); |
||||
}else{ |
||||
keepTris.add(t); |
||||
} |
||||
// boolean wasAdded = false;
|
||||
// for (int i = 0; i < 8; i++){
|
||||
// BoundingBox childBox = boxForChild[i];
|
||||
// if (contains(childBox, t)){
|
||||
// trisForChild[i].add(t);
|
||||
// wasAdded = true;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// if (!wasAdded){
|
||||
// keepTris.add(t);
|
||||
// }
|
||||
} |
||||
tris.retainAll(keepTris); |
||||
for (int i = 0; i < 8; i++){ |
||||
if (trisForChild[i].size() > 0){ |
||||
children[i] = new Octnode(boxForChild[i], trisForChild[i]); |
||||
children[i].subdivide(depth + 1, maxDepth, maxVolume, minTrisPerNode); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public void subdivide(int maxDepth, float maxVolume, int minTrisPerNode){ |
||||
subdivide(0, maxDepth, maxVolume, minTrisPerNode); |
||||
} |
||||
|
||||
public void createFastOctnode(List<Geometry> globalGeomList){ |
||||
fastNode = new FastOctnode(); |
||||
|
||||
if (geoms != null){ |
||||
Collection<Geometry> geomsColl = Arrays.asList(geoms); |
||||
List<Geometry> myOptimizedList = GeometryBatchFactory.makeBatches(geomsColl); |
||||
|
||||
int startIndex = globalGeomList.size(); |
||||
globalGeomList.addAll(myOptimizedList); |
||||
|
||||
fastNode.setOffset(startIndex); |
||||
fastNode.length = myOptimizedList.size(); |
||||
}else{ |
||||
fastNode.setOffset(0); |
||||
fastNode.length = 0; |
||||
} |
||||
|
||||
for (int i = 0; i < 8; i++){ |
||||
if (children[i] != null){ |
||||
children[i].createFastOctnode(globalGeomList); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public void generateFastOctnodeLinks(Octnode parent, Octnode nextSibling, int side){ |
||||
fastNode.setSide(side); |
||||
fastNode.next = nextSibling != null ? nextSibling.fastNode : null; |
||||
|
||||
// We set the next sibling property by going in reverse order
|
||||
Octnode prev = null; |
||||
for (int i = 7; i >= 0; i--){ |
||||
if (children[i] != null){ |
||||
children[i].generateFastOctnodeLinks(this, prev, i); |
||||
prev = children[i]; |
||||
} |
||||
} |
||||
fastNode.child = prev != null ? prev.fastNode : null; |
||||
} |
||||
|
||||
private void generateRenderSetNoCheck(Set<Geometry> renderSet, Camera cam){ |
||||
if (geoms != null){ |
||||
renderSet.addAll(Arrays.asList(geoms)); |
||||
} |
||||
for (int i = 0; i < 8; i++){ |
||||
if (children[i] != null){ |
||||
children[i].generateRenderSetNoCheck(renderSet, cam); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public void generateRenderSet(Set<Geometry> renderSet, Camera cam){ |
||||
// generateRenderSetNoCheck(renderSet, cam);
|
||||
|
||||
bbox.setCheckPlane(0); |
||||
cam.setPlaneState(0); |
||||
Camera.FrustumIntersect result = cam.contains(bbox); |
||||
if (result != Camera.FrustumIntersect.Outside){ |
||||
if (geoms != null){ |
||||
renderSet.addAll(Arrays.asList(geoms)); |
||||
} |
||||
for (int i = 0; i < 8; i++){ |
||||
if (children[i] != null){ |
||||
if (result == Camera.FrustumIntersect.Inside){ |
||||
children[i].generateRenderSetNoCheck(renderSet, cam); |
||||
}else{ |
||||
children[i].generateRenderSet(renderSet, cam); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
public void collectTriangles(Geometry[] inGeoms){ |
||||
if (tris.size() > 0){ |
||||
List<Geometry> geomsList = TriangleCollector.gatherTris(inGeoms, tris); |
||||
geoms = new Geometry[geomsList.size()]; |
||||
geomsList.toArray(geoms); |
||||
}else{ |
||||
geoms = null; |
||||
} |
||||
for (int i = 0; i < 8; i++){ |
||||
if (children[i] != null){ |
||||
children[i].collectTriangles(inGeoms); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public void renderBounds(RenderQueue rq, Matrix4f transform, WireBox box, Material mat){ |
||||
int numChilds = 0; |
||||
for (int i = 0; i < 8; i++){ |
||||
if (children[i] != null){ |
||||
numChilds ++; |
||||
break; |
||||
} |
||||
} |
||||
if (geoms != null && numChilds == 0){ |
||||
BoundingBox bbox2 = new BoundingBox(bbox); |
||||
bbox.transform(transform, bbox2); |
||||
// WireBox box = new WireBox(bbox2.getXExtent(), bbox2.getYExtent(),
|
||||
// bbox2.getZExtent());
|
||||
// WireBox box = new WireBox(1,1,1);
|
||||
|
||||
Geometry geom = new Geometry("bound", box); |
||||
geom.setLocalTranslation(bbox2.getCenter()); |
||||
geom.setLocalScale(bbox2.getXExtent(), bbox2.getYExtent(), |
||||
bbox2.getZExtent()); |
||||
geom.updateGeometricState(); |
||||
geom.setMaterial(mat); |
||||
rq.addToQueue(geom, Bucket.Opaque); |
||||
box = null; |
||||
geom = null; |
||||
} |
||||
for (int i = 0; i < 8; i++){ |
||||
if (children[i] != null){ |
||||
children[i].renderBounds(rq, transform, box, mat); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public final void intersectWhere(Ray r, Geometry[] geoms, float sceneMin, float sceneMax, |
||||
CollisionResults results){ |
||||
for (OCTTriangle t : tris){ |
||||
float d = r.intersects(t.get1(), t.get2(), t.get3()); |
||||
if (Float.isInfinite(d)) |
||||
continue; |
||||
|
||||
Vector3f contactPoint = new Vector3f(r.getDirection()).multLocal(d).addLocal(r.getOrigin()); |
||||
CollisionResult result = new CollisionResult(geoms[t.getGeometryIndex()], |
||||
contactPoint, |
||||
d, |
||||
t.getTriangleIndex()); |
||||
results.addCollision(result); |
||||
} |
||||
for (int i = 0; i < 8; i++){ |
||||
Octnode child = children[i]; |
||||
if (child == null) |
||||
continue; |
||||
|
||||
if (child.bbox.intersects(r)){ |
||||
child.intersectWhere(r, geoms, sceneMin, sceneMax, results); |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
@ -1,156 +0,0 @@ |
||||
/* |
||||
* Copyright (c) 2009-2012 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 jme3tools.optimize; |
||||
|
||||
import com.jme3.bounding.BoundingBox; |
||||
import com.jme3.bounding.BoundingVolume; |
||||
import com.jme3.collision.CollisionResults; |
||||
import com.jme3.material.Material; |
||||
import com.jme3.math.Matrix4f; |
||||
import com.jme3.math.Ray; |
||||
import com.jme3.math.Triangle; |
||||
import com.jme3.renderer.Camera; |
||||
import com.jme3.renderer.queue.RenderQueue; |
||||
import com.jme3.scene.Geometry; |
||||
import com.jme3.scene.Mesh; |
||||
import com.jme3.scene.Node; |
||||
import com.jme3.scene.Spatial; |
||||
import com.jme3.scene.debug.WireBox; |
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
import java.util.Set; |
||||
|
||||
public class Octree { |
||||
|
||||
private final ArrayList<OCTTriangle> allTris = new ArrayList<OCTTriangle>(); |
||||
private final Geometry[] geoms; |
||||
private final BoundingBox bbox; |
||||
private Octnode root; |
||||
|
||||
private CollisionResults boundResults = new CollisionResults(); |
||||
|
||||
private static List<Geometry> getGeometries(Spatial scene){ |
||||
if (scene instanceof Geometry){ |
||||
List<Geometry> geomList = new ArrayList<Geometry>(1); |
||||
geomList.add((Geometry) scene); |
||||
return geomList; |
||||
}else if (scene instanceof Node){ |
||||
Node n = (Node) scene; |
||||
List<Geometry> geoms = new ArrayList<Geometry>(); |
||||
for (Spatial child : n.getChildren()){ |
||||
geoms.addAll(getGeometries(child)); |
||||
} |
||||
return geoms; |
||||
}else{ |
||||
throw new UnsupportedOperationException("Unsupported scene element class"); |
||||
} |
||||
} |
||||
|
||||
public Octree(Spatial scene){ |
||||
scene.updateGeometricState(); |
||||
|
||||
List<Geometry> geomsList = getGeometries(scene); |
||||
geoms = new Geometry[geomsList.size()]; |
||||
geomsList.toArray(geoms); |
||||
// generate bound box for all geom
|
||||
bbox = new BoundingBox(); |
||||
for (Geometry geom : geoms){ |
||||
BoundingVolume bv = geom.getWorldBound(); |
||||
bbox.mergeLocal(bv); |
||||
} |
||||
|
||||
// set largest extent
|
||||
float extent = Math.max(bbox.getXExtent(), Math.max(bbox.getYExtent(), bbox.getZExtent())); |
||||
bbox.setXExtent(extent); |
||||
bbox.setYExtent(extent); |
||||
bbox.setZExtent(extent); |
||||
|
||||
Triangle t = new Triangle(); |
||||
for (int g = 0; g < geoms.length; g++){ |
||||
Mesh m = geoms[g].getMesh(); |
||||
for (int i = 0; i < m.getTriangleCount(); i++){ |
||||
m.getTriangle(i, t); |
||||
OCTTriangle ot = new OCTTriangle(t.get1(), t.get2(), t.get3(), i, g); |
||||
allTris.add(ot); |
||||
// convert triangle to world space
|
||||
// geom.getWorldTransform().transformVector(t.get1(), t.get1());
|
||||
// geom.getWorldTransform().transformVector(t.get2(), t.get2());
|
||||
// geom.getWorldTransform().transformVector(t.get3(), t.get3());
|
||||
} |
||||
} |
||||
} |
||||
|
||||
public void construct(int maxDepth, float maxVolume, int minTrisPerNode){ |
||||
root = new Octnode(bbox, allTris); |
||||
root.subdivide(maxDepth, maxVolume, minTrisPerNode); |
||||
root.collectTriangles(geoms); |
||||
} |
||||
|
||||
public void createFastOctnodes(List<Geometry> globalGeomList){ |
||||
root.createFastOctnode(globalGeomList); |
||||
} |
||||
|
||||
public BoundingBox getBound(){ |
||||
return bbox; |
||||
} |
||||
|
||||
public FastOctnode getFastRoot(){ |
||||
return root.fastNode; |
||||
} |
||||
|
||||
public void generateFastOctnodeLinks(){ |
||||
root.generateFastOctnodeLinks(null, null, 0); |
||||
} |
||||
|
||||
public void generateRenderSet(Set<Geometry> renderSet, Camera cam){ |
||||
root.generateRenderSet(renderSet, cam); |
||||
} |
||||
|
||||
public void renderBounds(RenderQueue rq, Matrix4f transform, WireBox box, Material mat){ |
||||
root.renderBounds(rq, transform, box, mat); |
||||
} |
||||
|
||||
public void intersect(Ray r, float farPlane, Geometry[] geoms, CollisionResults results){ |
||||
boundResults.clear(); |
||||
bbox.collideWith(r, boundResults); |
||||
if (boundResults.size() > 0){ |
||||
float tMin = boundResults.getClosestCollision().getDistance(); |
||||
float tMax = boundResults.getFarthestCollision().getDistance(); |
||||
|
||||
tMin = Math.max(tMin, 0); |
||||
tMax = Math.min(tMax, farPlane); |
||||
|
||||
root.intersectWhere(r, geoms, tMin, tMax, results); |
||||
} |
||||
} |
||||
} |
@ -1,54 +0,0 @@ |
||||
/* |
||||
* Copyright (c) 2009-2012 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 jme3tools.optimize; |
||||
|
||||
import com.jme3.math.Vector3f; |
||||
import com.jme3.scene.Geometry; |
||||
import com.jme3.scene.shape.Quad; |
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
public class TestCollector { |
||||
|
||||
public static void main(String[] args){ |
||||
Vector3f z = Vector3f.ZERO; |
||||
Geometry g = new Geometry("quad", new Quad(2,2)); |
||||
Geometry g2 = new Geometry("quad", new Quad(2,2)); |
||||
List<OCTTriangle> tris = new ArrayList<OCTTriangle>(); |
||||
tris.add(new OCTTriangle(z, z, z, 1, 0)); |
||||
tris.add(new OCTTriangle(z, z, z, 0, 1)); |
||||
List<Geometry> firstOne = TriangleCollector.gatherTris(new Geometry[]{ g, g2 }, tris); |
||||
System.out.println(firstOne.get(0).getMesh()); |
||||
} |
||||
|
||||
} |
@ -1,248 +0,0 @@ |
||||
/* |
||||
* Copyright (c) 2009-2012 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 jme3tools.optimize; |
||||
|
||||
import com.jme3.light.Light; |
||||
import com.jme3.scene.Geometry; |
||||
import com.jme3.scene.Mesh; |
||||
import com.jme3.scene.VertexBuffer; |
||||
import com.jme3.scene.VertexBuffer.Type; |
||||
import com.jme3.util.BufferUtils; |
||||
import com.jme3.util.IntMap; |
||||
import com.jme3.util.IntMap.Entry; |
||||
import java.nio.Buffer; |
||||
import java.nio.ShortBuffer; |
||||
import java.util.*; |
||||
|
||||
public class TriangleCollector { |
||||
|
||||
private static final GeomTriComparator comparator = new GeomTriComparator(); |
||||
|
||||
private static class GeomTriComparator implements Comparator<OCTTriangle> { |
||||
public int compare(OCTTriangle a, OCTTriangle b) { |
||||
if (a.getGeometryIndex() < b.getGeometryIndex()){ |
||||
return -1; |
||||
}else if (a.getGeometryIndex() > b.getGeometryIndex()){ |
||||
return 1; |
||||
}else{ |
||||
return 0; |
||||
} |
||||
} |
||||
} |
||||
|
||||
private static class Range { |
||||
|
||||
private int start, length; |
||||
|
||||
public Range(int start, int length) { |
||||
this.start = start; |
||||
this.length = length; |
||||
} |
||||
|
||||
public int getLength() { |
||||
return length; |
||||
} |
||||
|
||||
public void setLength(int length) { |
||||
this.length = length; |
||||
} |
||||
|
||||
public int getStart() { |
||||
return start; |
||||
} |
||||
|
||||
public void setStart(int start) { |
||||
this.start = start; |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* Grabs all the triangles specified in <code>tris</code> from the input array |
||||
* (using the indices OCTTriangle.getGeometryIndex() & OCTTriangle.getTriangleIndex()) |
||||
* then organizes them into output geometry. |
||||
* |
||||
* @param inGeoms |
||||
* @param tris |
||||
* @return The optimized geometries |
||||
*/ |
||||
public static final List<Geometry> gatherTris(Geometry[] inGeoms, List<OCTTriangle> tris){ |
||||
Collections.sort(tris, comparator); |
||||
HashMap<Integer, Range> ranges = new HashMap<Integer, Range>(); |
||||
|
||||
for (int i = 0; i < tris.size(); i++){ |
||||
Range r = ranges.get(tris.get(i).getGeometryIndex()); |
||||
if (r != null){ |
||||
// incremenet length
|
||||
r.setLength(r.getLength()+1); |
||||
}else{ |
||||
// set offset, length is 1
|
||||
ranges.put(tris.get(i).getGeometryIndex(), new Range(i, 1)); |
||||
} |
||||
} |
||||
|
||||
List<Geometry> newGeoms = new ArrayList<Geometry>(); |
||||
int[] vertIndicies = new int[3]; |
||||
int[] newIndices = new int[3]; |
||||
boolean[] vertexCreated = new boolean[3]; |
||||
HashMap<Integer, Integer> indexCache = new HashMap<Integer, Integer>(); |
||||
for (Map.Entry<Integer, Range> entry : ranges.entrySet()){ |
||||
int inGeomIndex = entry.getKey().intValue(); |
||||
int outOffset = entry.getValue().start; |
||||
int outLength = entry.getValue().length; |
||||
|
||||
Geometry inGeom = inGeoms[inGeomIndex]; |
||||
Mesh in = inGeom.getMesh(); |
||||
Mesh out = new Mesh(); |
||||
|
||||
int outElementCount = outLength * 3; |
||||
ShortBuffer ib = BufferUtils.createShortBuffer(outElementCount); |
||||
out.setBuffer(Type.Index, 3, ib); |
||||
|
||||
// generate output buffers based on input buffers
|
||||
IntMap<VertexBuffer> bufs = in.getBuffers(); |
||||
for (Entry<VertexBuffer> ent : bufs){ |
||||
VertexBuffer vb = ent.getValue(); |
||||
if (vb.getBufferType() == Type.Index) |
||||
continue; |
||||
|
||||
// NOTE: we are not actually sure
|
||||
// how many elements will be in this buffer.
|
||||
// It will be compacted later.
|
||||
Buffer b = VertexBuffer.createBuffer(vb.getFormat(), |
||||
vb.getNumComponents(), |
||||
outElementCount); |
||||
|
||||
VertexBuffer outVb = new VertexBuffer(vb.getBufferType()); |
||||
outVb.setNormalized(vb.isNormalized()); |
||||
outVb.setupData(vb.getUsage(), vb.getNumComponents(), vb.getFormat(), b); |
||||
out.setBuffer(outVb); |
||||
} |
||||
|
||||
int currentVertex = 0; |
||||
for (int i = outOffset; i < outOffset + outLength; i++){ |
||||
OCTTriangle t = tris.get(i); |
||||
|
||||
// find vertex indices for triangle t
|
||||
in.getTriangle(t.getTriangleIndex(), vertIndicies); |
||||
|
||||
// find indices in new buf
|
||||
Integer i0 = indexCache.get(vertIndicies[0]); |
||||
Integer i1 = indexCache.get(vertIndicies[1]); |
||||
Integer i2 = indexCache.get(vertIndicies[2]); |
||||
|
||||
// check which ones were not created
|
||||
// if not created in new IB, create them
|
||||
if (i0 == null){ |
||||
vertexCreated[0] = true; |
||||
newIndices[0] = currentVertex++; |
||||
indexCache.put(vertIndicies[0], newIndices[0]); |
||||
}else{ |
||||
newIndices[0] = i0.intValue(); |
||||
vertexCreated[0] = false; |
||||
} |
||||
if (i1 == null){ |
||||
vertexCreated[1] = true; |
||||
newIndices[1] = currentVertex++; |
||||
indexCache.put(vertIndicies[1], newIndices[1]); |
||||
}else{ |
||||
newIndices[1] = i1.intValue(); |
||||
vertexCreated[1] = false; |
||||
} |
||||
if (i2 == null){ |
||||
vertexCreated[2] = true; |
||||
newIndices[2] = currentVertex++; |
||||
indexCache.put(vertIndicies[2], newIndices[2]); |
||||
}else{ |
||||
newIndices[2] = i2.intValue(); |
||||
vertexCreated[2] = false; |
||||
} |
||||
|
||||
// if any verticies were created for this triangle
|
||||
// copy them to the output mesh
|
||||
IntMap<VertexBuffer> inbufs = in.getBuffers(); |
||||
for (Entry<VertexBuffer> ent : inbufs){ |
||||
VertexBuffer vb = ent.getValue(); |
||||
if (vb.getBufferType() == Type.Index) |
||||
continue; |
||||
|
||||
VertexBuffer outVb = out.getBuffer(vb.getBufferType()); |
||||
// copy verticies that were created for this triangle
|
||||
for (int v = 0; v < 3; v++){ |
||||
if (!vertexCreated[v]) |
||||
continue; |
||||
|
||||
// copy triangle's attribute from one
|
||||
// buffer to another
|
||||
vb.copyElement(vertIndicies[v], outVb, newIndices[v]); |
||||
} |
||||
} |
||||
|
||||
// write the indices onto the output index buffer
|
||||
ib.put((short)newIndices[0]) |
||||
.put((short)newIndices[1]) |
||||
.put((short)newIndices[2]); |
||||
} |
||||
ib.clear(); |
||||
indexCache.clear(); |
||||
|
||||
// since some verticies were cached, it means there's
|
||||
// extra data in some buffers
|
||||
IntMap<VertexBuffer> outbufs = out.getBuffers(); |
||||
for (Entry<VertexBuffer> ent : outbufs){ |
||||
VertexBuffer vb = ent.getValue(); |
||||
if (vb.getBufferType() == Type.Index) |
||||
continue; |
||||
|
||||
vb.compact(currentVertex); |
||||
} |
||||
|
||||
out.updateBound(); |
||||
out.updateCounts(); |
||||
out.setStatic(); |
||||
//out.setInterleaved();
|
||||
Geometry outGeom = new Geometry("Geom"+entry.getKey(), out); |
||||
outGeom.setLocalTransform(inGeom.getWorldTransform()); |
||||
outGeom.setMaterial(inGeom.getMaterial()); |
||||
for (Light light : inGeom.getWorldLightList()){ |
||||
outGeom.addLight(light); |
||||
} |
||||
|
||||
outGeom.updateGeometricState(); |
||||
newGeoms.add(outGeom); |
||||
} |
||||
|
||||
return newGeoms; |
||||
} |
||||
|
||||
} |
@ -1,40 +0,0 @@ |
||||
convert all leafs in octree to PvsNode, add to list pvsNodes |
||||
|
||||
for (every nodeX in pvsNodes): |
||||
for (every nodeY in pvsNodes): |
||||
if (nodeX == nodeY or nodeX adjecent or intersecting nodeY): |
||||
continue |
||||
|
||||
setup camera for (nodeX, nodeY) |
||||
draw every node except nodeX & nodeY |
||||
|
||||
turn on occlusion query |
||||
draw nodeY as bounding box |
||||
turn off occlusion query |
||||
|
||||
if (numSamples > 0): // node is visible |
||||
add nodeY to nodeX's potentially visible set |
||||
|
||||
|
||||
setup camera for node, sideI: |
||||
|
||||
float width, height, near; |
||||
|
||||
switch (sideI): |
||||
case X+ |
||||
case X- |
||||
width = x extent |
||||
height = y extent |
||||
near = z extent / 2 |
||||
case Y+ |
||||
case Y- |
||||
width = x extent |
||||
height = z extent |
||||
near = y extent / 2 |
||||
case Z+ |
||||
case Z- |
||||
width = z extent |
||||
height = y extent |
||||
near = x extent / 2 |
||||
|
||||
|
Loading…
Reference in new issue