added terrain.getNormal(x,z)

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@8200 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
3.0
bre..ns 13 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

@ -55,6 +55,15 @@ public interface Terrain {
*/
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
* count scaling and snaps the XZ coordinate to the nearest (rounded) heightmap grid point.

@ -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,13 +713,26 @@ 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.
* But it it not editable then. Set unlock to make it editable.

@ -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);

@ -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);
}
}

Loading…
Cancel
Save