I worte a small Class to handle custom Mesh for my own project. You can generate mesh based on Vector3f grid. If you can grab gray information of a pictrue, you can generate terrain meshs.
This is the gray scale map
This is the texture
This is the final scene
There are two parts of the codes.
This is the scene class, in which I grab the gray information form the gray scale map and setup the scene.
import com.jme3.app.SimpleApplication;
import com.jme3.asset.TextureKey;
import com.jme3.material.Material;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.texture.Texture;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import javax.imageio.ImageIO;
/**
* @author double1984
*/
public class Terrain extends SimpleApplication {
private int[] pixelSamples;
private int[][] pixelSample;
private float tileLength = 0.1f;
public static void main(String[] args) {
Terrain te = new Terrain();
te.start();
}
@Override
public void simpleInitApp() {
//read the gray scale map
URL url = Terrain.class.getClassLoader().getResource("pathWalker/land.jpg");
URI uri = null;
try {
uri = url.toURI();
} catch (URISyntaxException ex) {
}
File file = new File(uri);
BufferedImage bimage = null;
try {
bimage = ImageIO.read(file);
} catch (IOException ex) {
}
int w = bimage.getWidth();
int h = bimage.getHeight();
//set the cam
cam.setLocation(new Vector3f(w * tileLength / 2, w * tileLength / 2, h * tileLength));
cam.lookAt(new Vector3f(w * tileLength / 2, 0, h * tileLength / 2), Vector3f.UNIT_Y);
flyCam.setMoveSpeed(5);
//get the gray samples
pixelSamples = new int[h * w];
pixelSample = new int[h][w];
bimage.getRaster().getSamples(0, 0, w, h, 0, pixelSamples);
int count = 0;
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
pixelSample[i][j] = pixelSamples[count];
count++;
}
}
//generate vectors based on the gray information
Vector3f[][] vertex = new Vector3f[h][w];
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
vertex[i][j] = new Vector3f(j * tileLength, pixelSample[i][j] / 50f, i * tileLength);
}
}
//pass the vectors to the MultMesh object
MultMesh mm = new MultMesh(vertex);
mm.initMesh();
//setup material
Material mat2 = new Material(assetManager, "Common/MatDefs/Misc/SimpleTextured.j3md");
TextureKey key2 = new TextureKey("pathWalker/land2.jpg");
key2.setGenerateMips(true);
Texture tex2 = assetManager.loadTexture(key2);
mat2.setTexture("m_ColorMap", tex2);
//generate grometry
Geometry mmG = new Geometry("mesh", mm);
mmG.setMaterial(mat2);
mmG.updateModelBound();
mmG.updateGeometricState();
rootNode.attachChild(mmG);
}
}
This is the MultMesh Class which can generate mesh from a grid of Vector3f.
import com.jme3.math.Vector3f;
import com.jme3.scene.Mesh;
import com.jme3.scene.VertexBuffer.Type;
/**
*
* @author double1984
*/
public class MultMesh extends Mesh {
//x,z方向的单元数量
private int xUnit, zUnit;
//x, z方向上的顶点数量
private int xUp, zUp;
//顶点数组
private Vector3f[][] vertex;
public MultMesh(Vector3f[][] pts) {
vertex = pts;
zUnit = pts.length - 1;
xUnit = pts[0].length - 1;
zUp = pts.length;
xUp = pts[0].length;
}
//初始化多面
public void initMesh() {
this.setMode(Mode.Triangles);
//储存所有顶点的坐标
float[] positions = new float[xUp * zUp * 3];
int count = 0;
for (int i = 0; i < zUp; i++) {
for (int j = 0; j < xUp; j++) {
positions[count] = vertex[i][j].x;
count++;
positions[count] = vertex[i][j].y;
count++;
positions[count] = vertex[i][j].z;
count++;
}
}
this.setBuffer(Type.Position, 3, positions);
//储存所有顶点的次序
count = 0;
int[] indexs = new int[xUnit * zUnit * 6];
for (int i = 0; i < zUnit; i++) {
for (int j = 0; j < xUnit; j++) {
indexs[count] = i * xUp + j;
count++;
indexs[count] = i * xUp + xUp + j;
count++;
indexs[count] = i * xUp + xUp + j + 1;
count++;
indexs[count] = i * xUp + j;
count++;
indexs[count] = i * xUp + xUp + j + 1;
count++;
indexs[count] = i * xUp + j + 1;
count++;
}
}
this.setBuffer(Type.Index, 3, indexs);
//储存所有的贴图坐标
count = 0;
boolean xShift = true;
boolean zShift = true;
int texCoodSize = (xUnit + 1) * (zUnit + 1) * 2;
float[] texCood = new float[texCoodSize];
float xstep = 1f / (xUp - 1);
float zstep = 1f / (zUp - 1);
for (int i = 0; i < zUp; i++) {
for (int j = 0; j < xUp; j++) {
texCood[count] =j * xstep;
count++;
texCood[count] = 1-i * zstep;
count++;
}
}
this.setBuffer(Type.TexCoord, 2, texCood);
//所有顶点的颜色
count = 0;
float[] vertexColors = new float[xUp * zUp * 4];
for (int i = 0; i < xUp * zUp; i++) {
vertexColors[count] = (float) Math.random();
count++;
vertexColors[count] = (float) Math.random();
count++;
vertexColors[count] = (float) Math.random();
count++;
vertexColors[count] = (float) Math.random();
count++;
}
this.setBuffer(Type.Color, 4, vertexColors);
}
public Vector3f[][] getVertex() {
return this.vertex;
}
}