Quellcode durchsuchen

* Cleaned up and simplified the Terrain API.
* Removed dependence on TerrainQuad for TerrainLodControl
* Comments, general cleanup

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

bre..ns vor 14 Jahren
Ursprung
Commit
70f1a6f323

+ 12 - 33
engine/src/terrain/com/jme3/terrain/Terrain.java

@@ -34,7 +34,6 @@ package com.jme3.terrain;
 import com.jme3.material.Material;
 import com.jme3.math.Vector2f;
 import com.jme3.math.Vector3f;
-import com.jme3.scene.Spatial;
 import java.util.List;
 
 /**
@@ -107,20 +106,7 @@ public interface Terrain {
      * Infinite or "paged" terrains will not be able to support this, so use with caution.
      */
     public float[] getHeightMap();
-
-    /**
-     * Tell the terrain system to use/not use Level of Detail algorithms.
-     * This is allowed to be ignored if a particular implementation cannot support it.
-     */
-    public void useLOD(boolean useLod);
-
-    /**
-     * Check if the terrain is using LOD techniques.
-     * If a terrain system only supports enabled LOD, then this
-     * should always return true.
-     */
-    public boolean isUsingLOD();
-
+    
     /**
      * This is calculated by the specific LOD algorithm.
      * A value of one means that the terrain is showing full detail.
@@ -130,24 +116,19 @@ public interface Terrain {
     public int getMaxLod();
 
     /**
-     * Called in the update (pre or post, up to you) method of your game.
+     * Called by an LodControl.
      * Calculates the level of detail of the terrain and adjusts its geometry.
      * This is where the Terrain's LOD algorithm will change the detail of
      * the terrain based on how far away this position is from the particular
      * terrain patch.
-     * @param location often the Camera's location
+     * @param location: the Camera's location. A list of one camera location is normal 
+     *  if you just have one camera in your scene.
      */
     public void update(List<Vector3f> location);
 
-    /**
-     * Get the spatial instance of this Terrain. Right now just used in the 
-     * terrain editor in JMP.
-     */
-    public Spatial getSpatial();
-
     /**
      * Lock or unlock the meshes of this terrain.
-     * Locked meshes are uneditable but have better performance.
+     * Locked meshes are un-editable but have better performance.
      * This should call the underlying getMesh().setStatic()/setDynamic() methods.
      * @param locked or unlocked
      */
@@ -169,17 +150,15 @@ public interface Terrain {
     public Material getMaterial();
 
     /**
-     * Calculates the percentage along the terrain (in X-Z plane) that the
-     * supplied point (worldX,worldY) is, starting from the x=0, z=0 world
-     * position of the terrain.
-     * This method must take into account local translations and scale of the terrain.
-     * Used for painting onto an alpha image for texture splatting.
+     * Used for painting to get the number of vertices along the edge of the
+     * terrain.
+     * This is an un-scaled size, and should represent the vertex count (ie. the
+     * texture coord count) along an edge of a square terrain.
      * 
-     * @param worldX world position on X axis
-     * @param worldY world position on Z axis
-     * @return a point (U,V in the range [0,1] )
+     * In the standard TerrainQuad default implementation, this will return
+     * the "totalSize" of the terrain (512 or so).
      */
-    public Vector2f getPointPercentagePosition(float worldX, float worldY);
+    public int getTerrainSize();
 
     /**
      * Get the scale of the texture coordinates. Normally if the texture is

+ 22 - 10
engine/src/terrain/com/jme3/terrain/geomipmap/TerrainLodControl.java

@@ -41,6 +41,7 @@ import java.util.List;
 import com.jme3.renderer.Camera;
 import com.jme3.renderer.RenderManager;
 import com.jme3.renderer.ViewPort;
+import com.jme3.scene.Node;
 import com.jme3.scene.Spatial;
 import com.jme3.scene.control.AbstractControl;
 import com.jme3.scene.control.Control;
@@ -61,22 +62,27 @@ import java.util.ArrayList;
  */
 public class TerrainLodControl extends AbstractControl {
 
-    private TerrainQuad terrain;
+    private Terrain terrain;
     private List<Camera> cameras;
     private List<Vector3f> cameraLocations = new ArrayList<Vector3f>();
 
     public TerrainLodControl() {
     }
 
+    public TerrainLodControl(Terrain terrain, Camera camera) {
+        List<Camera> cams = new ArrayList<Camera>();
+        cams.add(camera);
+        this.terrain = terrain;
+        this.cameras = cams;
+    }
+    
     /**
      * Only uses the first camera right now.
      * @param terrain to act upon (must be a Spatial)
      * @param cameras one or more cameras to reference for LOD calc
      */
     public TerrainLodControl(Terrain terrain, List<Camera> cameras) {
-        if (terrain instanceof TerrainQuad) {
-            this.terrain = (TerrainQuad) terrain;
-        }
+        this.terrain = terrain;
         this.cameras = cameras;
     }
 
@@ -107,11 +113,17 @@ public class TerrainLodControl extends AbstractControl {
                     cameraClone.add(c);
                 }
             }
-            return new TerrainLodControl((TerrainQuad) spatial, cameraClone);
+            return new TerrainLodControl((Terrain) spatial, cameraClone);
         }
         return null;
     }
 
+    public void setCamera(Camera camera) {
+        List<Camera> cams = new ArrayList<Camera>();
+        cams.add(camera);
+        setCameras(cams);
+    }
+    
     public void setCameras(List<Camera> cameras) {
         this.cameras = cameras;
         cameraLocations.clear();
@@ -123,12 +135,12 @@ public class TerrainLodControl extends AbstractControl {
     @Override
     public void setSpatial(Spatial spatial) {
         super.setSpatial(spatial);
-        if (spatial instanceof TerrainQuad) {
-            this.terrain = (TerrainQuad) spatial;
+        if (spatial instanceof Terrain) {
+            this.terrain = (Terrain) spatial;
         }
     }
 
-    public void setTerrain(TerrainQuad terrain) {
+    public void setTerrain(Terrain terrain) {
         this.terrain = terrain;
     }
 
@@ -136,13 +148,13 @@ public class TerrainLodControl extends AbstractControl {
     public void write(JmeExporter ex) throws IOException {
         super.write(ex);
         OutputCapsule oc = ex.getCapsule(this);
-        oc.write(terrain, "terrain", null);
+        oc.write((Node)terrain, "terrain", null);
     }
 
     @Override
     public void read(JmeImporter im) throws IOException {
         super.read(im);
         InputCapsule ic = im.getCapsule(this);
-        terrain = (TerrainQuad) ic.readSavable("terrain", null);
+        terrain = (Terrain) ic.readSavable("terrain", null);
     }
 }

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

@@ -67,7 +67,6 @@ import com.jme3.util.TangentBinormalGenerator;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
-import java.util.logging.Logger;
 
 /**
  * A terrain quad is a node in the quad tree of the terrain system.
@@ -99,7 +98,6 @@ public class TerrainQuad extends Node implements Terrain {
 
     protected List<Vector3f> lastCameraLocations; // used for LOD calc
     private boolean lodCalcRunning = false;
-    private boolean usingLOD = true;
     private int maxLod = -1;
     private HashMap<String,UpdatedTerrainPatch> updatedPatches;
     private final Object updatePatchesLock = new Object();
@@ -274,10 +272,6 @@ public class TerrainQuad extends Node implements Terrain {
             return 0;
     }
 
-    public Spatial getSpatial() {
-        return this;
-    }
-
     public void generateEntropy(ProgressMonitor progressMonitor) {
         // only check this on the root quad
         if (isRootQuad())
@@ -312,11 +306,11 @@ public class TerrainQuad extends Node implements Terrain {
     public Material getMaterial() {
         // get the material from one of the children. They all share the same material
         if (children != null) {
-			for (int i = children.size(); --i >= 0;) {
-				Spatial child = children.get(i);
-				if (child instanceof TerrainQuad) {
-					return ((TerrainQuad)child).getMaterial();
-				} else if (child instanceof TerrainPatch) {
+            for (int i = children.size(); --i >= 0;) {
+                Spatial child = children.get(i);
+                if (child instanceof TerrainQuad) {
+                    return ((TerrainQuad)child).getMaterial();
+                } else if (child instanceof TerrainPatch) {
                     return ((TerrainPatch)child).getMaterial();
                 }
             }
@@ -383,12 +377,11 @@ public class TerrainQuad extends Node implements Terrain {
      */
     private void updateQuadLODs() {
         synchronized (updatePatchesLock) {
-            //if (true)
-            //	return;
+            
             if (updatedPatches == null || updatedPatches.isEmpty())
                 return;
 
-            //TODO do the actual geometry update here
+            // do the actual geometry update here
             for (UpdatedTerrainPatch utp : updatedPatches.values()) {
                 utp.updateAll();
             }
@@ -582,7 +575,7 @@ public class TerrainQuad extends Node implements Terrain {
         offsetAmount += quarterSize;
 
         if (lodCalculatorFactory == null)
-                lodCalculatorFactory = new LodDistanceCalculatorFactory(); // set a default one
+            lodCalculatorFactory = new LodDistanceCalculatorFactory(); // set a default one
 
         // 1 upper left
         float[] heightBlock1 = createHeightSubBlock(heightMap, 0, 0, split);
@@ -690,7 +683,7 @@ public class TerrainQuad extends Node implements Terrain {
         int split = (size + 1) >> 1;
 
         if (lodCalculatorFactory == null)
-                lodCalculatorFactory = new LodDistanceCalculatorFactory(); // set a default one
+            lodCalculatorFactory = new LodDistanceCalculatorFactory(); // set a default one
 
         offsetAmount += quarterSize;
 
@@ -1104,13 +1097,9 @@ public class TerrainQuad extends Node implements Terrain {
         return (x >= 0 && x <= totalSize && z >= 0 && z <= totalSize);
     }
 
-    public Vector2f getPointPercentagePosition(float worldX, float worldY) {
-        Vector2f uv = new Vector2f(worldX,worldY);
-        uv.subtractLocal(getLocalTranslation().x, getLocalTranslation().z); // center it on 0,0
-        uv.addLocal(totalSize/2, totalSize/2); // shift the bottom left corner up to 0,0
-        uv.divideLocal(totalSize); // get the location as a percentage
-
-        return uv;
+    
+    public int getTerrainSize() {
+        return totalSize;
     }
 
 
@@ -1510,10 +1499,6 @@ public class TerrainQuad extends Node implements Terrain {
         quadrant = c.readInt("quadrant", 0);
         totalSize = c.readInt("totalSize", 0);
         lodCalculatorFactory = (LodCalculatorFactory) c.readSavable("lodCalculatorFactory", null);
-
-        // the terrain is re-built on load, so we need to run this once
-        //affectedAreaBBox = new BoundingBox(new Vector3f(0,0,0), size, Float.MAX_VALUE, size);
-        //updateNormals();
     }
 
     @Override
@@ -1564,14 +1549,6 @@ public class TerrainQuad extends Node implements Terrain {
         return maxLod;
     }
 
-    public void useLOD(boolean useLod) {
-        usingLOD = useLod;
-    }
-
-    public boolean isUsingLOD() {
-        return usingLOD;
-}
-
     public int getPatchSize() {
         return patchSize;
     }
@@ -1583,9 +1560,6 @@ public class TerrainQuad extends Node implements Terrain {
 
     public float[] getHeightMap() {
 
-        //if (true)
-        //    return heightMap;
-
         float[] hm = null;
         int length = ((size-1)/2)+1;
         int area = size*size;

+ 28 - 26
engine/src/test/jme3test/terrain/TerrainTestReadWrite.java

@@ -33,6 +33,7 @@ package jme3test.terrain;
 
 import com.jme3.app.SimpleApplication;
 import com.jme3.bounding.BoundingBox;
+import com.jme3.export.Savable;
 import com.jme3.export.binary.BinaryExporter;
 import com.jme3.export.binary.BinaryImporter;
 import com.jme3.font.BitmapText;
@@ -44,6 +45,8 @@ import com.jme3.material.Material;
 import com.jme3.math.ColorRGBA;
 import com.jme3.math.Vector3f;
 import com.jme3.renderer.Camera;
+import com.jme3.scene.Node;
+import com.jme3.terrain.Terrain;
 import com.jme3.terrain.geomipmap.TerrainLodControl;
 import com.jme3.terrain.geomipmap.TerrainQuad;
 import com.jme3.terrain.heightmap.AbstractHeightMap;
@@ -69,7 +72,7 @@ import jme3tools.converters.ImageToAwt;
  */
 public class TerrainTestReadWrite extends SimpleApplication {
 
-    private TerrainQuad terrain;
+    private Terrain terrain;
     protected BitmapText hintText;
     private float grassScale = 64;
     private float dirtScale = 16;
@@ -147,8 +150,6 @@ public class TerrainTestReadWrite extends SimpleApplication {
         // CREATE HEIGHTMAP
         AbstractHeightMap heightmap = null;
         try {
-            //heightmap = new HillHeightMap(1025, 1000, 50, 100, (byte) 3);
-
             heightmap = new ImageBasedHeightMap(ImageToAwt.convert(heightMapImage.getImage(), false, true, 0), 1f);
             heightmap.load();
 
@@ -160,15 +161,17 @@ public class TerrainTestReadWrite extends SimpleApplication {
             loadTerrain();
         } else {
             // create the terrain as normal, and give it a control for LOD management
-            terrain = new TerrainQuad("terrain", 65, 513, heightmap.getHeightMap());//, new LodPerspectiveCalculatorFactory(getCamera(), 4)); // add this in to see it use entropy for LOD calculations
+            TerrainQuad terrainQuad = new TerrainQuad("terrain", 65, 129, heightmap.getHeightMap());//, new LodPerspectiveCalculatorFactory(getCamera(), 4)); // add this in to see it use entropy for LOD calculations
             List<Camera> cameras = new ArrayList<Camera>();
             cameras.add(getCamera());
-            TerrainLodControl control = new TerrainLodControl(terrain, cameras);
-            terrain.addControl(control);
-            terrain.setMaterial(matTerrain);
-            terrain.setLocalTranslation(0, -100, 0);
-            terrain.setLocalScale(2f, 1f, 2f);
-            rootNode.attachChild(terrain);
+            TerrainLodControl control = new TerrainLodControl(terrainQuad, cameras);
+            terrainQuad.addControl(control);
+            terrainQuad.setMaterial(matTerrain);
+            terrainQuad.setLocalTranslation(0, -100, 0);
+            terrainQuad.setLocalScale(4f, 0.25f, 4f);
+            rootNode.attachChild(terrainQuad);
+            
+            this.terrain = terrainQuad;
         }
 
         DirectionalLight light = new DirectionalLight();
@@ -211,7 +214,7 @@ public class TerrainTestReadWrite extends SimpleApplication {
                     fos = new FileOutputStream(new File("terrainsave.jme"));
 
                     // we just use the exporter and pass in the terrain
-                    BinaryExporter.getInstance().save(terrain, new BufferedOutputStream(fos));
+                    BinaryExporter.getInstance().save((Savable)terrain, new BufferedOutputStream(fos));
 
                     fos.flush();
                     float duration = (System.currentTimeMillis() - start) / 1000.0f;
@@ -237,29 +240,28 @@ public class TerrainTestReadWrite extends SimpleApplication {
             long start = System.currentTimeMillis();
             // remove the existing terrain and detach it from the root node.
             if (terrain != null) {
-                terrain.removeFromParent();
-                terrain.removeControl(TerrainLodControl.class);
-                terrain.detachAllChildren();
+                Node existingTerrain = (Node)terrain;
+                existingTerrain.removeFromParent();
+                existingTerrain.removeControl(TerrainLodControl.class);
+                existingTerrain.detachAllChildren();
                 terrain = null;
             }
 
             // import the saved terrain, and attach it back to the root node
-            fis = new FileInputStream(new File("terrainsave.jme"));
+            File f = new File("terrainsave.jme");
+            fis = new FileInputStream(f);
             BinaryImporter imp = BinaryImporter.getInstance();
             imp.setAssetManager(assetManager);
             terrain = (TerrainQuad) imp.load(new BufferedInputStream(fis));
-            rootNode.attachChild(terrain);
+            rootNode.attachChild((Node)terrain);
 
             float duration = (System.currentTimeMillis() - start) / 1000.0f;
             System.out.println("Load took " + duration + " seconds");
 
-            // now we have to add back the cameras to the LOD control, since we didn't want to duplicate them on save
-            List<Camera> cameras = new ArrayList<Camera>();
-            cameras.add(getCamera());
-            TerrainLodControl lodControl = terrain.getControl(TerrainLodControl.class);
-            if (lodControl != null) {
-                lodControl.setCameras(cameras);
-            }
+            // now we have to add back the camera to the LOD control
+            TerrainLodControl lodControl = ((Node)terrain).getControl(TerrainLodControl.class);
+            if (lodControl != null)
+                lodControl.setCamera(getCamera());
 
         } catch (IOException ex) {
             Logger.getLogger(TerrainTestReadWrite.class.getName()).log(Level.SEVERE, null, ex);
@@ -286,10 +288,10 @@ public class TerrainTestReadWrite extends SimpleApplication {
         public void onAction(String name, boolean pressed, float tpf) {
             if (name.equals("clone") && !pressed) {
 
-                TerrainQuad clone = terrain.clone();
-                terrain.removeFromParent();
+                Terrain clone = (Terrain) ((Node)terrain).clone();
+                ((Node)terrain).removeFromParent();
                 terrain = clone;
-                getRootNode().attachChild(terrain);
+                getRootNode().attachChild((Node)terrain);
             }
         }
     };