TerrainGrid Test yields unexpected result

Hey, I also updated the code, but now I’m getting very curious results.



First, I found out that the heightmap has to be a 16-bit png and I don’t really know how to create one, maybe you know a tool or something, and secondly the texture is acting very strange. The colors seem to be wrong somehow, here is a pic:







As you might see, the texture seems to be loading fine, but its very, very dark, so you can’t see colors.

@garymedas said:
First, I found out that the heightmap has to be a 16-bit png and I don't really know how to create one, maybe you know a tool or something, and secondly the texture is acting very strange. The colors seem to be wrong somehow, here is a pic:

ImageBasedHeightMapGrid has been using 16 bit grayscale since June. You can create one easily in photoshop: new image, pick grayscale, set to 16 bit.
ImageBasedHeightMapGrid should handle whatever image type you supply however, that is a change I need to make.

The darkness there might be if you have no light? Or just very little light.
@Sploreg said:
The darkness there might be if you have no light? Or just very little light.


I don't think thats the problem, because I tried changing light settings and it didn't change anything (even if I used colored light). It even shouldn't have an impact on the terrain because in "TerrainGrid.java" is also no light. I used now a brighter texture to show you what I mean:



It really looks like it was to dark, but the light is definitely not the problem. I also got a result where the teexture on screen was much much brighter than the original one.

TerrainGrid doesn’t use a specific material, you set that outside of the grid class. Nor does it use the lights, that is also up to the material.

What material are you using and what lights have you defined in your scene?

Okay, I solved the problem now by using png heightmaps. Until now I had the standard “all-zero” heightmap, where the results where strange like this. But with the real heightmaps it somehow works, but not really. It now appears correctly, but when I move to another map, the maps overlap, which means that one heightmap seems to be over the other. So appearently, I am below one heightmap and can the see the above heightmap. There are really strange behaviours:


  1. I go straight through the map and suddenly I am “warped” to another map. When I look behind my back I don’t see the old map where I came from.
  2. I change the map and can walk “under” the old map and see it from the bottom.
  3. The maps really seem to be on layers directly above each other, while they should be bordering each other.

Hmm, with the flat heightmap it could be that the normals are not calculated properly. Definitely a bug with that.



Could you post the code you use to set up your map? That tile stacking is not normal.

@Sploreg Ok, this issue isn’t solved yet!



Here is the code I am using, ( I have attached a light, there was no light in that scene, so how your screenshot is lit? ) (the physics and character stuff is commented out)



[java]package jme3test.terrain;



import com.jme3.app.SimpleApplication;

import com.jme3.app.state.ScreenshotAppState;

import com.jme3.asset.plugins.HttpZipLocator;

import com.jme3.asset.plugins.ZipLocator;

import com.jme3.bullet.BulletAppState;

import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;

import com.jme3.bullet.collision.shapes.HeightfieldCollisionShape;

import com.jme3.bullet.control.CharacterControl;

import com.jme3.bullet.control.RigidBodyControl;

import com.jme3.input.KeyInput;

import com.jme3.input.controls.ActionListener;

import com.jme3.input.controls.KeyTrigger;

import com.jme3.light.DirectionalLight;

import com.jme3.material.Material;

import com.jme3.math.ColorRGBA;

import com.jme3.math.Vector3f;

import com.jme3.terrain.geomipmap.TerrainGrid;

import com.jme3.terrain.geomipmap.TerrainGridListener;

import com.jme3.terrain.geomipmap.TerrainLodControl;

import com.jme3.terrain.geomipmap.TerrainQuad;

import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator;

import com.jme3.terrain.heightmap.ImageBasedHeightMapGrid;

import com.jme3.terrain.heightmap.Namer;

import com.jme3.texture.Texture;

import com.jme3.texture.Texture.WrapMode;

import java.io.File;



public class TerrainGridTest extends SimpleApplication {



private Material mat_terrain;

private TerrainGrid terrain;

private float grassScale = 64;

private float dirtScale = 16;

private float rockScale = 128;

// private boolean usePhysics = true;

// private boolean physicsAdded = false;



public static void main(final String[] args) {

TerrainGridTest app = new TerrainGridTest();

app.start();

}

// private CharacterControl player3;



@Override

public void simpleInitApp() {



DirectionalLight sun = new DirectionalLight();

sun.setDirection(new Vector3f(0.39415884f, -0.9180317f, 0.0430879f));

sun.setColor(ColorRGBA.White);

rootNode.addLight(sun);



File file = new File(“mountains.zip”);

// if (!file.exists()) {

// assetManager.registerLocator(“http://jmonkeyengine.googlecode.com/files/mountains.zip”, HttpZipLocator.class);

// } else {

assetManager.registerLocator(“mountains.zip”, ZipLocator.class);

// }



this.flyCam.setMoveSpeed(100f);

// ScreenshotAppState state = new ScreenshotAppState();

// this.stateManager.attach(state);



// TERRAIN TEXTURE material

this.mat_terrain = new Material(this.assetManager, “Common/MatDefs/Terrain/HeightBasedTerrain.j3md”);



// Parameters to material:

// regionXColorMap: X = 1…4 the texture that should be appliad to state X

// regionX: a Vector3f containing the following information:

// regionX.x: the start height of the region

// regionX.y: the end height of the region

// regionX.z: the texture scale for the region

// it might not be the most elegant way for storing these 3 values, but it packs the data nicely :slight_smile:

// slopeColorMap: the texture to be used for cliffs, and steep mountain sites

// slopeTileFactor: the texture scale for slopes

// terrainSize: the total size of the terrain (used for scaling the texture)

// GRASS texture

Texture grass = this.assetManager.loadTexture(“Textures/Terrain/splat/grass.jpg”);

grass.setWrap(WrapMode.Repeat);

this.mat_terrain.setTexture(“region1ColorMap”, grass);

this.mat_terrain.setVector3(“region1”, new Vector3f(88, 200, this.grassScale));



// DIRT texture

Texture dirt = this.assetManager.loadTexture(“Textures/Terrain/splat/dirt.jpg”);

dirt.setWrap(WrapMode.Repeat);

this.mat_terrain.setTexture(“region2ColorMap”, dirt);

this.mat_terrain.setVector3(“region2”, new Vector3f(0, 90, this.dirtScale));



// ROCK texture

Texture rock = this.assetManager.loadTexture(“Textures/Terrain/Rock2/rock.jpg”);

rock.setWrap(WrapMode.Repeat);

this.mat_terrain.setTexture(“region3ColorMap”, rock);

this.mat_terrain.setVector3(“region3”, new Vector3f(198, 260, this.rockScale));



this.mat_terrain.setTexture(“region4ColorMap”, rock);

this.mat_terrain.setVector3(“region4”, new Vector3f(198, 260, this.rockScale));



this.mat_terrain.setTexture(“slopeColorMap”, rock);

this.mat_terrain.setFloat(“slopeTileFactor”, 32);



this.mat_terrain.setFloat(“terrainSize”, 129);



this.terrain = new TerrainGrid(“terrain”, 65, 257, new ImageBasedHeightMapGrid(assetManager, new Namer() {



public String getName(int x, int y) {

return “Scenes/TerrainMountains/terrain_” + x + “_” + y + “.png”;

}

}));



this.terrain.setMaterial(this.mat_terrain);

this.terrain.setLocalTranslation(0, 0, 0);

this.terrain.setLocalScale(1f, 1f, 1f);

this.rootNode.attachChild(this.terrain);



TerrainLodControl control = new TerrainLodControl(this.terrain, getCamera());

control.setLodCalculator( new DistanceLodCalculator(65, 2.7f) ); // patch size, and a multiplier

this.terrain.addControl(control);



// final BulletAppState bulletAppState = new BulletAppState();

// stateManager.attach(bulletAppState);



this.getCamera().setLocation(new Vector3f(0, 256, 0));



this.viewPort.setBackgroundColor(new ColorRGBA(0.7f, 0.8f, 1f, 1f));



// if (usePhysics) {

// CapsuleCollisionShape capsuleShape = new CapsuleCollisionShape(0.5f, 1.8f, 1);

// player3 = new CharacterControl(capsuleShape, 0.5f);

// player3.setJumpSpeed(20);

// player3.setFallSpeed(10);

// player3.setGravity(10);

//

// player3.setPhysicsLocation(new Vector3f(cam.getLocation().x, 256, cam.getLocation().z));



// bulletAppState.getPhysicsSpace().add(player3);



terrain.addListener(“physicsStartListener”, new TerrainGridListener() {



public void gridMoved(Vector3f newCenter) {

}



public Material tileLoaded(Material material, Vector3f cell) {

return material;

}



public void tileAttached(Vector3f cell, TerrainQuad quad) {

quad.addControl(new RigidBodyControl(new HeightfieldCollisionShape(quad.getHeightMap(), terrain.getLocalScale()), 0));

// bulletAppState.getPhysicsSpace().add(quad);

}



public void tileDetached(Vector3f cell, TerrainQuad quad) {

// bulletAppState.getPhysicsSpace().remove(quad);

quad.removeControl(RigidBodyControl.class);

}



});

// }

this.terrain.initialize(cam.getLocation());

// this.initKeys();

}



// private void initKeys() {

// // You can map one or several inputs to one named action

// this.inputManager.addMapping(“Lefts”, new KeyTrigger(KeyInput.KEY_A));

// this.inputManager.addMapping(“Rights”, new KeyTrigger(KeyInput.KEY_D));

// this.inputManager.addMapping(“Ups”, new KeyTrigger(KeyInput.KEY_W));

// this.inputManager.addMapping(“Downs”, new KeyTrigger(KeyInput.KEY_S));

// this.inputManager.addMapping(“Jumps”, new KeyTrigger(KeyInput.KEY_SPACE));

// this.inputManager.addListener(this.actionListener, “Lefts”);

// this.inputManager.addListener(this.actionListener, “Rights”);

// this.inputManager.addListener(this.actionListener, “Ups”);

// this.inputManager.addListener(this.actionListener, “Downs”);

// this.inputManager.addListener(this.actionListener, “Jumps”);

// }

// private boolean left;

// private boolean right;

// private boolean up;

// private boolean down;

// private final ActionListener actionListener = new ActionListener() {

//

// @Override

// public void onAction(final String name, final boolean keyPressed, final float tpf) {

// if (name.equals(“Lefts”)) {

// if (keyPressed) {

// TerrainGridTest.this.left = true;

// } else {

// TerrainGridTest.this.left = false;

// }

// } else if (name.equals(“Rights”)) {

// if (keyPressed) {

// TerrainGridTest.this.right = true;

// } else {

// TerrainGridTest.this.right = false;

// }

// } else if (name.equals(“Ups”)) {

// if (keyPressed) {

// TerrainGridTest.this.up = true;

// } else {

// TerrainGridTest.this.up = false;

// }

// } else if (name.equals(“Downs”)) {

// if (keyPressed) {

// TerrainGridTest.this.down = true;

// } else {

// TerrainGridTest.this.down = false;

// }

// } else if (name.equals(“Jumps”)) {

// TerrainGridTest.this.player3.jump();

// }

// }

// };

// private final Vector3f walkDirection = new Vector3f();



@Override

public void simpleUpdate(final float tpf) {

// Vector3f camDir = this.cam.getDirection().clone().multLocal(0.6f);

// Vector3f camLeft = this.cam.getLeft().clone().multLocal(0.4f);

// this.walkDirection.set(0, 0, 0);

// if (this.left) {

// this.walkDirection.addLocal(camLeft);

// }

// if (this.right) {

// this.walkDirection.addLocal(camLeft.negate());

// }

// if (this.up) {

// this.walkDirection.addLocal(camDir);

// }

// if (this.down) {

// this.walkDirection.addLocal(camDir.negate());

// }

//

// if (usePhysics) {

// this.player3.setWalkDirection(this.walkDirection);

// this.cam.setLocation(this.player3.getPhysicsLocation());

// }

}

}

[/java]



This time I am reporting with a video. :slight_smile:



http://www.youtube.com/watch?v=B8xBTUSxLC0

.



I am moving around the scene but no textured terrain is appearing. Even I went down the black plane. Nothing is even hiding there. :stuck_out_tongue:

Yea it seems to work on mine. I guess it might be the material then. What does it look like if you set a wireframe material? I am seeing some other issues however.



@anthyon have you seen this before or have any ideas what might be causing these extra geometries?





It appears that extra terrain quads are loaded and placed in the scene, without any height applied to them. This happens in the TerrainGridTest class.



It also looks like the lod is a little broken on it when it looks to find the neighbours; it seems to not quite know where the camera is and ends up flipping the lod around causing seams.



Its as you mentioned. I only see the quad. No other geometries in the scene.



I committed some fixes to terrain grid that should help with seaming problems and the extra geometries that were seen.

I don’t think it will help with the material problem you are seeing @iamcreasy, but see if it helps with any other issues.

What might be the reason for not seeing the actual jagged terrain geometry?

hmm, it might be the downloaded zip file causing you issues.

What does TerrainFractalGridTest look like when you run it?

apart form some sudden pop up of the terrain and some seam issues TerrainFractalGridTest looks fine.

ok, I think it is the zip file not downloading for you then. It contains heightmap info for the test case and if it is not there then you get flat terrain. Check that mountains.zip is located in the directory where you are running your app. The test case should download it automatically.



The seams or holes you might be seeing is the lod catching up when new tiles get imported. It is very noticeable in the fractal demo because the terrain is very small and it is easy to get to the edge and see the next tile load in. A situation you want to prevent in the first place by making the terrain large enough. The distance on the lod calculator might also need some tweaking.

Now I was looking into mountain.zip file, and the following method

[java]

public String getName(int x, int y) {

return “Scenes/TerrainMountains/terrain_” + x + "" + y + “.png”;

}[/java]



But, there is no TerrainMountains/terrain_x_y.png. terrain
.png files are TerrainAlphaTest folder.



Now that I’ve changed it to the following, textured terrain started to appear.



[java]

public String getName(int x, int y) {

return “Scenes/TerrainAlphaTest/terrain_” + x + “_” + y + “.png”;

}[/java]



But, now there is another issue. It feels like the terrains are layered on top of each other. O_o. Why would that be?

After update :



1st case:

If I use the following :

[java]

public String getName(int x, int y) {

return “Scenes/TerrainMountains/mountains_” + x + “" + y + “.png”;

}[/java]

I get this result





2nd Case:

If I use the following :

[java] public String getName(int x, int y) {

return "Scenes/TerrainAlphaTest/terrain
” + x + “_” + y + “.png”;

}[/java]

I get this result





All are broken into pieces. No smooth transition. I think the 2nd case is what this example is all about.

Terrain grid had the axes originally incorrect to match with terrain quad. It just sort of worked by chance. The test data has to be updated. Right now the image index names are incorrect in that zip file.



EDIT: I will be fixing the test data. TerrainGrid is going through an overhaul right now to load assets differently. Once it gets nailed down then I will correct the images.

So, its the 2nd test that shows what the test was all about?