2
0
Эх сурвалжийг харах

added terrain.getNormal(x,z)

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@8200 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
bre..ns 14 жил өмнө
parent
commit
69fe43f079

+ 9 - 0
engine/src/terrain/com/jme3/terrain/Terrain.java

@@ -54,6 +54,15 @@ public interface Terrain {
      * @return the height at the given point
      */
     public float getHeight(Vector2f xz);
+    
+    /**
+     * Get the normal vector for the surface of the terrain at the specified
+     * X-Z coordinate. This normal vector can be a close approximation. It does not
+     * take into account any normal maps on the material.
+     * @param xz the X-Z world coordinate
+     * @return the normal vector at the given point
+     */
+    public Vector3f getNormal(Vector2f xz);
 
     /**
      * Get the heightmap height at the specified X-Z coordinate. This does not

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

@@ -691,19 +691,19 @@ public class TerrainPatch extends Geometry {
         
         Vector3f n1 = Vector3f.ZERO;
         if (topPoint != null && leftPoint != null) {
-            n1 = getNormal(topPoint.mult(scale), rootPoint.mult(scale), leftPoint.mult(scale));
+            n1 = calculateNormal(topPoint.mult(scale), rootPoint.mult(scale), leftPoint.mult(scale));
         }
         Vector3f n2 = Vector3f.ZERO;
         if (leftPoint != null && bottomPoint != null) {
-            n2 = getNormal(leftPoint.mult(scale), rootPoint.mult(scale), bottomPoint.mult(scale));
+            n2 = calculateNormal(leftPoint.mult(scale), rootPoint.mult(scale), bottomPoint.mult(scale));
         }
         Vector3f n3 = Vector3f.ZERO;
         if (rightPoint != null && bottomPoint != null) {
-            n3 = getNormal(bottomPoint.mult(scale), rootPoint.mult(scale), rightPoint.mult(scale));
+            n3 = calculateNormal(bottomPoint.mult(scale), rootPoint.mult(scale), rightPoint.mult(scale));
         }
         Vector3f n4 = Vector3f.ZERO;
         if (rightPoint != null && topPoint != null) {
-            n4 = getNormal(rightPoint.mult(scale), rootPoint.mult(scale), topPoint.mult(scale));
+            n4 = calculateNormal(rightPoint.mult(scale), rootPoint.mult(scale), topPoint.mult(scale));
         }
         
         Vector3f binormal = new Vector3f();
@@ -713,12 +713,25 @@ public class TerrainPatch extends Geometry {
         normal.set(n1.add(n2).add(n3).add(n4).normalizeLocal());
     }
 
-    private Vector3f getNormal(Vector3f firstPoint, Vector3f rootPoint, Vector3f secondPoint) {
+    private Vector3f calculateNormal(Vector3f firstPoint, Vector3f rootPoint, Vector3f secondPoint) {
         Vector3f normal = new Vector3f();
         normal.set(firstPoint).subtractLocal(rootPoint)
                   .crossLocal(secondPoint.subtract(rootPoint)).normalizeLocal();
         return normal;
     }
+    
+    protected Vector3f getMeshNormal(int x, int z) {
+        if (x >= size || z >= size)
+            return null; // out of range
+        
+        int index = (z*size+x)*3;
+        FloatBuffer nb = (FloatBuffer)this.getMesh().getBuffer(Type.Normal).getData();
+        Vector3f normal = new Vector3f();
+        normal.x = nb.get(index);
+        normal.y = nb.get(index+1);
+        normal.z = nb.get(index+2);
+        return normal;
+    }
 
     /**
      * Locks the mesh (sets it static) to improve performance.

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

@@ -959,12 +959,56 @@ public class TerrainQuad extends Node implements Terrain {
         return Float.NaN;
     }
 
+    protected Vector3f getMeshNormal(int x, int z) {
+        int quad = findQuadrant(x, z);
+        int split = (size + 1) >> 1;
+        if (children != null) {
+            for (int i = children.size(); --i >= 0;) {
+                Spatial spat = children.get(i);
+                int col = x;
+                int row = z;
+                boolean match = false;
+
+                // get the childs quadrant
+                int childQuadrant = 0;
+                if (spat instanceof TerrainQuad) {
+                    childQuadrant = ((TerrainQuad) spat).getQuadrant();
+                } else if (spat instanceof TerrainPatch) {
+                    childQuadrant = ((TerrainPatch) spat).getQuadrant();
+                }
+
+                if (childQuadrant == 1 && (quad & 1) != 0) {
+                    match = true;
+                } else if (childQuadrant == 2 && (quad & 2) != 0) {
+                    row = z - split + 1;
+                    match = true;
+                } else if (childQuadrant == 3 && (quad & 4) != 0) {
+                    col = x - split + 1;
+                    match = true;
+                } else if (childQuadrant == 4 && (quad & 8) != 0) {
+                    col = x - split + 1;
+                    row = z - split + 1;
+                    match = true;
+                }
+
+                if (match) {
+                    if (spat instanceof TerrainQuad) {
+                        return ((TerrainQuad) spat).getMeshNormal(col, row);
+                    } else if (spat instanceof TerrainPatch) {
+                        return ((TerrainPatch) spat).getMeshNormal(col, row);
+                    }
+                }
+
+            }
+        }
+        return null;
+    }
 
     public float getHeight(Vector2f xz) {
         // offset
         float x = (float)(((xz.x - getLocalTranslation().x) / getLocalScale().x) + (float)totalSize / 2f);
         float z = (float)(((xz.y - getLocalTranslation().z) / getLocalScale().z) + (float)totalSize / 2f);
-        float height = getHeight(x, z, xz);
+        float height = getHeight(x, z);
         height *= getLocalScale().y;
         return height;
     }
@@ -974,7 +1018,7 @@ public class TerrainQuad extends Node implements Terrain {
      * @param x coordinate translated into actual (positive) terrain grid coordinates
      * @param y coordinate translated into actual (positive) terrain grid coordinates
      */
-    protected float getHeight(float x, float z, Vector2f xz) {
+    protected float getHeight(float x, float z) {
         x-=0.5f;
         z-=0.5f;
         float col = FastMath.floor(x);
@@ -1000,6 +1044,38 @@ public class TerrainQuad extends Node implements Terrain {
         }
     }
 
+    public Vector3f getNormal(Vector2f xz) {
+        // offset
+        float x = (float)(((xz.x - getLocalTranslation().x) / getLocalScale().x) + (float)totalSize / 2f);
+        float z = (float)(((xz.y - getLocalTranslation().z) / getLocalScale().z) + (float)totalSize / 2f);
+        Vector3f normal = getNormal(x, z, xz);
+        
+        return normal;
+    }
+    
+    protected Vector3f getNormal(float x, float z, Vector2f xz) {
+        x-=0.5f;
+        z-=0.5f;
+        float col = FastMath.floor(x);
+        float row = FastMath.floor(z);
+        boolean onX = false;
+        if(1 - (x - col)-(z - row) < 0) // what triangle to interpolate on
+            onX = true;
+        // v1--v2  ^
+        // |  / |  |
+        // | /  |  |
+        // v3--v4  | Z
+        //         |
+        // <-------Y
+        //     X 
+        Vector3f n1 = getMeshNormal((int) FastMath.ceil(x), (int) FastMath.ceil(z));
+        Vector3f n2 = getMeshNormal((int) FastMath.floor(x), (int) FastMath.ceil(z));
+        Vector3f n3 = getMeshNormal((int) FastMath.ceil(x), (int) FastMath.floor(z));
+        Vector3f n4 = getMeshNormal((int) FastMath.floor(x), (int) FastMath.floor(z));
+        
+        return n1.add(n2).add(n3).add(n4).normalize();
+    }
+    
     public void setHeight(Vector2f xz, float height) {
         List<Vector2f> coord = new ArrayList<Vector2f>();
         coord.add(xz);

+ 16 - 16
engine/src/test/jme3test/terrain/TerrainTestModifyHeight.java

@@ -32,12 +32,8 @@
 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);
     }
 }