Terrain height does not fit to heightmap

Hello guys,

I am working on a client server application. The server generates a heightmap and transfers it to the client, then the client generates the terrain based on that heightmap. I did already try the client generating the heightmap itself but I have the same problem, so I guess the transferring works.
My problem is that the value I get with heightmap.getScaledHeightAtPoint() does not fit to the way the terrain is generated (For example I get a height of around 0.9f while the terrain is at 0).

Here is some code for you:

* Creates a new map, containing the heightmap and static objects (dungeons etc)
* @param settings The world settings
public Map(WorldSettings settings) throws Exception{
this.settings = settings;
random = new Random(settings.seed);
heightmap = new HillHeightMap(settings.realmSize + 1, 100, 10, 50, 3);

public float getHeightAt(Vector2f pos){
    return heightmap.getScaledHeightAtPoint((int)pos.x, (int)pos.y);
public HeightMap getHeightMap(){
    return heightmap;

The terrain is generated like this (I will add more textures and stuff later):

private void loadTerrain(float[] hm){
terrain = new TerrainQuad(“terrain”, 33, worldSettings.realmSize + 1, hm);

    Material terMat = new Material(assetManager, "Common/MatDefs/Terrain/Terrain.j3md");
    Texture grass = assetManager.loadTexture("Textures/grass.png");
    terMat.setTexture("Tex1", grass);
    terMat.setFloat("Tex1Scale", worldSettings.realmSize);
    terrain.addControl(new TerrainLodControl(terrain, cam));       

I am sure it is something really stupid but I can’t find what I did wrong…

Thank you :smile:

My guess is that because the position is explicitly converted from a float to an int, you could be at point 10.9f and the casting returns an int with a value of 10. It doesn’t round up or down, it just truncates anything after the decimal point. Not very precise, and even worse if you have a large scale factor.

There is another method that could alleviate the issue:

Other than that, you could do good old ray casting.

I read through the method really quick to see if it would properly deal with the fact that the terrain is really triangles (straight bilinear interpolation won’t really work in that case)… given that it’s only sample x+1 and z+1 then I guess it might if the triangles are all oriented the same. (I’ve never looked at JME terrain in wireframe so I don’t know). (Edit: thinking about it again, I’m pretty sure it’s not accurate… placing things on the terrain using this will either place them too high or too low depending on the variance of the three corners. In some cases it will be super off… especially if x+1, z+1 is very different from the others.)

…but it does look like it will give bad values at the edges. It interpolates a value along x but then ignores it if it can’t sample z + 1.

Edit: bottom line: probably don’t use this method if you want to use it for accurate terrain height for placing things on the terrain. Use ray casting.

Okay, thank you… I will try it with raycasting this weekend and then I will tell you if it works :wink:

EDIT: Next problem: I am trying to use raycasting now and I think my method should work:

private float getHeightOverTerrain(){
        Ray ray = new Ray(this.getSpatial().getLocalTranslation(), new Vector3f(0, -1, 0));
        TerrainQuad terr = server.getMap(thisObject.getWorld()).getTerrain();
        CollisionResults res = new CollisionResults();
        ray.collideWith(terr, res);
        if(res.size() > 0)
            return res.getClosestCollision().getDistance();
        return 0f;

When I try to use this I do (of course) get an exception because I did not create a BoundingVolume for the terrain. How can I do this? BoundingBox and BoundingSphere are useless for it… Is there a way to create and use a MeshCollisionShape? Or am I using a completely wrong way (still no jme pro)?

Ray casting doesnt need a collision shape, but here’s the code to add a collisionshape…

tq.addControl(new RigidBodyControl(new HeightfieldCollisionShape(heightmap, tq.getLocalScale()), 0));