Heightmaps + normals

Hi,

I’m trying to create terrain using the ImageBasedHeightMap. However, the terrain looks boring because there is no shading or shadows. Is there some sort of ‘normal generator’ I can use to shade my terrain?



I did add a directional light, but it seems that normals are not automatically generated. Did I do something wrong here?



DirectionalLight sun = new DirectionalLight();

sun.setColor(ColorRGBA.White);

sun.setDirection(new Vector3f(-1, -1, 1).normalizeLocal());

rootNode.addLight(sun);

perhaps this will work, don’t know:



[java]TangentBinormalGenerator.generate(terrain);[/java]

Do you use the TerrainLighting material or Terrain material? the first one is shaded, the second one is unshaded.

I used this (I got this from the tutorials on this website and modified it as I needed):



private TerrainQuad terrain;

private Material mat_terrain;





flyCam.setMoveSpeed(300);



DirectionalLight sun = new DirectionalLight();

sun.setColor(ColorRGBA.White);

sun.setDirection(new Vector3f(-1, -1, 1).normalizeLocal());

rootNode.addLight(sun);



/** 1. Create terrain material and load four textures into it. /

mat_terrain = new Material(assetManager,

“Common/MatDefs/Terrain/Terrain.j3md”);



/
* 1.1) Add ALPHA map (for red-blue-green coded splat textures) /

mat_terrain.setTexture(“Alpha”, assetManager.loadTexture(

“Textures/splat/alphamap.png”));



/
* 1.2) Add GRASS texture into the red layer (Tex1). /

Texture grass = assetManager.loadTexture(

“Textures/splat/grass.gif”);

grass.setWrap(WrapMode.Repeat);

mat_terrain.setTexture(“Tex1”, grass);

mat_terrain.setFloat(“Tex1Scale”, 64f);



/
* 1.3) Add DIRT texture into the green layer (Tex2) /

Texture dirt = assetManager.loadTexture(

“Textures/splat/dirt.gif”);

dirt.setWrap(WrapMode.Repeat);

mat_terrain.setTexture(“Tex2”, dirt);

mat_terrain.setFloat(“Tex2Scale”, 32f);



/
* 1.4) Add ROAD texture into the blue layer (Tex3) /

Texture rock = assetManager.loadTexture(

“Textures/splat/road.gif”);

rock.setWrap(WrapMode.Repeat);

mat_terrain.setTexture(“Tex3”, rock);

mat_terrain.setFloat(“Tex3Scale”, 128f);



/
* 2. Create the height map /

AbstractHeightMap heightmap = null;

Texture heightMapImage = assetManager.loadTexture(

“Textures/splat/mountain128.gif”);

heightmap = new ImageBasedHeightMap(

ImageToAwt.convert(heightMapImage.getImage(), false, true, 0));

heightmap.load();

// try {

// heightmap = new MidpointDisplacementHeightMap(129, 1, 0.5f, 0);

// } catch (Exception e) {}



/
* 3. We have prepared material and heightmap.

  • Now we create the actual terrain:
  • 3.1) Create a TerrainQuad and name it “my terrain”.
  • 3.2) A good value for terrain tiles is 64x64 – so we supply 64+1=65.
  • 3.3) We prepared a heightmap of size 512x512 – so we supply 512+1=513.
  • 3.4) As LOD step scale we supply Vector3f(1,1,1).
  • 3.5) We supply the prepared heightmap itself.

    /

    int patchSize = 65;

    terrain = new TerrainQuad(“my terrain”, patchSize, 513, heightmap.getHeightMap());



    /
    * 4. We give the terrain its material, position & scale it, and attach it. /

    terrain.setMaterial(mat_terrain);

    terrain.setLocalTranslation(0, -100, 0);

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

    rootNode.attachChild(terrain);



    /
    * 5. The LOD (level of detail) depends on were the camera is: */

    List cameras = new ArrayList();

    cameras.add(getCamera());

    TerrainLodControl control = new TerrainLodControl(terrain, cameras);

    terrain.addControl(control);

[java]

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

[/java]

that’s the problem



try

[java]

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

[/java]

java.lang.IllegalArgumentException: Material parameter is not defined: Alpha

at com.jme3.material.Material.checkSetParam(Material.java:374)

at com.jme3.material.Material.setTextureParam(Material.java:476)

at com.jme3.material.Material.setTexture(Material.java:524)

at HelloTerrain2.simpleInitApp(HelloTerrain2.java:46)

at com.jme3.app.SimpleApplication.initialize(SimpleApplication.java:230)

at com.jme3.system.lwjgl.LwjglAbstractDisplay.initInThread(LwjglAbstractDisplay.java:129)

at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:205)

at java.lang.Thread.run(Thread.java:662)



line 47 is



mat_terrain.setTexture(“Alpha”, assetManager.loadTexture(

“Textures/splat/alphamap.png”));



when I commented that line out the rest of the setTexture() calls throw similar exceptions



edit: I commented out ALL the setTextures() and the code succesfully ran; the terrain is gorgeous. But how do I get the textures to work?

I do need the texture splatting.

erf yeah there might be a couple of things to change

take a look at this test case

http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/test/jme3test/terrain/TerrainTestAdvanced.java

2 Likes

Nehon is correct. To have the terrain look pretty you want to use the TerrainLighting material, as shows in the TerrainTestAdvanced.java file.

This is what I did. I took nehon’s link and copied it into my code, making minimal changes to try and see if it works as is. I got a compiler error at :

heightmap = new ImageBasedHeightMap(heightMapImage.getImage());



[java]

assets = assetManager;



Material matTerrain = new Material(Artist.assets, “Common/MatDefs/Terrain/TerrainLighting.j3md”);

matTerrain.setBoolean(“useTriPlanarMapping”, false);

matTerrain.setFloat(“Shininess”, 0.0f);



matTerrain.setTexture(“AlphaMap”, Artist.assets.loadTexture(“Textures/alpha.png”));

matTerrain.setTexture(“AlphaMap_1”, Artist.assets.loadTexture(“Textures/alpha.png”));



Texture grass = Artist.assets.loadTexture(“Textures/grass.gif”);

grass.setWrap(WrapMode.Repeat);

matTerrain.setTexture(“DiffuseMap_1”, grass);

matTerrain.setFloat(“DiffuseMap_1_scale”, 16);



Texture dirt = Artist.assets.loadTexture(“Textures/mountain.gif”);

dirt.setWrap(WrapMode.Repeat);

matTerrain.setTexture(“DiffuseMap”, dirt);

matTerrain.setFloat(“DiffuseMap_0_scale”, 16);



Texture rock = Artist.assets.loadTexture(“Textures/plains.gif”);

rock.setWrap(WrapMode.Repeat);

matTerrain.setTexture(“DiffuseMap_2”, rock);

matTerrain.setFloat(“DiffuseMap_2_scale”, 16);





Texture normalMap0 = Artist.assets.loadTexture(“Textures/grass.gif”);

normalMap0.setWrap(WrapMode.Repeat);

Texture normalMap1 = Artist.assets.loadTexture(“Textures/mountain.gif”);

normalMap1.setWrap(WrapMode.Repeat);

Texture normalMap2 = Artist.assets.loadTexture(“Textures/plains.gif”);

normalMap2.setWrap(WrapMode.Repeat);

matTerrain.setTexture(“NormalMap”, normalMap0);



AbstractHeightMap heightmap = null;

Texture heightMapImage = assetManager.loadTexture(

“Textures/mountain.gif”);

heightmap = new ImageBasedHeightMap(heightMapImage.getImage());

heightmap.load();



int patchSize = 65;

TerrainQuad terrain = new TerrainQuad(“my terrain”, patchSize, 513, heightmap.getHeightMap());



terrain.setMaterial(matTerrain);

terrain.setModelBound(new BoundingBox());

terrain.updateModelBound();

terrain.setLocalTranslation(0, -100, 0);

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

rootNode.attachChild(terrain);



DirectionalLight light = new DirectionalLight();

light.setDirection((new Vector3f(-0.5f, -0.5f, -0.5f)).normalize());

rootNode.addLight(light);

[/java]



At the line: heightmap = new ImageBasedHeightMap(heightMapImage.getImage());



no suitable constructor found for ImageBasedHeightMap(com.jme3.texture.Image)

constructor com.jme3.terrain.heightmap.ImageBasedHeightMap.ImageBasedHeightMap(java.awt.Image,float) is not applicable

(actual and formal argument lists differ in length)

constructor com.jme3.terrain.heightmap.ImageBasedHeightMap.ImageBasedHeightMap(java.awt.Image) is not applicable

(actual argument com.jme3.texture.Image cannot be converted to java.awt.Image by method invocation conversion)



Apparently the compiler is confusing the awt Image class with jme3’s Image class. I tried various castings and some other stuff but it didn’t work.

You need to update to the latest version from SVN or the latest nightly build.