OSDN Git Service

added terrain.getNormal(x,z)
authorbrentowens <brentowens@75d07b2b-3a1a-0410-a2c5-0572b91ccdca>
Tue, 6 Sep 2011 05:31:24 +0000 (05:31 +0000)
committerbrentowens <brentowens@75d07b2b-3a1a-0410-a2c5-0572b91ccdca>
Tue, 6 Sep 2011 05:31:24 +0000 (05:31 +0000)
git-svn-id: http://jmonkeyengine.googlecode.com/svn/trunk@8200 75d07b2b-3a1a-0410-a2c5-0572b91ccdca

engine/src/terrain/com/jme3/terrain/Terrain.java
engine/src/terrain/com/jme3/terrain/geomipmap/TerrainPatch.java
engine/src/terrain/com/jme3/terrain/geomipmap/TerrainQuad.java
engine/src/test/jme3test/terrain/TerrainTestModifyHeight.java

index 9c6cd76..78a20ab 100644 (file)
@@ -54,6 +54,15 @@ public interface Terrain {
      * @return the height at the given point\r
      */\r
     public float getHeight(Vector2f xz);\r
+    \r
+    /**\r
+     * Get the normal vector for the surface of the terrain at the specified\r
+     * X-Z coordinate. This normal vector can be a close approximation. It does not\r
+     * take into account any normal maps on the material.\r
+     * @param xz the X-Z world coordinate\r
+     * @return the normal vector at the given point\r
+     */\r
+    public Vector3f getNormal(Vector2f xz);\r
 \r
     /**\r
      * Get the heightmap height at the specified X-Z coordinate. This does not\r
index 6024111..fab2efa 100644 (file)
@@ -691,19 +691,19 @@ public class TerrainPatch extends Geometry {
         \r
         Vector3f n1 = Vector3f.ZERO;\r
         if (topPoint != null && leftPoint != null) {\r
-            n1 = getNormal(topPoint.mult(scale), rootPoint.mult(scale), leftPoint.mult(scale));\r
+            n1 = calculateNormal(topPoint.mult(scale), rootPoint.mult(scale), leftPoint.mult(scale));\r
         }\r
         Vector3f n2 = Vector3f.ZERO;\r
         if (leftPoint != null && bottomPoint != null) {\r
-            n2 = getNormal(leftPoint.mult(scale), rootPoint.mult(scale), bottomPoint.mult(scale));\r
+            n2 = calculateNormal(leftPoint.mult(scale), rootPoint.mult(scale), bottomPoint.mult(scale));\r
         }\r
         Vector3f n3 = Vector3f.ZERO;\r
         if (rightPoint != null && bottomPoint != null) {\r
-            n3 = getNormal(bottomPoint.mult(scale), rootPoint.mult(scale), rightPoint.mult(scale));\r
+            n3 = calculateNormal(bottomPoint.mult(scale), rootPoint.mult(scale), rightPoint.mult(scale));\r
         }\r
         Vector3f n4 = Vector3f.ZERO;\r
         if (rightPoint != null && topPoint != null) {\r
-            n4 = getNormal(rightPoint.mult(scale), rootPoint.mult(scale), topPoint.mult(scale));\r
+            n4 = calculateNormal(rightPoint.mult(scale), rootPoint.mult(scale), topPoint.mult(scale));\r
         }\r
         \r
         Vector3f binormal = new Vector3f();\r
@@ -713,12 +713,25 @@ public class TerrainPatch extends Geometry {
         normal.set(n1.add(n2).add(n3).add(n4).normalizeLocal());\r
     }\r
 \r
-    private Vector3f getNormal(Vector3f firstPoint, Vector3f rootPoint, Vector3f secondPoint) {\r
+    private Vector3f calculateNormal(Vector3f firstPoint, Vector3f rootPoint, Vector3f secondPoint) {\r
         Vector3f normal = new Vector3f();\r
         normal.set(firstPoint).subtractLocal(rootPoint)\r
                   .crossLocal(secondPoint.subtract(rootPoint)).normalizeLocal();\r
         return normal;\r
     }\r
+    \r
+    protected Vector3f getMeshNormal(int x, int z) {\r
+        if (x >= size || z >= size)\r
+            return null; // out of range\r
+        \r
+        int index = (z*size+x)*3;\r
+        FloatBuffer nb = (FloatBuffer)this.getMesh().getBuffer(Type.Normal).getData();\r
+        Vector3f normal = new Vector3f();\r
+        normal.x = nb.get(index);\r
+        normal.y = nb.get(index+1);\r
+        normal.z = nb.get(index+2);\r
+        return normal;\r
+    }\r
 \r
     /**\r
      * Locks the mesh (sets it static) to improve performance.\r
index f084e0e..5ca0b39 100644 (file)
@@ -959,12 +959,56 @@ public class TerrainQuad extends Node implements Terrain {
         return Float.NaN;\r
     }\r
 \r
+    protected Vector3f getMeshNormal(int x, int z) {\r
+        int quad = findQuadrant(x, z);\r
+        int split = (size + 1) >> 1;\r
+        if (children != null) {\r
+            for (int i = children.size(); --i >= 0;) {\r
+                Spatial spat = children.get(i);\r
+                int col = x;\r
+                int row = z;\r
+                boolean match = false;\r
+\r
+                // get the childs quadrant\r
+                int childQuadrant = 0;\r
+                if (spat instanceof TerrainQuad) {\r
+                    childQuadrant = ((TerrainQuad) spat).getQuadrant();\r
+                } else if (spat instanceof TerrainPatch) {\r
+                    childQuadrant = ((TerrainPatch) spat).getQuadrant();\r
+                }\r
+\r
+                if (childQuadrant == 1 && (quad & 1) != 0) {\r
+                    match = true;\r
+                } else if (childQuadrant == 2 && (quad & 2) != 0) {\r
+                    row = z - split + 1;\r
+                    match = true;\r
+                } else if (childQuadrant == 3 && (quad & 4) != 0) {\r
+                    col = x - split + 1;\r
+                    match = true;\r
+                } else if (childQuadrant == 4 && (quad & 8) != 0) {\r
+                    col = x - split + 1;\r
+                    row = z - split + 1;\r
+                    match = true;\r
+                }\r
+\r
+                if (match) {\r
+                    if (spat instanceof TerrainQuad) {\r
+                        return ((TerrainQuad) spat).getMeshNormal(col, row);\r
+                    } else if (spat instanceof TerrainPatch) {\r
+                        return ((TerrainPatch) spat).getMeshNormal(col, row);\r
+                    }\r
+                }\r
+\r
+            }\r
+        }\r
+        return null;\r
+    }\r
 \r
     public float getHeight(Vector2f xz) {\r
         // offset\r
         float x = (float)(((xz.x - getLocalTranslation().x) / getLocalScale().x) + (float)totalSize / 2f);\r
         float z = (float)(((xz.y - getLocalTranslation().z) / getLocalScale().z) + (float)totalSize / 2f);\r
-        float height = getHeight(x, z, xz);\r
+        float height = getHeight(x, z);\r
         height *= getLocalScale().y;\r
         return height;\r
     }\r
@@ -974,7 +1018,7 @@ public class TerrainQuad extends Node implements Terrain {
      * @param x coordinate translated into actual (positive) terrain grid coordinates\r
      * @param y coordinate translated into actual (positive) terrain grid coordinates\r
      */\r
-    protected float getHeight(float x, float z, Vector2f xz) {\r
+    protected float getHeight(float x, float z) {\r
         x-=0.5f;\r
         z-=0.5f;\r
         float col = FastMath.floor(x);\r
@@ -1000,6 +1044,38 @@ public class TerrainQuad extends Node implements Terrain {
         }\r
     }\r
 \r
+    public Vector3f getNormal(Vector2f xz) {\r
+        // offset\r
+        float x = (float)(((xz.x - getLocalTranslation().x) / getLocalScale().x) + (float)totalSize / 2f);\r
+        float z = (float)(((xz.y - getLocalTranslation().z) / getLocalScale().z) + (float)totalSize / 2f);\r
+        Vector3f normal = getNormal(x, z, xz);\r
+        \r
+        return normal;\r
+    }\r
+    \r
+    protected Vector3f getNormal(float x, float z, Vector2f xz) {\r
+        x-=0.5f;\r
+        z-=0.5f;\r
+        float col = FastMath.floor(x);\r
+        float row = FastMath.floor(z);\r
+        boolean onX = false;\r
+        if(1 - (x - col)-(z - row) < 0) // what triangle to interpolate on\r
+            onX = true;\r
+        // v1--v2  ^\r
+        // |  / |  |\r
+        // | /  |  |\r
+        // v3--v4  | Z\r
+        //         |\r
+        // <-------Y\r
+        //     X \r
+        Vector3f n1 = getMeshNormal((int) FastMath.ceil(x), (int) FastMath.ceil(z));\r
+        Vector3f n2 = getMeshNormal((int) FastMath.floor(x), (int) FastMath.ceil(z));\r
+        Vector3f n3 = getMeshNormal((int) FastMath.ceil(x), (int) FastMath.floor(z));\r
+        Vector3f n4 = getMeshNormal((int) FastMath.floor(x), (int) FastMath.floor(z));\r
+        \r
+        return n1.add(n2).add(n3).add(n4).normalize();\r
+    }\r
+    \r
     public void setHeight(Vector2f xz, float height) {\r
         List<Vector2f> coord = new ArrayList<Vector2f>();\r
         coord.add(xz);\r
index d51a3ce..1fe7253 100644 (file)
 package jme3test.terrain;
 
 import com.jme3.app.SimpleApplication;
-import com.jme3.bounding.BoundingBox;
 import com.jme3.collision.CollisionResult;
 import com.jme3.collision.CollisionResults;
-import com.jme3.export.Savable;
-import com.jme3.export.binary.BinaryExporter;
-import com.jme3.export.binary.BinaryImporter;
 import com.jme3.font.BitmapText;
 import com.jme3.input.KeyInput;
 import com.jme3.input.MouseInput;
@@ -52,9 +48,8 @@ import com.jme3.math.ColorRGBA;
 import com.jme3.math.Ray;
 import com.jme3.math.Vector2f;
 import com.jme3.math.Vector3f;
-import com.jme3.renderer.queue.RenderQueue.Bucket;
 import com.jme3.scene.Geometry;
-import com.jme3.scene.Node;
+import com.jme3.scene.debug.Arrow;
 import com.jme3.scene.shape.Sphere;
 import com.jme3.terrain.geomipmap.TerrainGrid;
 import com.jme3.terrain.geomipmap.TerrainLodControl;
@@ -64,16 +59,8 @@ import com.jme3.terrain.heightmap.FractalHeightMapGrid;
 import com.jme3.terrain.heightmap.ImageBasedHeightMap;
 import com.jme3.texture.Texture;
 import com.jme3.texture.Texture.WrapMode;
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.logging.Level;
-import java.util.logging.Logger;
 import jme3tools.converters.ImageToAwt;
 import org.novyon.noise.ShaderUtils;
 import org.novyon.noise.basis.FilteredBasis;
@@ -106,6 +93,7 @@ public class TerrainTestModifyHeight extends SimpleApplication {
     private boolean lowerTerrain = false;
     
     private Geometry marker;
+    private Geometry markerNormal;
 
     public static void main(String[] args) {
         TerrainTestModifyHeight app = new TerrainTestModifyHeight();
@@ -132,6 +120,10 @@ public class TerrainTestModifyHeight extends SimpleApplication {
             float h = terrain.getHeight(new Vector2f(intersection.x, intersection.z));
             Vector3f tl = terrain.getWorldTranslation();
             marker.setLocalTranslation(tl.add(new Vector3f(intersection.x, h, intersection.z)) );
+            markerNormal.setLocalTranslation(tl.add(new Vector3f(intersection.x, h, intersection.z)) );
+            
+            Vector3f normal = terrain.getNormal(new Vector2f(intersection.x, intersection.z));
+            ((Arrow)markerNormal.getMesh()).setArrowExtent(normal);
         }
     }
     
@@ -148,8 +140,8 @@ public class TerrainTestModifyHeight extends SimpleApplication {
         matWire.getAdditionalRenderState().setWireframe(true);
         matWire.setColor("Color", ColorRGBA.Green);
         
-        //createTerrain();
-        createTerrainGrid();
+        createTerrain();
+        //createTerrainGrid();
         
         DirectionalLight light = new DirectionalLight();
         light.setDirection((new Vector3f(-0.5f, -1f, -0.5f)).normalize());
@@ -422,6 +414,7 @@ public class TerrainTestModifyHeight extends SimpleApplication {
     }
 
     private void createMarker() {
+        // collision marker
         Sphere sphere = new Sphere(8, 8, 0.5f);
         marker = new Geometry("Marker");
         marker.setMesh(sphere);
@@ -433,5 +426,12 @@ public class TerrainTestModifyHeight extends SimpleApplication {
         marker.setMaterial(mat);
         rootNode.attachChild(marker);
         
+        
+        // surface normal marker
+        Arrow arrow = new Arrow(new Vector3f(0,1,0));
+        markerNormal = new Geometry("MarkerNormal");
+        markerNormal.setMesh(arrow);
+        markerNormal.setMaterial(mat);
+        rootNode.attachChild(markerNormal);
     }
 }