Creating custom Mesh dynamically

I made a class that creates a natural looking random terrain using an algorithm.
The size of the map is as follows:
int DETAIL = 9;
int SIZE = (int)Math.pow(2, DETAIL) + 1; // SIZE is a power of 2, plus one

So, that class generates the heights array.
That is a float[] array.
When I want to get the height at a certain point on the ground, I convert the x and y map coords
to the heights array index as follows:

float h = heights[x + SIZE * y];

I have another class called Terrain which extends Mesh.
I use that class to get a custom mesh object.
Here is the code of that class:

package terrain;

import com.jme3.math.Vector3f;
import com.jme3.scene.Mesh;

public class Terrain extends Mesh {
    
    public Terrain() {
    
    }
    
    public void setHeights(float[] heights, int mapsize) {
    
        Vector3f[] vertices = new Vector3f[heights.length];
    
        for(int y = 0; y < mapsize; y++) {
            for(int x = 0; x < mapsize; x++) {
            
            int index = x + mapsize * y;
            vertices[index] = new Vector3f(x, y, heights[index]);
            }
        }
        
        // You should also set the indices manually when creating a custom Mesh.
        // And that is my problem.
        // I don't know how to determine the indexes of the triangles.
    }
}

I can simply set the vertices with a loop. But when you create a custom Mesh, you also have to set the indices of the triangles.
And that’s my problem. I don’t know how to set the indexes.

I followed this tutorial: http://wiki.jmonkeyengine.org/doku.php/jme3:advanced:custom_meshes
In the tutorial page “Connecting the Dots” is where I get stuck.

Which part is unclear?

You’ve created a big array of vertexes. Now you need to define what makes the triangles. What three vertexes make the first triangle? Those are the first three values in your index buffer.

I understand what the indexes are. But I can’t invent a way to set the indexes in a loop or something.
So I want to determine the indexes of the triangles when I have the heights array

Since your vertexes are in a grid then the math shouldn’t be too hard.

Iterate over the cells (y = 0; y < mapSize - 1) (x = 0; y < mapSize - 1)… then calculate the index of the base corner. Calculate the index of the other four corners. Add six indexes in the appropriate order.

I managed in getting the indexes at the right places.
Now I’m able to make my terrain visible, and so I did.
But, now I have another problem.
Here’s an image of the terrain: (top view)

Every time when I start the game and generate a terrain, there are some not-random heights like you see in the image. I always get an oblique line of low heights (the canyon) .
This is the tutorial I used: Realistic terrain in 130 lines
And the code of that tutorial: playfuljs-demos/index.html at gh-pages · hunterloftis/playfuljs-demos · GitHub

And here’s my own class that generates the terrain:

package terrain;

import com.jme3.asset.AssetManager;
import com.jme3.material.Material;
import com.jme3.scene.Geometry;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture.WrapMode;

public class TerrainGenerator {

	private static final int TERRAIN_WIDTH = 100;
	private static final int TERRAIN_HEIGHT = 100;
	private static final float DEFAULT_HEIGHT = 1.0f;
	private static final int DETAIL = 6;
	private static final int SIZE = (int) Math.pow(2, DETAIL) + 1;
	private static final int MAX = SIZE - 1;
	private static final float ROUGHNESS = 0.1f;
	private float[] heights;
	private AssetManager assetManager;
	
	public TerrainGenerator(AssetManager assetManager) {
		
		this.assetManager = assetManager;
	}
	
	public float get(int x, int y) {
		try {
			if (x < 0 || x > MAX || y < 0 || y > MAX) {
			return -1f;
			}

			return heights[x + SIZE * y];
		} catch (Exception ex) {

			System.out.println("Error! > " + ex.getMessage());
		}
		return 0;
	}

	public void set(int x, int y, float val) {
		
		heights[x + SIZE * y] = val;
	}

	public void initArray() {
		
		heights = new float[SIZE * SIZE];
		
		set(0, 0, MAX);
		set(MAX, 0, MAX / 2);
		set(MAX, MAX, 0);
		set(0, MAX, MAX / 2);
		
		System.out.println("Size of heights array: " + heights.length);
	}

	public void generateTerrain() {
		
		initArray();
		divide(MAX);
		
	}

	public void divide(float size) {
		
		System.out.println("d " + size);
		int x, y, half = (int) (size / 2);
		float scale = ROUGHNESS * size;
		
		if(half < 1f) {
			return;
		}
		
		for (y = half; y < MAX; y += size) {
			for (x = half; x < MAX; x += size) {

				float random = (float) Math.random();
				square(x, y, half, random * scale * 2 - scale);
			}
		}

		for (y = 0; y <= MAX; y += half) {
			for (x = (int) ((y + half) % size); x <= MAX; x += size) {

				float random = (float) Math.random();
				diamond(x, y, half, random * scale * 2 - scale);
			}
		}
		
		divide(size / 2); // Cycle
	}

	public float average(float[] values) {

		float[] valid = new float[values.length];

		// check valid values
		for (int i = 0; i < values.length; i++) {
			if (values[i] != -1.0f) {
				valid[i] = values[i];
			}
		}

		// calculate average
		float total = 0f;
		for (int n = 0; n < valid.length; n++) {
			total += valid[n];
		}

		return total / valid.length;
	}

	public void square(int x, int y, int size, float offset) {

		float ave = average(new float[]{
			get(x - size, y - size), // upper left
			get(x + size, y - size), // upper right
			get(x + size, y + size), // lower right
			get(x - size, y + size) // lower left
		});

		set(x, y, ave + offset);
	}

	public void diamond(int x, int y, int size, float offset) {

		float ave = average(new float[]{
			get(x, y - size), // top
			get(x + size, y), // right
			get(x, y + size), // bottom
			get(x - size, y) // left
		});

		set(x, y, ave + offset);
	}

	public void debug() {

		System.out.println("Open terrain debug window");

		JFrame frm = new JFrame("Terrain debug map");
		frm.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
		frm.setSize(TERRAIN_WIDTH * 10, TERRAIN_HEIGHT * 10);
		frm.setLocationRelativeTo(null);

		TerrainMapPanel panel = new TerrainMapPanel(heights, SIZE, MAX);
		frm.setLayout(new BorderLayout());
		frm.add(panel, BorderLayout.CENTER);
		frm.setVisible(true);

	}

	private Color getColor(int x, int y) {

		return Color.red;
	}
	
	/**
	* This method is only to get an object to render
	*/
	public Geometry getGeneratedTerrain() {

		Terrain terr = new Terrain();
		terr.setHeights(heights, MAX);

		Geometry geom = new Geometry("terrain", terr);

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

		mat_terrain.setTexture("Alpha", assetManager.loadTexture(
			"Textures/Terrain/splat/alphamap.png"));

		Texture grass = assetManager.loadTexture(
			"Textures/Terrain/splat/grass.png");
		grass.setWrap(WrapMode.Repeat);
		mat_terrain.setTexture("Tex1", grass);
		mat_terrain.setFloat("Tex1Scale", 64f);

		Texture dirt = assetManager.loadTexture(
			"Textures/Terrain/splat/dirt.png");
		dirt.setWrap(WrapMode.Repeat);
		mat_terrain.setTexture("Tex2", dirt);
		mat_terrain.setFloat("Tex2Scale", 32f);

		Texture rock = assetManager.loadTexture(
			"Textures/Terrain/splat/rocks.png");
		rock.setWrap(WrapMode.Repeat);
		mat_terrain.setTexture("Tex3", rock);
		mat_terrain.setFloat("Tex3Scale", 128f);
		
		geom.setMaterial(mat_terrain);
		
		geom.setLocalTranslation(-16f, -10f, 0);
		
		mat_terrain.getAdditionalRenderState().setWireframe(true);
		return geom;
	}
}

Anyone?

Generally, to debug something like this: make a smaller map and validate how each value is calculated.

At a quick glance, without actually knowing what’s going on… y += half looks odd when everything else seems to be += size.

Look at Control mesh vertecies position
there other techique Examples for use OpenCL in Java with LWGL