remove 8 octree optimization files from trunk

per discussion at http://hub.jmonkeyengine.org/forum/topic/proposed-removal-of-octree-and-related-files

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@11093 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
experimental
sgold 11 years ago
parent f5ccf45aed
commit 5eb5f0d2cc
  1. 163
      engine/src/test/jme3test/tools/TestOctree.java
  2. 169
      engine/src/tools/jme3tools/optimize/FastOctnode.java
  3. 80
      engine/src/tools/jme3tools/optimize/OCTTriangle.java
  4. 317
      engine/src/tools/jme3tools/optimize/Octnode.java
  5. 156
      engine/src/tools/jme3tools/optimize/Octree.java
  6. 54
      engine/src/tools/jme3tools/optimize/TestCollector.java
  7. 248
      engine/src/tools/jme3tools/optimize/TriangleCollector.java
  8. 40
      engine/src/tools/jme3tools/optimize/pvsnotes

@ -1,163 +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 jme3test.tools;
import com.jme3.app.SimpleApplication;
import com.jme3.bounding.BoundingBox;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
import com.jme3.material.MaterialList;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.post.SceneProcessor;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.Geometry;
import com.jme3.scene.Spatial;
import com.jme3.scene.debug.WireBox;
import com.jme3.scene.plugins.ogre.MeshLoader;
import com.jme3.scene.plugins.ogre.OgreMeshKey;
import com.jme3.texture.FrameBuffer;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import jme3tools.optimize.FastOctnode;
import jme3tools.optimize.Octree;
public class TestOctree extends SimpleApplication implements SceneProcessor {
private Octree tree;
private FastOctnode fastRoot;
private Geometry[] globalGeoms;
private BoundingBox octBox;
private Set<Geometry> renderSet = new HashSet<Geometry>(300);
private Material mat, mat2;
private WireBox box = new WireBox(1,1,1);
public static void main(String[] args){
TestOctree app = new TestOctree();
app.start();
}
public void simpleInitApp() {
// this.flyCam.setMoveSpeed(2000);
// this.cam.setFrustumFar(10000);
// mat = new Material(assetManager, "Common/MatDefs/Misc/WireColor.j3md");
// mat.setColor("Color", ColorRGBA.White);
// mat2 = new Material(assetManager, "Common/MatDefs/Misc/ShowNormals.j3md");
assetManager.registerLocator("quake3level.zip", com.jme3.asset.plugins.ZipLocator.class);
MaterialList matList = (MaterialList) assetManager.loadAsset("Scene.material");
OgreMeshKey key = new OgreMeshKey("main.meshxml", matList);
Spatial scene = assetManager.loadModel(key);
// Spatial scene = assetManager.loadModel("Models/Teapot/teapot.obj");
// scene.scale(3);
DirectionalLight dl = new DirectionalLight();
dl.setColor(ColorRGBA.White);
dl.setDirection(new Vector3f(-1, -1, -1).normalize());
rootNode.addLight(dl);
DirectionalLight dl2 = new DirectionalLight();
dl2.setColor(ColorRGBA.White);
dl2.setDirection(new Vector3f(1, -1, 1).normalize());
rootNode.addLight(dl2);
// generate octree
// tree = new Octree(scene, 20000);
tree = new Octree(scene);
tree.construct(50, 0.01f, 50);
ArrayList<Geometry> globalGeomList = new ArrayList<Geometry>();
tree.createFastOctnodes(globalGeomList);
tree.generateFastOctnodeLinks();
for (Geometry geom : globalGeomList){
geom.addLight(dl);
geom.addLight(dl2);
geom.updateGeometricState();
}
globalGeoms = globalGeomList.toArray(new Geometry[0]);
fastRoot = tree.getFastRoot();
octBox = tree.getBound();
viewPort.addProcessor(this);
}
public void initialize(RenderManager rm, ViewPort vp) {
}
public void reshape(ViewPort vp, int w, int h) {
}
public boolean isInitialized() {
return true;
}
public void preFrame(float tpf) {
}
public void postQueue(RenderQueue rq) {
renderSet.clear();
//tree.generateRenderSet(renderSet, cam);
fastRoot.generateRenderSet(globalGeoms, renderSet, cam, octBox, true);
// System.out.println("Geoms: "+renderSet.size());
int tris = 0;
for (Geometry geom : renderSet){
tris += geom.getTriangleCount();
// geom.setMaterial(mat2);
rq.addToQueue(geom, geom.getQueueBucket());
}
// Matrix4f transform = new Matrix4f();
// transform.setScale(0.2f, 0.2f, 0.2f);
// System.out.println("Tris: "+tris);
// tree.renderBounds(rq, transform, box, mat);
// renderManager.flushQueue(viewPort);
}
public void postFrame(FrameBuffer out) {
}
public void cleanup() {
}
}

@ -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…
Cancel
Save