Custom Mesh Generator

Hello,

I am trying to write a game with a minecraft-like cube-based terrain (I see these are very popular now, sorry). I have looked at some other voxel projects like jme3-voxel, bloxel, and Cave3D. Will someone help me with my MeshMaker class. Excuse me if I seem hopelessly confused, I am really new to 3D programming, but I seem to be learning quick (jME 3 has helped immensely with that, thank you guys for creating and support a great free engine).



Here is the code in the class. Let me know if you see anything that is wrong with it. Nothing appears on the screen, but there are no compile-time errors. I also use the UnshadedArray material with TextureArrays.



[java]public class MeshMaker {

// Normals for each face

static final Vector3f NORMAL_UP = new Vector3f(0, 1, 0);

static final Vector3f NORMAL_DOWN = new Vector3f(0, -1, 0);

static final Vector3f NORMAL_RIGHT = new Vector3f(1, 0, 0);

static final Vector3f NORMAL_LEFT = new Vector3f(-1, 0, 0);

static final Vector3f NORMAL_FRONT = new Vector3f(0, 0, 1);

static final Vector3f NORMAL_BACK = new Vector3f(0, 0, -1);



// constants for each face using bitwise operators

private static final int FACE_NO = 0;

private static final int FACE_RIGHT = (int) Math.pow(2, 0);

private static final int FACE_LEFT = (int) Math.pow(2, 1);

private static final int FACE_UP = (int) Math.pow(2, 2);

private static final int FACE_DOWN = (int) Math.pow(2, 3);

private static final int FACE_FRONT = (int) Math.pow(2, 4);

private static final int FACE_BACK = (int) Math.pow(2, 5);



public static Mesh makeMesh(int[][][] blocks) {

Mesh mesh = new Mesh();

ArrayList<Vector3f> vert = new ArrayList<Vector3f>();

ArrayList<Vector3f> normals = new ArrayList<Vector3f>();

ArrayList<Vector3f> texcoords = new ArrayList<Vector3f>();

for (int x = 0; x < Chunk.SIZE_X; x++) {

for (int y = 0; y < Chunk.SIZE_Y; y++) {

for (int z = 0; z < Chunk.SIZE_Z; z++) {

if (blocks[x][y][z] == Blocks.AIR)

continue;

Vector3f v1 = new Vector3f(x, y, z + 1);

Vector3f v2 = new Vector3f(x + 1, y, z + 1);

Vector3f v3 = new Vector3f(x, y + 1, z + 1);

Vector3f v4 = new Vector3f(x + 1, y + 1, z + 1);

Vector3f v5 = new Vector3f(x, y, z);

Vector3f v6 = new Vector3f(x + 1, y, z);

Vector3f v7 = new Vector3f(x, y + 1, z);

Vector3f v8 = new Vector3f(x + 1, y + 1, z);



int faces = neededFaces(x, y, z, blocks);

if ((faces & FACE_FRONT) > 0) {

vert.add(v5);

vert.add(v6);

vert.add(v7);

vert.add(v8);

texcoords.add(new Vector3f(0,0,0));

texcoords.add(new Vector3f(1,0,0));

texcoords.add(new Vector3f(1,1,0));

texcoords.add(new Vector3f(0,1,0));

for (int i = 0; i < 4; i++)

normals.add(NORMAL_FRONT);

}

if ((faces & FACE_BACK) > 0) {

vert.add(v1);

vert.add(v2);

vert.add(v3);

vert.add(v4);

texcoords.add(new Vector3f(0,0,0));

texcoords.add(new Vector3f(1,0,0));

texcoords.add(new Vector3f(1,1,0));

texcoords.add(new Vector3f(0,1,0));

for (int i = 0; i < 4; i++)

normals.add(NORMAL_BACK);

}

if ((faces & FACE_RIGHT) > 0)

{

vert.add(v2);

vert.add(v4);

vert.add(v6);

vert.add(v8);

texcoords.add(new Vector3f(0,0,0));

texcoords.add(new Vector3f(1,0,0));

texcoords.add(new Vector3f(1,1,0));

texcoords.add(new Vector3f(0,1,0));

for (int i = 0; i < 4; i++)

normals.add(NORMAL_RIGHT);

}

if ((faces & FACE_LEFT) > 0)

{

vert.add(v1);

vert.add(v3);

vert.add(v5);

vert.add(v7);

texcoords.add(new Vector3f(0,0,0));

texcoords.add(new Vector3f(1,0,0));

texcoords.add(new Vector3f(1,1,0));

texcoords.add(new Vector3f(0,1,0));

for (int i = 0; i < 4; i++)

normals.add(NORMAL_LEFT);

}

if ((faces & FACE_UP) > 0)

{

vert.add(v3);

vert.add(v4);

vert.add(v7);

vert.add(v8);

texcoords.add(new Vector3f(0,0,0));

texcoords.add(new Vector3f(1,0,0));

texcoords.add(new Vector3f(1,1,0));

texcoords.add(new Vector3f(0,1,0));

for (int i = 0; i < 4; i++)

normals.add(NORMAL_UP);

}

if ((faces & FACE_DOWN) > 0)

{

vert.add(v1);

vert.add(v2);

vert.add(v5);

vert.add(v6);

texcoords.add(new Vector3f(0,0,0));

texcoords.add(new Vector3f(1,0,0));

texcoords.add(new Vector3f(1,1,0));

texcoords.add(new Vector3f(0,1,0));

for (int i = 0; i < 4; i++)

normals.add(NORMAL_DOWN);

}

}

}

}

mesh.setBuffer(Type.Position, 3, BufferUtils.createFloatBuffer(vert.toArray(new Vector3f[vert.size()])));

mesh.setBuffer(Type.TexCoord, 3, BufferUtils.createFloatBuffer(texcoords.toArray(new Vector3f[texcoords.size()])));

mesh.setBuffer(Type.Normal, 3, BufferUtils.createFloatBuffer(normals.toArray(new Vector3f[normals.size()])));

return mesh;

}



private static int neededFaces(int x, int y, int z, int[][][] b) {

int faces = FACE_NO;

//


if (x == 0 || isSeeThrough(x - 1, y, z, b)) {
faces |= FACE_LEFT;
}
if (x == Chunk.SIZE_X - 1 || isSeeThrough(x + 1, y, z, b)) {
faces |= FACE_RIGHT;
}
if (y == Chunk.SIZE_Y - 1 || isSeeThrough(x, y + 1, z, b)) {
faces |= FACE_UP;
}
if (y == 0 || isSeeThrough(x, y - 1, z, b)) {
faces |= FACE_DOWN;
}
if (z == Chunk.SIZE_Z - 1 || isSeeThrough(x, y, z + 1, b)) {
faces |= FACE_FRONT;
}
if (z == 0 || isSeeThrough(x, y, z - 1, b)) {
faces |= FACE_BACK;
}
return faces;
}

private static boolean isSeeThrough(int x, int y, int z, int[][][] b) {
return b[x][y][z] == Blocks.AIR;
}
}
[/java]

EDIT:
I forgot to mention the way I handle my data. In my Chunk class, I have a 3-dimmensional int array of all the blocks. For example, if the block at 0,0,0 (relative to the chunk) doesn't exist (is an AIR block), then blocks[0][0][0] will be equal to Blocks.AIR. (the Blocks class contains a list of constants for all the blocks).

You miss the indexing. This way you have vertices but the graphics card does not know what to do with it. The tutorial about custom meshes does explain that to you.

On top of that you should at least use GNU Trove’s TFloatList to increase performance much! Or maybe calculate the buffer size needed beforehand and create a good fitting buffer in the beginning.

@enum said:
You miss the indexing. This way you have vertices but the graphics card does not know what to do with it. The tutorial about custom meshes does explain that to you.
On top of that you should at least use GNU Trove's TFloatList to increase performance much! Or maybe calculate the buffer size needed beforehand and create a good fitting buffer in the beginning.


Fail. I knew I was forgetting something stupid. Thanks for pointing this out for me. I'll look into the TFloatList.

EDIT: also, if anyone is looking at my code, I forgot to put mesh.updateBound() at the bottom of the method. :evil: