Bug in jme export/import of TerrainPage

I noticed a bug in an imported jme format serialized TerrainPage object.  When you first load the TerrainPage, everything looks good, but as soon as you try to modify the terrain heights, things break.  The crack-closing of adjacent TerrainBlock instances no longer works and you get a spikey mess in the modified block.  No combo of calling update methods seem to fix the problem.  My solution for this now is to just keep track of the underlying height map data, write that out along with the parameters needed to initialize the terrain page, and then use those loaded parameters during importing to recreate the TerrainPage, avoiding serializing the actual TerrainPage object alltogether.

Are you serializing or using the preferred binary importer/exporter method?

Sorry for late response.  I've been busy the last couple of days.  I'm using BinaryImporter/BinaryExporter

I had another related problem with this when I tried to import the exported scene into my game and implement terrain following.  I noticed that TerrainPage.getHeight(Vector3f) often returned float.NaN when I walked a short distance on my terrain.  When I used the same technique to create a new TerrainPage instance from the original height map data using the same constructor parameters, the problem went away.  So there is a problem somewhere in the jme import/export mechanism for TerrainPage.  I tried commenting out the export of the field "oldHeightMap" so that the geometry would be rebuilt on the call to TerrainPage.updateFromHeightMap().  This fixed the the float.NaN problem but the terrain became a huge mess of broken triangles like I mentioned in my previous post.  So there must be something that is not getting properly initialized during the read operation or some post read fix-up work has to be performed on the terrain mesh data.


Hmm, I don't see any reason for oldHeightMap to be saved out, so I think that should be removed anyhow.  If you could post a small SimpleGame test showing the error, I'd be happy to look at it.

Here is a test extending TestTerrainPage that shows the problem.  It uses jme 1.0.

package com.nma.engine.terrain;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import jmetest.terrain.TestTerrainPage;
import com.jme.image.Texture;
import com.jme.scene.Spatial;
import com.jme.scene.state.RenderState;
import com.jme.scene.state.TextureState;
import com.jme.system.JmeException;
import com.jme.util.export.binary.BinaryExporter;
import com.jme.util.export.binary.BinaryImporter;
import com.jmex.terrain.TerrainPage;

 * Test to show problems with displaying a loaded terrain and then trying to modify it.
 * Height query methods are fixed by not reading and writing "oldHeightMap" field in TerrainBlock.
 * Rendering artifacts remain.
 * @author Anubis
 * @version $Id:$
public class TerrainPageLoadTest extends TestTerrainPage

      * Entry point for the test,
      * @param args
     public static void main(String[] args) {
       TerrainPageLoadTest app = new TerrainPageLoadTest();

   /* (non-Javadoc)
    * @see com.jme.app.BaseSimpleGame#simpleInitGame()
   protected void simpleInitGame()
      display.setTitle("Terrain Page Load Test");
      TerrainPage page = (TerrainPage)rootNode.getChild("Terrain");
      int pageIndex = rootNode.getChildIndex(page);
      // set the textures to be stored in jme binary
      TextureState ts = (TextureState)rootNode.getRenderState(RenderState.RS_TEXTURE);
      for(int i = 0; i < ts.getNumberOfSetTextures(); ++i)
         Texture tex = ts.getTexture(i);
         if(tex != null) tex.setStoreTexture(true);
      // write out the terrain page to jme binary
      ByteArrayOutputStream bOut = new ByteArrayOutputStream(1024 * 1024);
      BinaryExporter exporter = BinaryExporter.getInstance();
         exporter.save(page, bOut);
      catch(IOException e)
         throw new JmeException("Unable to write terrain page",e);
      // now import it back in
      BinaryImporter importer = BinaryImporter.getInstance();
         page = (TerrainPage)importer.load(bOut.toByteArray());
      catch(IOException e)
         throw new JmeException("Unable to read terrain page",e);
      // now change an entry in the heightmap and update
      // Even if we don't do this, the loaded textures are still messed up
      // We don't even need to change a height map value for the artifacts to appear
      // just need to call updateFromHeightMap
      //page.setHeightMapValue(36, 36, 500);
      // reattach the page to scene graph
      Spatial s = rootNode.detachChildAt(pageIndex);
      if(!(s instanceof TerrainPage)) throw new AssertionError("Old page not detached!");
      rootNode.attachChildAt(page, pageIndex);
      rootNode.updateGeometricState(0.0f, true);

Anyone fix or know how to fix such a problem?

Running that test with jME 2.0 shows no problems here…