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
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.