Heightmap

From JPCT
Revision as of 12:12, 30 November 2010 by Kaiidyn (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

A Heightmap class I wrote (more like edited Egon's random terrain)

Egon's Terrain script that randomly generates terrain heights.

/**
 * This is where the terrain-array is filled with some data, i.e. the
 * terrain is build. Keep in mind that this approach to build a terrain
 * is quite simple and slow. But it's easy to understand and the results
 * are not that bad, so....
 */
for (int x = 0; x < X_SIZE; x++) {
	for (int z = 0; z < Z_SIZE; z++) {
		terrain[x][z] = -20 + (float) Math.random() * 40f; // Very
		// simple....
	}
}

/**
 * We are now smoothing the terrain heights. This looks better because
 * it removes sharp edges from the terrain.
 */
for (int x = 0; x < X_SIZE - 1; x++) {
	for (int z = 0; z < Z_SIZE - 1; z++) {
		terrain[x][z] = (terrain[x][z] + terrain[x + 1][z] + terrain[x][z + 1] + terrain[x + 1][z + 1]) / 4;
	}
}

/**
 * The terrain heights are calculated now. Now we have to build an
 * Object3D from them.
 */
ground = new Object3D(X_SIZE * Z_SIZE * 2);

/**
 * We have 50 tiles in x and z direction and 2 polygons per tile.
 */
float xSizeF = (float) X_SIZE;
float zSizeF = (float) Z_SIZE;

int id = texMan.getTextureID("base");

for (int x = 0; x < X_SIZE - 1; x++) {
	for (int z = 0; z < Z_SIZE - 1; z++) {
		/**
		 * We are now taking the heights calculated above and build the
		 * actual triangles using this data. The terrain's grid is fixed
		 * in x and z direction and so are the texture coordinates. The
		 * only part that varies is the height, represented by the data
		 * in terrain[][]. jPCT automatically takes care of vertex
		 * sharing and mesh optimizations (this is why building objects
		 * this way isn't blazing fast...but it pays out in the
		 * end...:-)) The Mesh is build with triangle strips in mind
		 * here. The format for these strips is equal to that of
		 * OpenGL's triangle strips.
		 */

		TextureInfo ti = new TextureInfo(id, (x / xSizeF), (z / zSizeF), ((x + 1) / xSizeF), (z / zSizeF), (x / xSizeF), ((z + 1) / zSizeF));
		ground.addTriangle(new SimpleVector(x * 10, terrain[x][z], z * 10), new SimpleVector((x + 1) * 10, terrain[x + 1][z], z * 10),
				new SimpleVector(x * 10, terrain[x][z + 1], (z + 1) * 10), ti);

		ti = new TextureInfo(id, (x / xSizeF), ((z + 1) / zSizeF), ((x + 1) / xSizeF), (z / zSizeF), ((x + 1) / xSizeF), ((z + 1) / zSizeF));
		ground.addTriangle(new SimpleVector(x * 10, terrain[x][z + 1], (z + 1) * 10), new SimpleVector((x + 1) * 10, terrain[x + 1][z], z * 10), new SimpleVector((x + 1) * 10,
				terrain[x + 1][z + 1], (z + 1) * 10), ti);
	}
}


My terrain class that uses a bitmap.

When using it make sure you have a Texture Manager with a TextureID ready, (I used a flat gray 128x128 image for this)

public class Terrain {
	
	public static float HighestPoint = 0;
	
	
	static Bitmap bmp = null;
	static String pixel = null;
	public static Object3D Generate(int X_SIZE, int Z_SIZE, TextureManager tm, String TextureID){

		bmp = BitmapFactory.decodeResource(SpaceGrabber.resources, R.drawable.terrain); // the heightmap texture (128x128 due to memory limitations?)
		
		float[][] terrain = new float[X_SIZE][Z_SIZE];
		
		for (int x = 0; x < X_SIZE-1; x++) {
			for (int z = 0; z < Z_SIZE-1; z++) {
				
				pixel = Integer.toString(bmp.getPixel(x, z), 16);
				terrain[x][z] = Integer.parseInt(pixel.charAt(1) + "" + pixel.charAt(2), 16);
				
				if(terrain[x][z] > HighestPoint){
					HighestPoint = terrain[x][z];
				}
			}
			
		}
		for (int x = 0; x < X_SIZE - 1; x++) {
			for (int z = 0; z < Z_SIZE - 1; z++) {
				terrain[x][z] = (terrain[x][z] + terrain[x + 1][z] + terrain[x][z + 1] + terrain[x + 1][z + 1]) / 4;
			}
		}
		Object3D ground = new Object3D(X_SIZE * Z_SIZE * 2);
		
		float xSizeF = (float) X_SIZE;
		float zSizeF = (float) Z_SIZE;
		
		int id = tm.getTextureID(TextureID); // I used a gray 128x128 texture
		
		for (int x = 0; x < X_SIZE - 1; x++) {
			for (int z = 0; z < Z_SIZE - 1; z++) {
				
				TextureInfo ti = new TextureInfo(id, (x / xSizeF), (z / zSizeF), ((x + 1) / xSizeF), (z / zSizeF), (x / xSizeF), ((z + 1) / zSizeF));
				ground.addTriangle(new SimpleVector(x * 10, terrain[x][z], z * 10), new SimpleVector((x + 1) * 10, terrain[x + 1][z], z * 10),
						new SimpleVector(x * 10, terrain[x][z + 1], (z + 1) * 10), ti);

				ti = new TextureInfo(id, (x / xSizeF), ((z + 1) / zSizeF), ((x + 1) / xSizeF), (z / zSizeF), ((x + 1) / xSizeF), ((z + 1) / zSizeF));
				ground.addTriangle(new SimpleVector(x * 10, terrain[x][z + 1], (z + 1) * 10), new SimpleVector((x + 1) * 10, terrain[x + 1][z], z * 10), new SimpleVector((x + 1) * 10,
						terrain[x + 1][z + 1], (z + 1) * 10), ti);
			}
		}
		
		return ground;
	}
}

It might need some modification to work in your application, but it's something to start with :)