private void createTerrain() {
    // First, we load up our textures and the heightmap texture for the terrain

    // TERRAIN TEXTURE material
    matTerrain = new Material(assetManager, "Common/MatDefs/Terrain/TerrainLighting.j3md");
    matTerrain.setBoolean("useTriPlanarMapping", false);
    matTerrain.setBoolean("WardIso", true);
    matTerrain.setFloat("Shininess", 0);

    // ALPHA map (for splat textures)
    matTerrain.setTexture(
        "AlphaMap", assetManager.loadTexture("Textures/Terrain/splat/alphamap.png"));

    // GRASS texture
    Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg");
    grass.setWrap(WrapMode.Repeat);
    matTerrain.setTexture("DiffuseMap", grass);
    matTerrain.setFloat("DiffuseMap_0_scale", grassScale);

    // DIRT texture
    Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg");
    dirt.setWrap(WrapMode.Repeat);
    matTerrain.setTexture("DiffuseMap_1", dirt);
    matTerrain.setFloat("DiffuseMap_1_scale", dirtScale);

    // ROCK texture
    Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg");
    rock.setWrap(WrapMode.Repeat);
    matTerrain.setTexture("DiffuseMap_2", rock);
    matTerrain.setFloat("DiffuseMap_2_scale", rockScale);

    // HEIGHTMAP image (for the terrain heightmap)
    Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png");
    AbstractHeightMap heightmap = null;
    try {
      heightmap = new ImageBasedHeightMap(heightMapImage.getImage(), 0.5f);
      heightmap.load();
      heightmap.smooth(0.9f, 1);

    } catch (Exception e) {
      e.printStackTrace();
    }

    // CREATE THE TERRAIN
    terrain = new TerrainQuad("terrain", 65, 513, heightmap.getHeightMap());
    TerrainLodControl control = new TerrainLodControl(terrain, getCamera());
    control.setLodCalculator(new DistanceLodCalculator(65, 2.7f)); // patch size, and a multiplier
    terrain.addControl(control);
    terrain.setMaterial(matTerrain);
    terrain.setLocalTranslation(0, -100, 0);
    terrain.setLocalScale(2.5f, 0.5f, 2.5f);
    rootNode.attachChild(terrain);
  }
 public Control cloneForSpatial(Spatial spatial) {
   if (spatial instanceof Terrain) {
     List<Camera> cameraClone = new ArrayList<Camera>();
     if (cameras != null) {
       for (Camera c : cameras) {
         cameraClone.add(c);
       }
     }
     TerrainLodControl cloned = new TerrainLodControl((Terrain) spatial, cameraClone);
     cloned.setLodCalculator(lodCalculator.clone());
     return cloned;
   }
   return null;
 }
  @Override
  public void simpleInitApp() {
    File file = new File("TerrainGridTestData.zip");
    if (!file.exists()) {
      assetManager.registerLocator(
          "http://jmonkeyengine.googlecode.com/files/TerrainGridTestData.zip",
          HttpZipLocator.class);
    } else {
      assetManager.registerLocator("TerrainGridTestData.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 :)
    // 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);
    // quad.getHeightMap(), terrain.getLocalScale()), 0
    AssetTileLoader grid = new AssetTileLoader(assetManager, "testgrid", "TerrainGrid");
    this.terrain = new TerrainGrid("terrain", 65, 257, grid);

    this.terrain.setMaterial(this.mat_terrain);
    this.terrain.setLocalTranslation(0, 0, 0);
    this.terrain.setLocalScale(2f, 1f, 2f);
    //        try {
    //            BinaryExporter.getInstance().save(terrain, new
    // File("/Users/normenhansen/Documents/Code/jme3/engine/src/test-data/TerrainGrid/"
    //                    + "TerrainGrid.j3o"));
    //        } catch (IOException ex) {
    //            Logger.getLogger(TerrainFractalGridTest.class.getName()).log(Level.SEVERE, null,
    // ex);
    //        }

    this.rootNode.attachChild(this.terrain);

    TerrainLodControl control = new TerrainGridLodControl(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().updateLocation(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.getCamera().getLocation().x, 256, cam.getCamera().getLocation().z));

      bulletAppState.getPhysicsSpace().add(player3);

      terrain.addListener(
          new TerrainGridListener() {

            public void gridMoved(Vector3f newCenter) {}

            public void tileAttached(Vector3f cell, TerrainQuad quad) {
              while (quad.getControl(RigidBodyControl.class) != null) {
                quad.removeControl(RigidBodyControl.class);
              }
              quad.addControl(
                  new RigidBodyControl(
                      new HeightfieldCollisionShape(quad.getHeightMap(), terrain.getLocalScale()),
                      0));
              bulletAppState.getPhysicsSpace().add(quad);
            }

            public void tileDetached(Vector3f cell, TerrainQuad quad) {
              if (quad.getControl(RigidBodyControl.class) != null) {
                bulletAppState.getPhysicsSpace().remove(quad);
                quad.removeControl(RigidBodyControl.class);
              }
            }
          });
    }

    this.initKeys();
  }