Terrain: getHeight() returns not always exact height

Hello,



i got a problem with the function TerrainBlock.getHeight().

I increased the scale of a terrain block and noticed that the character sinks in the terrain at some special edges.



The red line is the height, which getHeight() calculates with interpolation, but the green line shows the real hight of the terrain.

In other words, A and C are the diagonal of the terrainquad, but the getHeight() function feigns as if B and D are the diagonal.



The solution would be perhaps to cast a ray with the orgin (x,0,z) and the direction (0,1,0) through the terrain and check for an intersection.

My problem is, that i don

No one can me say how to read out a terrain-triangle above a specific x,z-position?

Or is there an other solution?

I think there is no possibility with CLOD to get vertexes/triangles. Without CLOD it is quite simple, look at TerrainBlock.buildVertices() to see, how triangles are built.



This is not checked, but might work:

Between every 4 height points there are two triangles, the upper right and lower left. First we'd need to determine which triangle the object is standing on. If the frac(x)>frac(y) then it is on upper right triangle. If it is on upper right, then leave out the bottom left height point from interpolation, else leave out the upper right point.



Hope this makes some sense.  :expressionless:

You can get the triangle with pick results, but I'm not sure that is helpful to you.



Set up your pick results to get triangle pick results.



Use terrain block findPick with the ray and the pick results.



You can get a trimesh from the pick results.



From the trimesh you can get the triangle's verticies.



I'm not sure this is what you are looking for, but it works for me to click on the terrain with the mouse and have the player walk to that position.



Let me know if you want more elaboration.

@ vear:

I tried to "improve" the TerrainBlock.getHeight() function with your "idea", but something iam doing wrong and i don

Try this one:



       // Use linear interpolation to find the height.
       if(intOnX>intOnZ) {
           return FastMath.LERP(1-intOnX+intOnZ,topRight,FastMath.LERP(intOnX,topLeft,bottomRight));
       } else {
           return FastMath.LERP(intOnX+1-intOnZ,bottomLeft,FastMath.LERP(intOnX,topLeft,bottomRight));
       }



I've placed some grass around the terrain with this, and it seems to better match the slopes, but yours is the final word....

Hm, your solution seems to produce the same result than my.

The downleft triangle isn

Errm, perhaps this?



       // Use linear interpolation to find the height.
       if(intOnX>intOnZ) {
           return (1-intOnX)*topLeft + (intOnX-intOnZ)*topRight + (intOnZ)*bottomRight;
       } else {
           return (1-intOnZ)*topLeft + (intOnZ-intOnX)*bottomLeft + (intOnX)*bottomRight;
       }

That works PERFECT! :smiley:

Thank you very much, vear.

This improvement should be added to the CVS.



Class: com.jmex.TerrainBlock

Function: getHeight(float x, float z)


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.
       if(intOnX>intOnZ)
           return (1-intOnX)*topLeft + (intOnX-intOnZ)*topRight + (intOnZ)*bottomRight;
       else
           return (1-intOnZ)*topLeft + (intOnZ-intOnX)*bottomLeft + (intOnX)*bottomRight;      
   }


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.

secret changes?



Is it the elusive "Write My Game For Me" button? :-p



darkfrog