From 64b736f2e94c82331f39247f009013f9dbba80b8 Mon Sep 17 00:00:00 2001 From: "bre..ns" Date: Tue, 3 Apr 2012 15:13:31 +0000 Subject: [PATCH] fix a bug in terrain getHeight for some edge cases git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9275 75d07b2b-3a1a-0410-a2c5-0572b91ccdca --- .../com/jme3/terrain/geomipmap/LODGeomap.java | 57 +++++++++- .../jme3/terrain/geomipmap/TerrainPatch.java | 4 + .../jme3/terrain/geomipmap/TerrainQuad.java | 100 +++++++++++++----- 3 files changed, 132 insertions(+), 29 deletions(-) diff --git a/engine/src/terrain/com/jme3/terrain/geomipmap/LODGeomap.java b/engine/src/terrain/com/jme3/terrain/geomipmap/LODGeomap.java index 104d75826..2f85d23c4 100644 --- a/engine/src/terrain/com/jme3/terrain/geomipmap/LODGeomap.java +++ b/engine/src/terrain/com/jme3/terrain/geomipmap/LODGeomap.java @@ -929,6 +929,61 @@ public class LODGeomap extends GeoMap { } } + /** + * Get the two triangles that make up the grid section at the specified point. + * + * For every grid space there are two triangles oriented like this: + * *----* + * |a / | + * | / b| + * *----* + * The corners of the mesh have differently oriented triangles. The two + * corners that we have to special-case are the top left and bottom right + * corners. They are oriented inversely: + * *----* + * | \ b| + * |a \ | + * *----* + */ + protected float getHeight(int x, int z, float xm, float zm) { + + int index = findClosestHeightIndex(x, z); + if (index < 0) { + return Float.NaN; + } + + float h1 = hdata[index]; // top left + float h2 = hdata[index + 1]; // top right + float h3 = hdata[index + width]; // bottom left + float h4 = hdata[index + width + 1]; // bottom right + + //float dix = (x % 1f) ; + //float diz = (z % 1f) ; + + if ((x == 0 && z == 0) || (x == width - 2 && z == width - 2)) { + // top left or bottom right grid point + /* 1----2 + * | \ b| + * |a \ | + * 3----4 */ + if (xm> 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) + return new QuadrantChild(col, row, spat); + } + } + return null; + } + + /** + * Get the interpolated height of the terrain at the specified point. + * @param xz the location to get the height for + * @return Float.NAN if the value does not exist, or the coordinates are outside of the terrain + */ public float getHeight(Vector2f xz) { // offset - float x = (float)(((xz.x - getWorldTranslation().x) / getWorldScale().x) + (float)totalSize / 2f); - float z = (float)(((xz.y - getWorldTranslation().z) / getWorldScale().z) + (float)totalSize / 2f); - float height = getHeight(x, z); + float x = (float)(((xz.x - getWorldTranslation().x) / getWorldScale().x) + (float)(totalSize-1) / 2f); + float z = (float)(((xz.y - getWorldTranslation().z) / getWorldScale().z) + (float)(totalSize-1) / 2f); + float height = getHeight((int)x, (int)z, (x%1f), (z%1f)); height *= getWorldScale().y; return height; } /* * gets an interpolated value at the specified point - * @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) { - 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 - 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; + protected float getHeight(int x, int z, float xm, float zm) { + + QuadrantChild match = findMatchingChild(x,z); + if (match != null) { + if (match.child instanceof TerrainQuad) { + return ((TerrainQuad) match.child).getHeight(match.col, match.row, xm, zm); + } else if (match.child instanceof TerrainPatch) { + return ((TerrainPatch) match.child).getHeight(match.col, match.row, xm, zm); + } } + return Float.NaN; } public Vector3f getNormal(Vector2f xz) {