added terrain.getNormal(x,z)

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@8200 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
3.0
bre..ns 14 years ago
parent 7036ce194a
commit 69fe43f079
  1. 9
      engine/src/terrain/com/jme3/terrain/Terrain.java
  2. 23
      engine/src/terrain/com/jme3/terrain/geomipmap/TerrainPatch.java
  3. 80
      engine/src/terrain/com/jme3/terrain/geomipmap/TerrainQuad.java
  4. 32
      engine/src/test/jme3test/terrain/TerrainTestModifyHeight.java

@ -54,6 +54,15 @@ public interface Terrain {
* @return the height at the given point * @return the height at the given point
*/ */
public float getHeight(Vector2f xz); 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 * Get the heightmap height at the specified X-Z coordinate. This does not

@ -691,19 +691,19 @@ public class TerrainPatch extends Geometry {
Vector3f n1 = Vector3f.ZERO; Vector3f n1 = Vector3f.ZERO;
if (topPoint != null && leftPoint != null) { 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; Vector3f n2 = Vector3f.ZERO;
if (leftPoint != null && bottomPoint != null) { 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; Vector3f n3 = Vector3f.ZERO;
if (rightPoint != null && bottomPoint != null) { 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; Vector3f n4 = Vector3f.ZERO;
if (rightPoint != null && topPoint != null) { 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(); Vector3f binormal = new Vector3f();
@ -713,12 +713,25 @@ public class TerrainPatch extends Geometry {
normal.set(n1.add(n2).add(n3).add(n4).normalizeLocal()); 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(); Vector3f normal = new Vector3f();
normal.set(firstPoint).subtractLocal(rootPoint) normal.set(firstPoint).subtractLocal(rootPoint)
.crossLocal(secondPoint.subtract(rootPoint)).normalizeLocal(); .crossLocal(secondPoint.subtract(rootPoint)).normalizeLocal();
return normal; 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. * Locks the mesh (sets it static) to improve performance.

@ -959,12 +959,56 @@ public class TerrainQuad extends Node implements Terrain {
return Float.NaN; 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) { public float getHeight(Vector2f xz) {
// offset // offset
float x = (float)(((xz.x - getLocalTranslation().x) / getLocalScale().x) + (float)totalSize / 2f); 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 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; height *= getLocalScale().y;
return height; return height;
} }
@ -974,7 +1018,7 @@ public class TerrainQuad extends Node implements Terrain {
* @param x coordinate translated into actual (positive) terrain grid coordinates * @param x coordinate translated into actual (positive) terrain grid coordinates
* @param y 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; x-=0.5f;
z-=0.5f; z-=0.5f;
float col = FastMath.floor(x); 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) { public void setHeight(Vector2f xz, float height) {
List<Vector2f> coord = new ArrayList<Vector2f>(); List<Vector2f> coord = new ArrayList<Vector2f>();
coord.add(xz); coord.add(xz);

@ -32,12 +32,8 @@
package jme3test.terrain; package jme3test.terrain;
import com.jme3.app.SimpleApplication; import com.jme3.app.SimpleApplication;
import com.jme3.bounding.BoundingBox;
import com.jme3.collision.CollisionResult; import com.jme3.collision.CollisionResult;
import com.jme3.collision.CollisionResults; 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.font.BitmapText;
import com.jme3.input.KeyInput; import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput; import com.jme3.input.MouseInput;
@ -52,9 +48,8 @@ import com.jme3.math.ColorRGBA;
import com.jme3.math.Ray; import com.jme3.math.Ray;
import com.jme3.math.Vector2f; import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
import com.jme3.renderer.queue.RenderQueue.Bucket;
import com.jme3.scene.Geometry; 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.scene.shape.Sphere;
import com.jme3.terrain.geomipmap.TerrainGrid; import com.jme3.terrain.geomipmap.TerrainGrid;
import com.jme3.terrain.geomipmap.TerrainLodControl; 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.terrain.heightmap.ImageBasedHeightMap;
import com.jme3.texture.Texture; import com.jme3.texture.Texture;
import com.jme3.texture.Texture.WrapMode; 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.ArrayList;
import java.util.List; import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import jme3tools.converters.ImageToAwt; import jme3tools.converters.ImageToAwt;
import org.novyon.noise.ShaderUtils; import org.novyon.noise.ShaderUtils;
import org.novyon.noise.basis.FilteredBasis; import org.novyon.noise.basis.FilteredBasis;
@ -106,6 +93,7 @@ public class TerrainTestModifyHeight extends SimpleApplication {
private boolean lowerTerrain = false; private boolean lowerTerrain = false;
private Geometry marker; private Geometry marker;
private Geometry markerNormal;
public static void main(String[] args) { public static void main(String[] args) {
TerrainTestModifyHeight app = new TerrainTestModifyHeight(); TerrainTestModifyHeight app = new TerrainTestModifyHeight();
@ -132,6 +120,10 @@ public class TerrainTestModifyHeight extends SimpleApplication {
float h = terrain.getHeight(new Vector2f(intersection.x, intersection.z)); float h = terrain.getHeight(new Vector2f(intersection.x, intersection.z));
Vector3f tl = terrain.getWorldTranslation(); Vector3f tl = terrain.getWorldTranslation();
marker.setLocalTranslation(tl.add(new Vector3f(intersection.x, h, intersection.z)) ); 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.getAdditionalRenderState().setWireframe(true);
matWire.setColor("Color", ColorRGBA.Green); matWire.setColor("Color", ColorRGBA.Green);
//createTerrain(); createTerrain();
createTerrainGrid(); //createTerrainGrid();
DirectionalLight light = new DirectionalLight(); DirectionalLight light = new DirectionalLight();
light.setDirection((new Vector3f(-0.5f, -1f, -0.5f)).normalize()); light.setDirection((new Vector3f(-0.5f, -1f, -0.5f)).normalize());
@ -422,6 +414,7 @@ public class TerrainTestModifyHeight extends SimpleApplication {
} }
private void createMarker() { private void createMarker() {
// collision marker
Sphere sphere = new Sphere(8, 8, 0.5f); Sphere sphere = new Sphere(8, 8, 0.5f);
marker = new Geometry("Marker"); marker = new Geometry("Marker");
marker.setMesh(sphere); marker.setMesh(sphere);
@ -433,5 +426,12 @@ public class TerrainTestModifyHeight extends SimpleApplication {
marker.setMaterial(mat); marker.setMaterial(mat);
rootNode.attachChild(marker); 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);
} }
} }

Loading…
Cancel
Save