Sfoglia il codice sorgente

* fixed terrain grid issues
* added javadoc

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

bre..ns 14 anni fa
parent
commit
253334fd07

+ 85 - 90
engine/src/terrain/com/jme3/terrain/geomipmap/TerrainGrid.java

@@ -50,12 +50,17 @@ import com.jme3.terrain.heightmap.HeightMapGrid;
 import java.util.concurrent.Callable;
 import java.util.concurrent.Callable;
 
 
 /**
 /**
+ * 
+ * The grid is indexed by cells. Each cell has an integer XZ coordinate originating at 0,0.
+ * TerrainGrid will piggyback on the TerrainLodControl so it can use the camera for its
+ * updates as well. It does this in the overwritten update() method.
+ * 
  * @author Anthyon
  * @author Anthyon
  */
  */
 public class TerrainGrid extends TerrainQuad {
 public class TerrainGrid extends TerrainQuad {
 
 
     protected static final Logger log = Logger.getLogger(TerrainGrid.class.getCanonicalName());
     protected static final Logger log = Logger.getLogger(TerrainGrid.class.getCanonicalName());
-    protected Vector3f currentCell;
+    protected Vector3f currentCamCell;
     protected int quarterSize;
     protected int quarterSize;
     protected int quadSize;
     protected int quadSize;
     protected HeightMapGrid heightMapGrid;
     protected HeightMapGrid heightMapGrid;
@@ -77,7 +82,6 @@ public class TerrainGrid extends TerrainQuad {
         }
         }
 
 
         public void run() {
         public void run() {
-
             for (int i = 0; i < 4; i++) {
             for (int i = 0; i < 4; i++) {
                 for (int j = 0; j < 4; j++) {
                 for (int j = 0; j < 4; j++) {
                     int quadIdx = i * 4 + j;
                     int quadIdx = i * 4 + j;
@@ -86,7 +90,7 @@ public class TerrainGrid extends TerrainQuad {
                     if (q == null) {
                     if (q == null) {
                         // create the new Quad since it doesn't exist
                         // create the new Quad since it doesn't exist
                         HeightMap heightMapAt = heightMapGrid.getHeightMapAt(temp);
                         HeightMap heightMapAt = heightMapGrid.getHeightMapAt(temp);
-                        q = new TerrainQuad(getName() + "Quad" + temp, patchSize, totalSize, quadSize, heightMapAt == null ? null : heightMapAt.getHeightMap());
+                        q = new TerrainQuad(getName() + "Quad" + temp, patchSize, quadSize, heightMapAt == null ? null : heightMapAt.getHeightMap());
                         q.setMaterial(material.clone());
                         q.setMaterial(material.clone());
                         log.log(Level.FINE, "Loaded TerrainQuad {0}", q.getName());
                         log.log(Level.FINE, "Loaded TerrainQuad {0}", q.getName());
                     }
                     }
@@ -116,13 +120,13 @@ public class TerrainGrid extends TerrainQuad {
     }
     }
 
 
     protected int getQuadrant(int quadIndex) {
     protected int getQuadrant(int quadIndex) {
-        if (quadIndex == 9) {
+        if (quadIndex == 5) {
             return 1;
             return 1;
-        } else if (quadIndex == 5) {
+        } else if (quadIndex == 9) {
             return 2;
             return 2;
-        } else if (quadIndex == 10) {
-            return 3;
         } else if (quadIndex == 6) {
         } else if (quadIndex == 6) {
+            return 3;
+        } else if (quadIndex == 10) {
             return 4;
             return 4;
         }
         }
         return 0; // error
         return 0; // error
@@ -141,16 +145,22 @@ public class TerrainGrid extends TerrainQuad {
         this.totalSize = maxVisibleSize;
         this.totalSize = maxVisibleSize;
         this.offset = offset;
         this.offset = offset;
         this.offsetAmount = offsetAmount;
         this.offsetAmount = offsetAmount;
-        //this.lodCalculatorFactory = lodCalculatorFactory;
         this.gridOffset = new int[]{0,0};
         this.gridOffset = new int[]{0,0};
-        //if (lodCalculatorFactory == null) {
-        //    lodCalculatorFactory = new LodDistanceCalculatorFactory();
-        //}
+        
+        /*
+         *        -z
+         *         | 
+         *        1|3 
+         *  -x ----+---- x
+         *        2|4
+         *         |
+         *         z
+         */
         this.quadIndex = new Vector3f[]{
         this.quadIndex = new Vector3f[]{
-        new Vector3f(-1, 0, 2), new Vector3f(0, 0, 2), new Vector3f(1, 0, 2), new Vector3f(2, 0, 2),
-        new Vector3f(-1, 0, 1), new Vector3f(0, 0, 1), new Vector3f(1, 0, 1), new Vector3f(2, 0, 1),
+        new Vector3f(-1, 0, -1), new Vector3f(0, 0, -1), new Vector3f(1, 0, -1), new Vector3f(2, 0, -1),
         new Vector3f(-1, 0, 0), new Vector3f(0, 0, 0), new Vector3f(1, 0, 0), new Vector3f(2, 0, 0),
         new Vector3f(-1, 0, 0), new Vector3f(0, 0, 0), new Vector3f(1, 0, 0), new Vector3f(2, 0, 0),
-        new Vector3f(-1, 0, -1), new Vector3f(0, 0, -1), new Vector3f(1, 0, -1), new Vector3f(-2, 0, -1)};
+        new Vector3f(-1, 0, 1), new Vector3f(0, 0, 1), new Vector3f(1, 0, 1), new Vector3f(2, 0, 1),
+        new Vector3f(-1, 0, 2), new Vector3f(0, 0, 2), new Vector3f(1, 0, 2), new Vector3f(2, 0, 2)};
 
 
         addControl(new UpdateControl());
         addControl(new UpdateControl());
     }
     }
@@ -170,7 +180,7 @@ public class TerrainGrid extends TerrainQuad {
         if (this.material == null) {
         if (this.material == null) {
             throw new RuntimeException("Material must be set prior to call of initialize");
             throw new RuntimeException("Material must be set prior to call of initialize");
         }
         }
-        Vector3f camCell = this.getCell(location);
+        Vector3f camCell = this.getCamCell(location);
         this.updateChildrens(camCell);
         this.updateChildrens(camCell);
         for (TerrainGridListener l : this.listeners.values()) {
         for (TerrainGridListener l : this.listeners.values()) {
             l.gridMoved(camCell);
             l.gridMoved(camCell);
@@ -184,13 +194,14 @@ public class TerrainGrid extends TerrainQuad {
         // 1: every camera has an associated grid, then the location is not enough to identify which camera location has changed
         // 1: every camera has an associated grid, then the location is not enough to identify which camera location has changed
         // 2: grids are associated with locations, and no incremental update is done, we load new grids for new locations, and unload those that are not needed anymore
         // 2: grids are associated with locations, and no incremental update is done, we load new grids for new locations, and unload those that are not needed anymore
         Vector3f cam = locations.get(0);
         Vector3f cam = locations.get(0);
-        Vector3f camCell = this.getCell(cam);
+        Vector3f camCell = this.getCamCell(cam); // get the grid index value of where the camera is (ie. 2,1)
         if(cellsLoaded>1){                  // Check if cells are updated before updating gridoffset.
         if(cellsLoaded>1){                  // Check if cells are updated before updating gridoffset.
             gridOffset[0] = Math.round(camCell.x*(size/2));
             gridOffset[0] = Math.round(camCell.x*(size/2));
             gridOffset[1] = Math.round(camCell.z*(size/2));
             gridOffset[1] = Math.round(camCell.z*(size/2));
             cellsLoaded=0;
             cellsLoaded=0;
         }
         }
-        if (camCell.x != this.currentCell.x || camCell.z != currentCell.z) {
+        if (camCell.x != this.currentCamCell.x || camCell.z != currentCamCell.z) {
+            // if the camera has moved into a new cell, load new terrain into the visible 4 center quads
             this.updateChildrens(camCell);
             this.updateChildrens(camCell);
             for (TerrainGridListener l : this.listeners.values()) {
             for (TerrainGridListener l : this.listeners.values()) {
                 l.gridMoved(camCell);
                 l.gridMoved(camCell);
@@ -199,10 +210,21 @@ public class TerrainGrid extends TerrainQuad {
         super.update(locations, lodCalculator);
         super.update(locations, lodCalculator);
     }
     }
 
 
-    public Vector3f getCell(Vector3f location) {
-        final Vector3f v = location.add(this.getWorldScale().mult((this.quadSize - 1)/2)).divide(this.getWorldScale().mult(this.quadSize - 1)).add(0.5f, 0, 0.5f);
-        
-        return new Vector3f(FastMath.floor(v.x), 0, FastMath.floor(v.z));
+    public Vector3f getCamCell(Vector3f location) {
+        Vector3f tile = getTileCell(location);
+        Vector3f offsetHalf = new Vector3f(-0.5f, 0, -0.5f);
+        Vector3f shifted = tile.subtract(offsetHalf);
+        return new Vector3f(FastMath.floor(shifted.x), 0, FastMath.floor(shifted.z));
+    }
+    
+    /**
+     * Centered at 0,0.
+     * Get the tile index location in integer form:
+     * @param location world coordinate
+     */
+    public Vector3f getTileCell(Vector3f location) {
+        Vector3f tileLoc = location.divide(this.getWorldScale().mult(this.quadSize));
+        return tileLoc;
     }
     }
 
 
     protected void removeQuad(int idx) {
     protected void removeQuad(int idx) {
@@ -211,7 +233,7 @@ public class TerrainGrid extends TerrainQuad {
                 this.getQuad(idx).removeControl(RigidBodyControl.class);
                 this.getQuad(idx).removeControl(RigidBodyControl.class);
             }
             }
             for (TerrainGridListener l : listeners.values()) {
             for (TerrainGridListener l : listeners.values()) {
-                l.tileDetached(getCell(this.getQuad(idx).getWorldTranslation()), this.getQuad(idx));
+                l.tileDetached(getTileCell(this.getQuad(idx).getWorldTranslation()), this.getQuad(idx));
             }
             }
             this.detachChild(this.getQuad(idx));
             this.detachChild(this.getQuad(idx));
             cellsLoaded++; // For gridoffset calc., maybe the run() method is a better location for this.
             cellsLoaded++; // For gridoffset calc., maybe the run() method is a better location for this.
@@ -223,8 +245,7 @@ public class TerrainGrid extends TerrainQuad {
      */
      */
     protected void attachQuadAt(TerrainQuad q, int quadrant, Vector3f cam) {
     protected void attachQuadAt(TerrainQuad q, int quadrant, Vector3f cam) {
         this.removeQuad(quadrant);
         this.removeQuad(quadrant);
-        //q.setMaterial(this.material);
-        //q.setLocalTranslation(quadOrigins[quadrant - 1]);
+        
         q.setQuadrant((short) quadrant);
         q.setQuadrant((short) quadrant);
         this.attachChild(q);
         this.attachChild(q);
 
 
@@ -234,53 +255,66 @@ public class TerrainGrid extends TerrainQuad {
         for (TerrainGridListener l : listeners.values()) {
         for (TerrainGridListener l : listeners.values()) {
             l.tileAttached(cam, q);
             l.tileAttached(cam, q);
         }
         }
-
+        System.err.println("attachQuadAt "+quadrant+", children: "+this.getChildren().size());
         updateModelBound();
         updateModelBound();
     }
     }
 
 
-    protected void updateChildrens(Vector3f cam) {
-        // ---------------------------------------------------
-        // LRU cache is used, so elements that need to remain
-        // should be touched.
-        // ---------------------------------------------------
+    /**
+     * Called when the camera has moved into a new cell. We need to
+     * update what quads are in the scene now.
+     * 
+     * Step 1: touch cache
+     * LRU cache is used, so elements that need to remain
+     * should be touched.
+     *
+     * Step 2: load new quads in background thread
+     * if the camera has moved into a new cell, we load in new quads
+     * @param camCell the cell the camera is in
+     */
+    protected void updateChildrens(Vector3f camCell) {
+        
         int dx = 0;
         int dx = 0;
         int dy = 0;
         int dy = 0;
-        if (currentCell != null) {
-            dx = (int) (cam.x - currentCell.x);
-            dy = (int) (cam.z - currentCell.z);
+        if (currentCamCell != null) {
+            dx = (int) (camCell.x - currentCamCell.x);
+            dy = (int) (camCell.z - currentCamCell.z);
         }
         }
 
 
-        int kxm = 0;
-        int kxM = 4;
-        int kym = 0;
-        int kyM = 4;
-        if (dx == -1) {
-            kxM = 3;
-        } else if (dx == 1) {
-            kxm = 1;
+        int xMin = 0;
+        int xMax = 4;
+        int yMin = 0;
+        int yMax = 4;
+        if (dx == -1) { // camera moved to -X direction
+            xMax = 3;
+        } else if (dx == 1) { // camera moved to +X direction
+            xMin = 1;
         }
         }
 
 
-        if (dy == -1) {
-            kyM = 3;
-        } else if (dy == 1) {
-            kym = 1;
+        if (dy == -1) { // camera moved to -Y direction
+            yMax = 3;
+        } else if (dy == 1) { // camera moved to +Y direction
+            yMin = 1;
         }
         }
 
 
-        for (int i = kym; i < kyM; i++) {
-            for (int j = kxm; j < kxM; j++) {
-                cache.get(cam.add(quadIndex[i * 4 + j]));
+        // Touch the items in the cache that we are and will be interested in.
+        // We activate cells in the direction we are moving. If we didn't move 
+        // either way in one of the axes (say X or Y axis) then they are all touched.
+        for (int i = yMin; i < yMax; i++) {
+            for (int j = xMin; j < xMax; j++) {
+                cache.get(camCell.add(quadIndex[i * 4 + j]));
             }
             }
         }
         }
         // ---------------------------------------------------
         // ---------------------------------------------------
         // ---------------------------------------------------
         // ---------------------------------------------------
 
 
         if (executor == null) {
         if (executor == null) {
+            // use the same executor as the LODControl
             executor = createExecutorService();
             executor = createExecutorService();
         }
         }
 
 
-        executor.submit(new UpdateQuadCache(cam));
+        executor.submit(new UpdateQuadCache(camCell));
 
 
-        this.currentCell = cam;
+        this.currentCamCell = camCell;
     }
     }
 
 
     public void addListener(String id, TerrainGridListener listener) {
     public void addListener(String id, TerrainGridListener listener) {
@@ -288,7 +322,7 @@ public class TerrainGrid extends TerrainQuad {
     }
     }
 
 
     public Vector3f getCurrentCell() {
     public Vector3f getCurrentCell() {
-        return this.currentCell;
+        return this.currentCamCell;
     }
     }
 
 
     public void removeListener(String id) {
     public void removeListener(String id) {
@@ -320,43 +354,4 @@ public class TerrainGrid extends TerrainQuad {
         return super.getHeightmapHeight(x-gridOffset[0], z-gridOffset[1]);
         return super.getHeightmapHeight(x-gridOffset[0], z-gridOffset[1]);
     }
     }
 
 
-    @Override
-    protected TerrainQuad findDownQuad() {
-        if (quadrant == 1) {
-            return cache.get(currentCell.add(quadIndex[13]));
-        } else if (quadrant == 3) {
-            return cache.get(currentCell.add(quadIndex[14]));
-        }
-        return null;
-    }
-
-    @Override
-    protected TerrainQuad findLeftQuad() {
-        if (quadrant == 1) {
-            return cache.get(currentCell.add(quadIndex[8]));
-        } else if (quadrant == 2) {
-            return cache.get(currentCell.add(quadIndex[4]));
-        }
-        return null;
-    }
-
-    @Override
-    protected TerrainQuad findRightQuad() {
-        if (quadrant == 3) {
-            return cache.get(currentCell.add(quadIndex[11]));
-        } else if (quadrant == 4) {
-            return cache.get(currentCell.add(quadIndex[7]));
-        }
-        return null;
-    }
-
-    @Override
-    protected TerrainQuad findTopQuad() {
-        if (quadrant == 2) {
-            return cache.get(currentCell.add(quadIndex[1]));
-        } else if (quadrant == 4) {
-            return cache.get(currentCell.add(quadIndex[2]));
-        }
-        return null;
-    }
 }
 }

+ 18 - 18
engine/src/terrain/com/jme3/terrain/geomipmap/TerrainQuad.java

@@ -80,8 +80,7 @@ import java.util.logging.Logger;
  *
  *
  * 
  * 
  * Heightmap coordinates start from the bottom left of the world and work towards the
  * Heightmap coordinates start from the bottom left of the world and work towards the
- * top right. This will seem upside down, but the texture coordinates compensate; and
- * it allows you to easily get the heightmap values at real world X,Z coordinates.
+ * top right.
  * 
  * 
  *  +x
  *  +x
  *  ^
  *  ^
@@ -108,7 +107,7 @@ public class TerrainQuad extends Node implements Terrain {
 
 
     protected float offsetAmount;
     protected float offsetAmount;
 
 
-    protected int quadrant = 1; // 1=upper left, 2=lower left, 3=upper right, 4=lower right
+    protected int quadrant = 0; // 1=upper left, 2=lower left, 3=upper right, 4=lower right
 
 
     //protected LodCalculatorFactory lodCalculatorFactory;
     //protected LodCalculatorFactory lodCalculatorFactory;
     //protected LodCalculator lodCalculator;
     //protected LodCalculator lodCalculator;
@@ -646,13 +645,14 @@ public class TerrainQuad extends Node implements Terrain {
 
 
     /**
     /**
      * Quadrants, world coordinates, and heightmap coordinates (Y-up):
      * Quadrants, world coordinates, and heightmap coordinates (Y-up):
-     *         x
-     *         | u
-     *        2|4 v
-     *  -z ----+---- z
-     *     -v 1|3
-     *      -u |
-     *        -x
+     * 
+     *         -z
+     *      -u | 
+     *    -v  1|3 
+     *  -x ----+---- x
+     *        2|4 u
+     *         | v
+     *         z
      * <code>createQuad</code> generates four new quads from this quad.
      * <code>createQuad</code> generates four new quads from this quad.
      * The heightmap's top left (0,0) coordinate is at the bottom, -x,-z
      * The heightmap's top left (0,0) coordinate is at the bottom, -x,-z
      * coordinate of the terrain, so it grows in the positive x.z direction.
      * coordinate of the terrain, so it grows in the positive x.z direction.
@@ -669,7 +669,7 @@ public class TerrainQuad extends Node implements Terrain {
         //if (lodCalculator == null)
         //if (lodCalculator == null)
         //    lodCalculator = createDefaultLodCalculator(); // set a default one
         //    lodCalculator = createDefaultLodCalculator(); // set a default one
 
 
-        // 1 upper left of heightmap, lower left quad
+        // 1 upper left of heightmap, upper left quad
         float[] heightBlock1 = createHeightSubBlock(heightMap, 0, 0, split);
         float[] heightBlock1 = createHeightSubBlock(heightMap, 0, 0, split);
 
 
         Vector3f origin1 = new Vector3f(-quarterSize * stepScale.x, 0,
         Vector3f origin1 = new Vector3f(-quarterSize * stepScale.x, 0,
@@ -687,7 +687,7 @@ public class TerrainQuad extends Node implements Terrain {
         quad1.quadrant = 1;
         quad1.quadrant = 1;
         this.attachChild(quad1);
         this.attachChild(quad1);
 
 
-        // 2 lower left of heightmap, upper left quad
+        // 2 lower left of heightmap, lower left quad
         float[] heightBlock2 = createHeightSubBlock(heightMap, 0, split - 1,
         float[] heightBlock2 = createHeightSubBlock(heightMap, 0, split - 1,
                         split);
                         split);
 
 
@@ -707,7 +707,7 @@ public class TerrainQuad extends Node implements Terrain {
         quad2.quadrant = 2;
         quad2.quadrant = 2;
         this.attachChild(quad2);
         this.attachChild(quad2);
 
 
-        // 3 upper right of heightmap, lower right quad
+        // 3 upper right of heightmap, upper right quad
         float[] heightBlock3 = createHeightSubBlock(heightMap, split - 1, 0,
         float[] heightBlock3 = createHeightSubBlock(heightMap, split - 1, 0,
                         split);
                         split);
 
 
@@ -727,7 +727,7 @@ public class TerrainQuad extends Node implements Terrain {
         quad3.quadrant = 3;
         quad3.quadrant = 3;
         this.attachChild(quad3);
         this.attachChild(quad3);
         
         
-        // 4 lower right of heightmap, upper right quad
+        // 4 lower right of heightmap, lower right quad
         float[] heightBlock4 = createHeightSubBlock(heightMap, split - 1,
         float[] heightBlock4 = createHeightSubBlock(heightMap, split - 1,
                         split - 1, split);
                         split - 1, split);
 
 
@@ -779,7 +779,7 @@ public class TerrainQuad extends Node implements Terrain {
 
 
         offsetAmount += quarterSize;
         offsetAmount += quarterSize;
 
 
-        // 1 upper left
+        // 1 lower left
         float[] heightBlock1 = createHeightSubBlock(heightMap, 0, 0, split);
         float[] heightBlock1 = createHeightSubBlock(heightMap, 0, 0, split);
 
 
         Vector3f origin1 = new Vector3f(-halfSize * stepScale.x, 0, -halfSize
         Vector3f origin1 = new Vector3f(-halfSize * stepScale.x, 0, -halfSize
@@ -801,7 +801,7 @@ public class TerrainQuad extends Node implements Terrain {
         //patch1.setLodCalculator(lodCalculator);
         //patch1.setLodCalculator(lodCalculator);
         //TangentBinormalGenerator.generate(patch1);
         //TangentBinormalGenerator.generate(patch1);
 
 
-        // 2 lower left
+        // 2 upper left
         float[] heightBlock2 = createHeightSubBlock(heightMap, 0, split - 1,
         float[] heightBlock2 = createHeightSubBlock(heightMap, 0, split - 1,
                         split);
                         split);
 
 
@@ -823,7 +823,7 @@ public class TerrainQuad extends Node implements Terrain {
         //patch2.setLodCalculator(lodCalculator);
         //patch2.setLodCalculator(lodCalculator);
         //TangentBinormalGenerator.generate(patch2);
         //TangentBinormalGenerator.generate(patch2);
 
 
-        // 3 upper right
+        // 3 lower right
         float[] heightBlock3 = createHeightSubBlock(heightMap, split - 1, 0,
         float[] heightBlock3 = createHeightSubBlock(heightMap, split - 1, 0,
                         split);
                         split);
 
 
@@ -845,7 +845,7 @@ public class TerrainQuad extends Node implements Terrain {
         //patch3.setLodCalculator(lodCalculator);
         //patch3.setLodCalculator(lodCalculator);
         //TangentBinormalGenerator.generate(patch3);
         //TangentBinormalGenerator.generate(patch3);
 
 
-        // 4 lower right
+        // 4 upper right
         float[] heightBlock4 = createHeightSubBlock(heightMap, split - 1,
         float[] heightBlock4 = createHeightSubBlock(heightMap, split - 1,
                         split - 1, split);
                         split - 1, split);