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).