Browse Source

* fixed lod bug in TerrainGrid
* flipped the grid orientation to match the Quad's orientation
* removed blocking call to loading thread

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

bre..ns 14 years ago
parent
commit
1a08b7b0f6

+ 144 - 58
engine/src/terrain/com/jme3/terrain/geomipmap/TerrainGrid.java

@@ -1,9 +1,38 @@
 /*
- * To change this template, choose Tools | Templates
- * and open the template in the editor.
+ * Copyright (c) 2009-2010 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *   may be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 package com.jme3.terrain.geomipmap;
 
+import com.jme3.scene.control.UpdateControl;
+import com.jme3.app.Application;
 import com.jme3.bullet.PhysicsSpace;
 import com.jme3.bullet.collision.shapes.HeightfieldCollisionShape;
 import com.jme3.bullet.control.RigidBodyControl;
@@ -19,10 +48,11 @@ import com.jme3.material.Material;
 import com.jme3.math.FastMath;
 import com.jme3.math.Vector2f;
 import com.jme3.math.Vector3f;
+import com.jme3.renderer.Camera;
 import com.jme3.terrain.geomipmap.lodcalc.LodCalculatorFactory;
 import com.jme3.terrain.geomipmap.lodcalc.LodDistanceCalculatorFactory;
 import com.jme3.terrain.heightmap.HeightMapGrid;
-import com.jme3.terrain.heightmap.RawHeightMap;
+import java.util.concurrent.Callable;
 
 /**
  * @author Anthyon
@@ -34,7 +64,7 @@ public class TerrainGrid extends TerrainQuad {
     private int quarterSize;
     private int quadSize;
     private HeightMapGrid heightMapGrid;
-    private Vector3f[] quadOrigins;
+    //private Vector3f[] quadOrigins;
     private Vector3f[] quadIndex;
     private Map<String, TerrainGridListener> listeners = new HashMap<String, TerrainGridListener>();
     private Material material;
@@ -45,77 +75,107 @@ public class TerrainGrid extends TerrainQuad {
     private class UpdateQuadCache implements Runnable {
 
         private final Vector3f location;
-        private final boolean centerOnly;
 
         public UpdateQuadCache(Vector3f location) {
             this.location = location;
-            this.centerOnly = false;
-        }
-
-        public UpdateQuadCache(Vector3f location, boolean centerOnly) {
-            this.location = location;
-            this.centerOnly = centerOnly;
         }
 
         public void run() {
-            for (int i = centerOnly ? 1 : 0; i < (centerOnly ? 3 : 4); i++) {
-                for (int j = centerOnly ? 1 : 0; j < (centerOnly ? 3 : 4); j++) {
-                    Vector3f temp = location.add(quadIndex[i * 4 + j]);
-                    if (cache.get(temp) == null) {
+            
+            for (int i = 0; i < 4; i++) {
+                for (int j = 0; j < 4; j++) {
+                    int quadIdx = i * 4 + j;
+                    final Vector3f temp = location.add(quadIndex[quadIdx]);
+                    TerrainQuad q = cache.get(temp);
+                    if (q == null) {
+                        // create the new Quad since it doesn't exist
                         HeightMap heightMapAt = heightMapGrid.getHeightMapAt(temp);
-                        TerrainQuad q = new TerrainQuad(getName() + "Quad" + temp, patchSize, quadSize, heightMapAt == null ? null : heightMapAt.getHeightMap(), lodCalculatorFactory);
+                        q = new TerrainQuad(getName() + "Quad" + temp, patchSize, quadSize, totalSize, heightMapAt == null ? null : heightMapAt.getHeightMap(), lodCalculatorFactory);
                         Material mat = material.clone();
                         for (TerrainGridListener l : listeners.values()) {
                             mat = l.tileLoaded(mat, temp);
                         }
                         q.setMaterial(mat);
-                        cache.put(temp, q);
+                        log.log(Level.FINE, "Loaded TerrainQuad {0}", q.getName());
+                    }
+                    cache.put(temp, q);
+                    
+                    if (isCenter(quadIdx)) {
+                        // if it should be attached as a child right now, attach it
+                        final int quadrant = getQuadrant(quadIdx);
+                        final TerrainQuad newQuad = q;
+                        // back on the OpenGL thread:
+                        getControl(UpdateControl.class).enqueue(new Callable() {
+                            public Object call() throws Exception {
+                                attachQuadAt(newQuad, quadrant, temp);
+                                return null;
+                            }
+                        });
                     }
                 }
             }
 
         }
     }
+    
+    private boolean isCenter(int quadIndex) {
+        return quadIndex == 9 || quadIndex == 5 || quadIndex == 10 || quadIndex == 6;
+    }
+    
+    private int getQuadrant(int quadIndex) {
+        if (quadIndex == 9)
+            return 1;
+        else if (quadIndex == 5)
+            return 2;
+        else if (quadIndex == 10)
+            return 3;
+        else if (quadIndex == 6)
+            return 4;
+        return 0; // error
+    }
 
-    public TerrainGrid(String name, int patchSize, int size, Vector3f stepScale, HeightMapGrid heightMapGrid, int totalSize,
+    public TerrainGrid(String name, int patchSize, int maxVisibleSize, Vector3f scale, HeightMapGrid heightMapGrid,
             Vector2f offset, float offsetAmount, LodCalculatorFactory lodCalculatorFactory) {
         this.name = name;
         this.patchSize = patchSize;
-        this.size = size;
-        this.quarterSize = size >> 2;
-        this.quadSize = (size + 1) >> 1;
-        this.stepScale = stepScale;
+        this.size = maxVisibleSize;
+        this.quarterSize = maxVisibleSize >> 2;
+        this.quadSize = (maxVisibleSize + 1) >> 1;
+        this.stepScale = scale;
         this.heightMapGrid = heightMapGrid;
         heightMapGrid.setSize(this.quadSize);
-        this.totalSize = totalSize;
+        this.totalSize = maxVisibleSize;
         this.offset = offset;
         this.offsetAmount = offsetAmount;
         this.lodCalculatorFactory = lodCalculatorFactory;
         if (lodCalculatorFactory == null) {
             lodCalculatorFactory = new LodDistanceCalculatorFactory();
         }
-        this.quadOrigins = new Vector3f[]{new Vector3f(-this.quarterSize, 0, -this.quarterSize).mult(this.stepScale),
-            new Vector3f(-this.quarterSize, 0, this.quarterSize).mult(this.stepScale),
-            new Vector3f(this.quarterSize, 0, -this.quarterSize).mult(this.stepScale),
-            new Vector3f(this.quarterSize, 0, this.quarterSize).mult(this.stepScale)};
+//        this.quadOrigins = new Vector3f[]{
+//            new Vector3f(-this.quarterSize, 0, -this.quarterSize).mult(this.stepScale),
+//            new Vector3f(-this.quarterSize, 0, this.quarterSize).mult(this.stepScale),
+//            new Vector3f(this.quarterSize, 0, -this.quarterSize).mult(this.stepScale),
+//            new Vector3f(this.quarterSize, 0, this.quarterSize).mult(this.stepScale)};
         this.quadIndex = new Vector3f[]{
-            new Vector3f(-1, 0, -1), new Vector3f(-1, 0, 0), new Vector3f(-1, 0, 1), new Vector3f(-1, 0, 2),
-            new Vector3f(0, 0, -1), new Vector3f(0, 0, 0), new Vector3f(0, 0, 1), new Vector3f(0, 0, 2),
-            new Vector3f(1, 0, -1), new Vector3f(1, 0, 0), new Vector3f(1, 0, 1), new Vector3f(1, 0, 2),
-            new Vector3f(2, 0, -1), new Vector3f(2, 0, 0), new Vector3f(2, 0, 1), new Vector3f(2, 0, 2)};
+            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, 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)};
+        
+        addControl(new UpdateControl());
     }
 
-    public TerrainGrid(String name, int patchSize, int size, Vector3f scale, HeightMapGrid heightMapGrid,
+    public TerrainGrid(String name, int patchSize, int maxVisibleSize, Vector3f scale, HeightMapGrid heightMapGrid,
             LodCalculatorFactory lodCalculatorFactory) {
-        this(name, patchSize, size, scale, heightMapGrid, size, new Vector2f(), 0, lodCalculatorFactory);
+        this(name, patchSize, maxVisibleSize, scale, heightMapGrid, new Vector2f(), 0, lodCalculatorFactory);
     }
 
-    public TerrainGrid(String name, int patchSize, int totalSize, HeightMapGrid heightMapGrid, LodCalculatorFactory lodCalculatorFactory) {
-        this(name, patchSize, totalSize, Vector3f.UNIT_XYZ, heightMapGrid, lodCalculatorFactory);
+    public TerrainGrid(String name, int patchSize, int maxVisibleSize, HeightMapGrid heightMapGrid, LodCalculatorFactory lodCalculatorFactory) {
+        this(name, patchSize, maxVisibleSize, Vector3f.UNIT_XYZ, heightMapGrid, lodCalculatorFactory);
     }
 
-    public TerrainGrid(String name, int patchSize, int totalSize, HeightMapGrid heightMapGrid) {
-        this(name, patchSize, totalSize, heightMapGrid, null);
+    public TerrainGrid(String name, int patchSize, int maxVisibleSize, HeightMapGrid heightMapGrid) {
+        this(name, patchSize, maxVisibleSize, heightMapGrid, null);
     }
 
     public TerrainGrid() {
@@ -164,13 +224,18 @@ public class TerrainGrid extends TerrainQuad {
         }
     }
 
+    /**
+     * Runs on the rendering thread
+     */
     protected void attachQuadAt(TerrainQuad q, int quadrant, Vector3f cam) {
+        this.removeQuad(quadrant);
         //q.setMaterial(this.material);
         //q.setLocalTranslation(quadOrigins[quadrant - 1]);
         q.setQuadrant((short) quadrant);
         this.attachChild(q);
 
-        q.setLocalTranslation(cam.mult(this.quadSize).add(quadOrigins[quadrant-1]));
+        Vector3f loc = cam.mult(this.quadSize-1).subtract(quarterSize, 0, quarterSize);// quadrant location handled TerrainQuad automatically now
+        q.setLocalTranslation(loc );
 
         if (quadControls != null) {
             quadControls[quadrant - 1].setEnabled(false);
@@ -181,6 +246,8 @@ public class TerrainGrid extends TerrainQuad {
             //quadControls[quadrant - 1].setPhysicsLocation(cam.add(this.quadOrigins[quadrant - 1]));
         } else {
         }
+        
+        updateModelBound();
     }
 
     private void updateChildrens(Vector3f cam) {
@@ -203,11 +270,14 @@ public class TerrainGrid extends TerrainQuad {
             }
         }
 
-        TerrainQuad q1 = cache.get(cam.add(quadIndex[5]));
-        TerrainQuad q2 = cache.get(cam.add(quadIndex[6]));
-        TerrainQuad q3 = cache.get(cam.add(quadIndex[9]));
-        TerrainQuad q4 = cache.get(cam.add(quadIndex[10]));
+        //TerrainQuad q1 = cache.get(cam.add(quadIndex[9]));
+        //TerrainQuad q2 = cache.get(cam.add(quadIndex[5]));
+        //TerrainQuad q3 = cache.get(cam.add(quadIndex[10]));
+        //TerrainQuad q4 = cache.get(cam.add(quadIndex[6]));
 
+        // ---------------------------------------------------
+        // what does this block do?
+        // ---------------------------------------------------
         int dx = 0;
         int dy = 0;
         if (currentCell != null) {
@@ -236,16 +306,21 @@ public class TerrainGrid extends TerrainQuad {
                 cache.get(cam.add(quadIndex[i * 4 + j]));
             }
         }
-
-        if (q1 == null || q2 == null || q3 == null || q4 == null) {
+        // ---------------------------------------------------
+        // ---------------------------------------------------
+        
+        if (executor == null)
+            executor = createExecutorService();
+
+        executor.submit(new UpdateQuadCache(cam));
+        
+/*        if (q1 == null || q2 == null || q3 == null || q4 == null) {
             try {
-                if (executor == null)
-                    executor = createExecutorService();
-                executor.submit(new UpdateQuadCache(cam, true)).get();
-                q1 = cache.get(cam.add(quadIndex[5]));
-                q2 = cache.get(cam.add(quadIndex[6]));
-                q3 = cache.get(cam.add(quadIndex[9]));
-                q4 = cache.get(cam.add(quadIndex[10]));
+                executor.submit(new UpdateQuadCache(cam, true)).get(); // BLOCKING
+                q1 = cache.get(cam.add(quadIndex[9]));
+                q2 = cache.get(cam.add(quadIndex[5]));
+                q3 = cache.get(cam.add(quadIndex[10]));
+                q4 = cache.get(cam.add(quadIndex[6]));
             } catch (InterruptedException ex) {
                 Logger.getLogger(TerrainGrid.class.getName()).log(Level.SEVERE, null, ex);
                 return;
@@ -263,15 +338,15 @@ public class TerrainGrid extends TerrainQuad {
         this.removeQuad(3);
         this.removeQuad(4);
 
-        attachQuadAt(q1, 1, cam);
-        attachQuadAt(q2, 2, cam);
-        attachQuadAt(q3, 3, cam);
-        attachQuadAt(q4, 4, cam);
-
+        attachQuadAt(q1, 1, cam); // quadIndex[9]
+        attachQuadAt(q2, 2, cam); // quadIndex[5]
+        attachQuadAt(q3, 3, cam); // quadIndex[10]
+        attachQuadAt(q4, 4, cam); // quadIndex[6]
+*/
         this.currentCell = cam;
-        this.updateModelBound();
+//        this.updateModelBound();
     }
-
+    
     public void addListener(String id, TerrainGridListener listener) {
         this.listeners.put(id, listener);
     }
@@ -293,4 +368,15 @@ public class TerrainGrid extends TerrainQuad {
     public void setQuadSize(int quadSize) {
         this.quadSize = quadSize;
     }
+    
+    @Override
+    public void adjustHeight(List<Vector2f> xz, List<Float> height) {
+        Vector3f currentGridLocation = getCurrentCell().mult( getLocalScale() ).multLocal( quadSize-1 );
+        for ( Vector2f vect : xz )
+        {
+            vect.x -= currentGridLocation.x;
+            vect.y -= currentGridLocation.z;
+        }
+        super.adjustHeight( xz, height );
+    }
 }

+ 29 - 2
engine/src/terrain/com/jme3/terrain/geomipmap/TerrainGridListener.java

@@ -1,6 +1,33 @@
 /*
- * To change this template, choose Tools | Templates
- * and open the template in the editor.
+ * Copyright (c) 2009-2010 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *   may be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 package com.jme3.terrain.geomipmap;
 

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

@@ -32,6 +32,8 @@
 
 package com.jme3.terrain.geomipmap;
 
+import com.jme3.scene.control.UpdateControl;
+import com.jme3.app.AppTask;
 import com.jme3.material.Material;
 import java.io.IOException;
 import java.util.HashMap;
@@ -67,6 +69,9 @@ import com.jme3.util.TangentBinormalGenerator;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.Future;
 
 /**
  * A terrain quad is a node in the quad tree of the terrain system.
@@ -94,8 +99,7 @@ public class TerrainQuad extends Node implements Terrain {
     protected int quadrant = 1; // 1=upper left, 2=lower left, 3=upper right, 4=lower right
 
     protected LodCalculatorFactory lodCalculatorFactory;
-
-
+    
     protected List<Vector3f> lastCameraLocations; // used for LOD calc
     private boolean lodCalcRunning = false;
     private int maxLod = -1;
@@ -129,14 +133,19 @@ public class TerrainQuad extends Node implements Terrain {
     public TerrainQuad(String name, int patchSize, int totalSize, float[] heightMap, LodCalculatorFactory lodCalculatorFactory) {
         this(name, patchSize, totalSize, Vector3f.UNIT_XYZ, heightMap, lodCalculatorFactory);
     }
-
-    public TerrainQuad(String name, int patchSize, int size, Vector3f scale, float[] heightMap, LodCalculatorFactory lodCalculatorFactory) {
-        this(name, patchSize, size, scale, heightMap, size, new Vector2f(), 0, lodCalculatorFactory);
+    
+    public TerrainQuad(String name, int patchSize, int size, int totalSize, float[] heightMap, LodCalculatorFactory lodCalculatorFactory) {
+        this(name, patchSize, size, Vector3f.UNIT_XYZ, heightMap, totalSize, new Vector2f(), 0, lodCalculatorFactory);
         affectedAreaBBox = new BoundingBox(new Vector3f(0,0,0), size, Float.MAX_VALUE, size);
         fixNormalEdges(affectedAreaBBox);
         addControl(new NormalRecalcControl(this));
     }
 
+    public TerrainQuad(String name, int patchSize, int size, Vector3f scale, float[] heightMap, LodCalculatorFactory lodCalculatorFactory) {
+        this(name, patchSize, size, scale, heightMap, size, new Vector2f(), 0, lodCalculatorFactory);
+        
+    }
+
     protected TerrainQuad(String name, int patchSize, int size,
                             Vector3f scale, float[] heightMap, int totalSize,
                             Vector2f offset, float offsetAmount,
@@ -1580,7 +1589,7 @@ public class TerrainQuad extends Node implements Terrain {
         int area = size*size;
         hm = new float[area];
 
-        if (getChildren() != null) {
+        if (getChildren() != null && !getChildren().isEmpty()) {
             float[] ul=null, ur=null, bl=null, br=null;
             // get the child heightmaps
             if (getChild(0) instanceof TerrainPatch) {

+ 31 - 0
engine/src/terrain/com/jme3/terrain/heightmap/FractalHeightMapGrid.java

@@ -1,3 +1,34 @@
+/*
+ * Copyright (c) 2009-2010 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *   may be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
 package com.jme3.terrain.heightmap;
 
 import java.awt.image.BufferedImage;

+ 29 - 2
engine/src/terrain/com/jme3/terrain/heightmap/Grayscale16BitHeightMap.java

@@ -1,6 +1,33 @@
 /*
- * To change this template, choose Tools | Templates
- * and open the template in the editor.
+ * Copyright (c) 2009-2010 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *   may be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 package com.jme3.terrain.heightmap;
 

+ 0 - 3
engine/src/test/jme3test/terrain/TerrainFractalGridTest.java

@@ -19,10 +19,7 @@ import com.jme3.math.Vector3f;
 import com.jme3.renderer.Camera;
 import com.jme3.terrain.geomipmap.TerrainGrid;
 import com.jme3.terrain.geomipmap.TerrainLodControl;
-import com.jme3.terrain.geomipmap.TerrainQuad;
 import com.jme3.terrain.heightmap.FractalHeightMapGrid;
-import com.jme3.terrain.heightmap.ImageBasedHeightMapGrid;
-import com.jme3.terrain.heightmap.Namer;
 import com.jme3.texture.Texture;
 import com.jme3.texture.Texture.WrapMode;
 import org.novyon.noise.ShaderUtils;

+ 150 - 43
engine/src/test/jme3test/terrain/TerrainTestModifyHeight.java

@@ -47,12 +47,22 @@ import com.jme3.math.ColorRGBA;
 import com.jme3.math.Ray;
 import com.jme3.math.Vector2f;
 import com.jme3.math.Vector3f;
+import com.jme3.terrain.geomipmap.TerrainGrid;
 import com.jme3.terrain.geomipmap.TerrainLodControl;
 import com.jme3.terrain.geomipmap.TerrainQuad;
+import com.jme3.terrain.heightmap.FractalHeightMapGrid;
 import com.jme3.texture.Texture;
 import com.jme3.texture.Texture.WrapMode;
 import java.util.ArrayList;
 import java.util.List;
+import org.novyon.noise.ShaderUtils;
+import org.novyon.noise.basis.FilteredBasis;
+import org.novyon.noise.filter.IterativeFilter;
+import org.novyon.noise.filter.OptimizedErode;
+import org.novyon.noise.filter.PerturbFilter;
+import org.novyon.noise.filter.SmoothFilter;
+import org.novyon.noise.fractal.FractalSum;
+import org.novyon.noise.modulator.NoiseModulator;
 
 /**
  *
@@ -82,15 +92,15 @@ public class TerrainTestModifyHeight extends SimpleApplication {
 
     @Override
     public void simpleUpdate(float tpf){
-        updateHintText();
+        Vector3f intersection = getWorldIntersection();
+        updateHintText(intersection);
         
         if (raiseTerrain){
-            Vector3f intersection = getWorldIntersection();
+            
             if (intersection != null) {
                 adjustHeight(intersection, 64, tpf * 60);
             }
         }else if (lowerTerrain){
-            Vector3f intersection = getWorldIntersection();
             if (intersection != null) {
                 adjustHeight(intersection, 64, -tpf * 60);
             }
@@ -103,47 +113,13 @@ public class TerrainTestModifyHeight extends SimpleApplication {
         initCrossHairs();
         setupKeys();
 
-        // First, we load up our textures and the heightmap texture for the terrain
-
-        // TERRAIN TEXTURE material
-        matTerrain = new Material(assetManager, "Common/MatDefs/Terrain/TerrainLighting.j3md");
-        matTerrain.setBoolean("useTriPlanarMapping", false);
-        matTerrain.setBoolean("WardIso", true);
-
-        // ALPHA map (for splat textures)
-        matTerrain.setTexture("AlphaMap", assetManager.loadTexture("Textures/Terrain/splat/alphamap.png"));
-
-        // GRASS texture
-        Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg");
-        grass.setWrap(WrapMode.Repeat);
-        matTerrain.setTexture("DiffuseMap", grass);
-        matTerrain.setFloat("DiffuseMap_0_scale", grassScale);
-
-        // DIRT texture
-        Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg");
-        dirt.setWrap(WrapMode.Repeat);
-        matTerrain.setTexture("DiffuseMap_1", dirt);
-        matTerrain.setFloat("DiffuseMap_1_scale", dirtScale);
-
-        // ROCK texture
-        Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg");
-        rock.setWrap(WrapMode.Repeat);
-        matTerrain.setTexture("DiffuseMap_2", rock);
-        matTerrain.setFloat("DiffuseMap_2_scale", rockScale);
-
         // WIREFRAME material
         matWire = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
         matWire.getAdditionalRenderState().setWireframe(true);
         matWire.setColor("Color", ColorRGBA.Green);
-
-        // CREATE THE TERRAIN
-        terrain = new TerrainQuad("terrain", 65, 513, null);
-        TerrainLodControl control = new TerrainLodControl(terrain, getCamera());
-        terrain.addControl(control);
-        terrain.setMaterial(matTerrain);
-        terrain.setLocalTranslation(0, -100, 0);
-        terrain.setLocalScale(2f, 1f, 2f);
-        rootNode.attachChild(terrain);
+        
+        //createTerrain();
+        createTerrainGrid();
 
         DirectionalLight light = new DirectionalLight();
         light.setDirection((new Vector3f(-0.5f, -1f, -0.5f)).normalize());
@@ -153,7 +129,7 @@ public class TerrainTestModifyHeight extends SimpleApplication {
         ambLight.setColor(new ColorRGBA(1f, 1f, 0.8f, 0.2f));
         rootNode.addLight(ambLight);
 
-        cam.setLocation(new Vector3f(0, 10, -10));
+        cam.setLocation(new Vector3f(0, 256, 0));
         cam.lookAtDirection(new Vector3f(0, -1.5f, -1).normalizeLocal(), Vector3f.UNIT_Y);
     }
 
@@ -164,11 +140,14 @@ public class TerrainTestModifyHeight extends SimpleApplication {
         guiNode.attachChild(hintText);
     }
 
-    public void updateHintText() {
+    public void updateHintText(Vector3f target) {
         int x = (int) getCamera().getLocation().x;
         int y = (int) getCamera().getLocation().y;
         int z = (int) getCamera().getLocation().z;
-        hintText.setText("Press left mouse button to raise terrain, press right mouse button to lower terrain.  " + x + "," + y + "," + z);
+        String targetText = "";
+        if (target!= null)
+            targetText = "  intersect: "+target.toString();
+        hintText.setText("Press left mouse button to raise terrain, press right mouse button to lower terrain.  " + x + "," + y + "," + z+targetText);
     }
 
     protected void initCrossHairs() {
@@ -272,4 +251,132 @@ public class TerrainTestModifyHeight extends SimpleApplication {
         }
         return null;
     }
+    
+    private void createTerrain() {
+        // First, we load up our textures and the heightmap texture for the terrain
+
+        // TERRAIN TEXTURE material
+        matTerrain = new Material(assetManager, "Common/MatDefs/Terrain/TerrainLighting.j3md");
+        matTerrain.setBoolean("useTriPlanarMapping", false);
+        matTerrain.setBoolean("WardIso", true);
+
+        // ALPHA map (for splat textures)
+        matTerrain.setTexture("AlphaMap", assetManager.loadTexture("Textures/Terrain/splat/alphamap.png"));
+
+        // GRASS texture
+        Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg");
+        grass.setWrap(WrapMode.Repeat);
+        matTerrain.setTexture("DiffuseMap", grass);
+        matTerrain.setFloat("DiffuseMap_0_scale", grassScale);
+
+        // DIRT texture
+        Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg");
+        dirt.setWrap(WrapMode.Repeat);
+        matTerrain.setTexture("DiffuseMap_1", dirt);
+        matTerrain.setFloat("DiffuseMap_1_scale", dirtScale);
+
+        // ROCK texture
+        Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg");
+        rock.setWrap(WrapMode.Repeat);
+        matTerrain.setTexture("DiffuseMap_2", rock);
+        matTerrain.setFloat("DiffuseMap_2_scale", rockScale);
+
+        // CREATE THE TERRAIN
+        terrain = new TerrainQuad("terrain", 65, 513, null);
+        TerrainLodControl control = new TerrainLodControl(terrain, getCamera());
+        terrain.addControl(control);
+        terrain.setMaterial(matTerrain);
+        terrain.setLocalTranslation(0, -100, 0);
+        terrain.setLocalScale(2f, 1f, 2f);
+        rootNode.attachChild(terrain);
+    }
+
+    private void createTerrainGrid() {
+        
+        // TERRAIN TEXTURE material
+        matTerrain = new Material(this.assetManager, "Common/MatDefs/Terrain/HeightBasedTerrain.j3md");
+
+        // Parameters to material:
+        // regionXColorMap: X = 1..4 the texture that should be appliad to state X
+        // regionX: a Vector3f containing the following information:
+        //      regionX.x: the start height of the region
+        //      regionX.y: the end height of the region
+        //      regionX.z: the texture scale for the region
+        //  it might not be the most elegant way for storing these 3 values, but it packs the data nicely :)
+        // slopeColorMap: the texture to be used for cliffs, and steep mountain sites
+        // slopeTileFactor: the texture scale for slopes
+        // terrainSize: the total size of the terrain (used for scaling the texture)
+        // GRASS texture
+        Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg");
+        grass.setWrap(WrapMode.Repeat);
+        matTerrain.setTexture("region1ColorMap", grass);
+        matTerrain.setVector3("region1", new Vector3f(88, 200, this.grassScale));
+
+        // DIRT texture
+        Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg");
+        dirt.setWrap(WrapMode.Repeat);
+        matTerrain.setTexture("region2ColorMap", dirt);
+        matTerrain.setVector3("region2", new Vector3f(0, 90, this.dirtScale));
+
+        // ROCK texture
+        Texture rock = assetManager.loadTexture("Textures/Terrain/Rock2/rock.jpg");
+        rock.setWrap(WrapMode.Repeat);
+        matTerrain.setTexture("region3ColorMap", rock);
+        matTerrain.setVector3("region3", new Vector3f(198, 260, this.rockScale));
+
+        matTerrain.setTexture("region4ColorMap", rock);
+        matTerrain.setVector3("region4", new Vector3f(198, 260, this.rockScale));
+
+        matTerrain.setTexture("slopeColorMap", rock);
+        matTerrain.setFloat("slopeTileFactor", 32);
+
+        matTerrain.setFloat("terrainSize", 513);
+
+        FractalSum base = new FractalSum();
+        base.setRoughness(0.7f);
+        base.setFrequency(1.0f);
+        base.setAmplitude(1.0f);
+        base.setLacunarity(2.12f);
+        base.setOctaves(8);
+        base.setScale(0.02125f);
+        base.addModulator(new NoiseModulator() {
+            @Override
+            public float value(float... in) {
+                return ShaderUtils.clamp(in[0] * 0.5f + 0.5f, 0, 1);
+            }
+        });
+
+        FilteredBasis ground = new FilteredBasis(base);
+
+        PerturbFilter perturb = new PerturbFilter();
+        perturb.setMagnitude(0.119f);
+
+        OptimizedErode therm = new OptimizedErode();
+        therm.setRadius(5);
+        therm.setTalus(0.011f);
+
+        SmoothFilter smooth = new SmoothFilter();
+        smooth.setRadius(1);
+        smooth.setEffect(0.7f);
+
+        IterativeFilter iterate = new IterativeFilter();
+        iterate.addPreFilter(perturb);
+        iterate.addPostFilter(smooth);
+        iterate.setFilter(therm);
+        iterate.setIterations(1);
+
+        ground.addPreFilter(iterate);
+
+        this.terrain = new TerrainGrid("terrain", 65, 257, new FractalHeightMapGrid(ground, null, 256f));
+
+
+        terrain.setMaterial(matWire);
+        terrain.setLocalTranslation(0, 0, 0);
+        terrain.setLocalScale(2f, 1f, 2f);
+        ((TerrainGrid)terrain).initialize(Vector3f.ZERO);
+        rootNode.attachChild(this.terrain);
+
+        TerrainLodControl control = new TerrainLodControl(this.terrain, getCamera());
+        this.terrain.addControl(control);
+    }
 }