* fixed bug with terrain collision and flat terrain having a zero-volume bounding box

* corrected terrain.getHeight()

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@8135 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
3.0
bre..ns 13 years ago
parent e102bfe0de
commit 6940694e14
  1. 67
      engine/src/terrain/com/jme3/terrain/geomipmap/TerrainQuad.java

@ -77,6 +77,20 @@ import java.util.logging.Logger;
* *
* The leaves of the terrain quad tree are Terrain Patches. These have the real geometry mesh. * The leaves of the terrain quad tree are Terrain Patches. These have the real geometry mesh.
* *
*
* Heightmap coordinates start from the bottom left of the world and work towards the
* top right. This will seem upside down, but the texture coordinates compensate; and
* it allows you to easily get the heightmap values at real world X,Z coordinates.
*
* +x
* ^
* | ......N = length of heightmap
* | : :
* | : :
* | 0.....:
* +---------> +z
* (world coordinates)
*
* @author Brent Owens * @author Brent Owens
*/ */
public class TerrainQuad extends Node implements Terrain { public class TerrainQuad extends Node implements Terrain {
@ -152,16 +166,17 @@ public class TerrainQuad extends Node implements Terrain {
LodCalculatorFactory lodCalculatorFactory) LodCalculatorFactory lodCalculatorFactory)
{ {
super(name); super(name);
if (heightMap == null)
heightMap = generateDefaultHeightMap(size);
if (!FastMath.isPowerOfTwo(size - 1)) { if (!FastMath.isPowerOfTwo(size - 1)) {
throw new RuntimeException("size given: " + size + " Terrain quad sizes may only be (2^N + 1)"); throw new RuntimeException("size given: " + size + " Terrain quad sizes may only be (2^N + 1)");
} }
if (FastMath.sqrt(heightMap.length) > size) { if (FastMath.sqrt(heightMap.length) > size) {
Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "Heightmap size is larger than the terrain size. Make sure your heightmap image is the same size as the terrain!"); Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "Heightmap size is larger than the terrain size. Make sure your heightmap image is the same size as the terrain!");
} }
if (heightMap == null)
heightMap = generateDefaultHeightMap(size);
this.offset = offset; this.offset = offset;
this.offsetAmount = offsetAmount; this.offsetAmount = offsetAmount;
this.totalSize = totalSize; this.totalSize = totalSize;
@ -958,21 +973,29 @@ public class TerrainQuad extends Node implements Terrain {
* @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, Vector2f xz) {
float topLeft = getHeightmapHeight((int)FastMath.floor(x), (int)FastMath.ceil(z)); x-=0.5f;
float topRight = getHeightmapHeight((int)FastMath.ceil(x), (int)FastMath.ceil(z)); z-=0.5f;
float bottomLeft = getHeightmapHeight((int)FastMath.floor(x), (int)FastMath.floor(z)); float col = FastMath.floor(x);
float bottomRight = getHeightmapHeight((int)FastMath.ceil(x), (int)FastMath.floor(z)); float row = FastMath.floor(z);
boolean onX = false;
// create a vertical, down-facing, ray and get the height from that if(1 - (x - col)-(z - row) < 0) // what triangle to interpolate on
float max = Math.max(Math.max(Math.max(topLeft, topRight), bottomRight),bottomLeft); onX = true;
max = max*getWorldScale().y; // v1--v2 ^
Ray ray = new Ray(new Vector3f(xz.x,max+10f,xz.y), new Vector3f(0,-1,0).normalizeLocal()); // | / | |
CollisionResults cr = new CollisionResults(); // | / | |
int num = this.collideWith(ray, cr); // v3--v4 | Z
if (num > 0) // |
return cr.getClosestCollision().getContactPoint().y; // <-------Y
else // X
return 0; float v1 = getHeightmapHeight((int) FastMath.ceil(x), (int) FastMath.ceil(z));
float v2 = getHeightmapHeight((int) FastMath.floor(x), (int) FastMath.ceil(z));
float v3 = getHeightmapHeight((int) FastMath.ceil(x), (int) FastMath.floor(z));
float v4 = getHeightmapHeight((int) FastMath.floor(x), (int) FastMath.floor(z));
if (onX) {
return ((x - col) + (z - row) - 1f)*v1 + (1f - (x - col))*v2 + (1f - (z - row))*v3;
} else {
return (1f - (x - col) - (z - row))*v4 + (z - row)*v2 + (x - col)*v3;
}
} }
public void setHeight(Vector2f xz, float height) { public void setHeight(Vector2f xz, float height) {
@ -1473,6 +1496,12 @@ public class TerrainQuad extends Node implements Terrain {
for (int i = 0; i < getQuantity(); i++) { for (int i = 0; i < getQuantity(); i++) {
if (children.get(i) instanceof TerrainPatch) { if (children.get(i) instanceof TerrainPatch) {
TerrainPatch tp = (TerrainPatch) children.get(i); TerrainPatch tp = (TerrainPatch) children.get(i);
if (tp.getModelBound() instanceof BoundingBox) {
if (((BoundingBox)tp.getModelBound()).getYExtent() == 0) {
// a correction so the box always has a volume
((BoundingBox)tp.getModelBound()).setYExtent(0.00001f);
}
}
if (tp.getWorldBound().intersects(toTest)) { if (tp.getWorldBound().intersects(toTest)) {
CollisionResults cr = new CollisionResults(); CollisionResults cr = new CollisionResults();
toTest.collideWith(tp.getWorldBound(), cr); toTest.collideWith(tp.getWorldBound(), cr);

Loading…
Cancel
Save