Height computing in TerrainBlock

Hello,



I'm trying to position a horse above a terrain. But often, the height returned by TerrainBlock.getHeight() is below the terrain 3d mesh.



I searched a bit in TerrainBlock code and found that the height for a given point is computed by bi-linear interpolation of the heightmap :



public float getHeight(float x, float z) {
        x /= stepScale.x;
        z /= stepScale.z;
        float col = FastMath.floor(x);
        float row = FastMath.floor(z);

        if (col < 0 || row < 0 || col >= size - 1 || row >= size - 1) {
            return Float.NaN;
        }
        float intOnX = x - col, intOnZ = z - row;

        float topLeft, topRight, bottomLeft, bottomRight;

        int focalSpot = (int) (col + row * size);

        // find the heightmap point closest to this position (but will always
        // be to the left ( < x) and above (< z) of the spot.
        topLeft = heightMap[focalSpot] * stepScale.y;

        // now find the next point to the right of topLeft's position...
        topRight = heightMap[focalSpot + 1] * stepScale.y;

        // now find the next point below topLeft's position...
        bottomLeft = heightMap[focalSpot + size] * stepScale.y;

        // now find the next point below and to the right of topLeft's
        // position...
        bottomRight = heightMap[focalSpot + size + 1] * stepScale.y;

        // Use linear interpolation to find the height.
       return FastMath.LERP(intOnZ, FastMath.LERP(intOnX, topLeft, topRight),
                FastMath.LERP(intOnX, bottomLeft, bottomRight));
    }



As the terrain mesh is represented by triangles, the returned result is different from the real mesh height at this point.  I wonder why you did not decide to compute it considering only the triangle in which the point actually is. I suggest the code below which I think gives more precise results :


        // Determine in witch triangle we are
        if(intOnX > intOnZ) {
           
            // point is in triangle TL-TR-BR
           
            float dHeightX = (1 - intOnX) * (topLeft - topRight);
            float dHeightZ = intOnZ * (bottomRight - topRight);
            return topRight + dHeightX + dHeightZ;
        } else {
           
            // point is in triangle TL-BR-BL
           
            float dHeightX = (intOnX) * (bottomRight - bottomLeft);
            float dHeightZ = (1 - intOnZ) * (topLeft - bottomLeft);
            return bottomLeft + dHeightX + dHeightZ;
        }



What do you think about that ?

Thanks  :)

One of the problems with this, is that it depends on which way the triangles have been set-up (i.e. the diagonal of the Quad is || or |/|). With bilinear interpolation, the result is independent on that. I agree that there is some conceptual problem with using one method for logical height, and another for actual height, but that should not be a major issue.


See this old thread:

http://www.jmonkeyengine.com/jmeforum/index.php?topic=2914.0

I think its the same code.

The triangles in TerrainBlock are set up in one way. For collision detection its better to use exact triangles. For calculating normals, its better to use interpolation.

Ok I read this post and it appears that this modification should already be done…



Renanse said :


I've added the change to my local copy.  Unfortunately the class has too many other changes that I can't check in just yet, so stay tuned.


But the actual code does not contain it I think... Has it been aborted ?

Thanks..

Hello everybody !



Are there some news about this problem ?



Thanks for your help…

It's in cvs now.  Probably was wiped in a merge.

Thanks a lot  :smiley: