# Java Marching Cubes "Fun"

## Recommended Posts

Hey guys, I've been working on some marching cubes, and I've been having some weird issues that I really can't seem to understand. Basically the mesh isn't forming properly. Here are some screenshots and the code as it will show you the issue quicker than me describing it.

As you can see the cube kinda forms but some areas are messed up, Here is the relevant code.

package voxels;

import java.util.ArrayList;
import java.util.List;

import javax.swing.plaf.basic.BasicTreeUI.TreeCancelEditingAction;

import org.lwjgl.util.vector.Vector3f;
import models.MarchingCubesCases;
import toolbox.UniversalFunctions;

public class MeshGenerator {

private static int[][] vertexOffset = new int[][] { { 0, 0, 0 }, { 1, 0, 0 }, { 1, 1, 0 }, { 0, 1, 0 }, { 0, 0, 1 },
{ 1, 0, 1 }, { 1, 1, 1 }, { 0, 1, 1 } };
private static float target = 0.5f;

public static Voxel[][][] generateVoxels(int size) {
Voxel[][][] voxels = new Voxel[size][size][size];

for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
for (int k = 0; k < size; k++) {
voxels[i][j][k] = new Voxel(VoxelMaterial.Grass);
}
}
}

return voxels;
}

public static MeshData generateMeshMarchingCubes(Voxel[][][] voxels) {

List<Vector3f> verts = new ArrayList<Vector3f>();
List<Float> normals = new ArrayList<Float>();
List<Integer> indices = new ArrayList<Integer>();
List<Float> textureCoords = new ArrayList<Float>();

for (int x = 0; x < voxels.length; x++) {
for (int y = 0; y < voxels.length; y++) {
for (int z = 0; z < voxels.length; z++) {

if (voxels[x][y][z].getMaterial() == VoxelMaterial.Air) {
continue;
}

float[] cube = new float[8];

if (checkIfExpose(voxels, x, y, z, cube) == false) {
continue;
}

MarchCube(new Vector3f(x, y, z), cube, verts, indices);

}
}
}

MeshData data = new MeshData();
data.setIndices(UniversalFunctions.intListToArray(indices));
data.setVertsFromVector3f(verts);
data.setNormals(UniversalFunctions.floatListToArray(normals));
data.setTextureCoords(UniversalFunctions.floatListToArray(textureCoords));

return data;
}

private static boolean checkIfExpose(Voxel[][][] voxels, int x, int y, int z, float[] cube) {

Voxel[] surroundingVoxels = getSurroundingVoxels(voxels, x, y, z);
boolean bool = false;

for (int i = 0; i < cube.length; i++) {
cube[i] = 1;
}

if (surroundingVoxels[0].getMaterial().equals(VoxelMaterial.Air)) {

cube[0] = 0;
cube[1] = 0;
cube[4] = 0;
cube[5] = 0;
bool = true;

}

if (surroundingVoxels[1].getMaterial().equals(VoxelMaterial.Air)) {

cube[0] = 0;
cube[3] = 0;
cube[4] = 0;
cube[7] = 0;
bool = true;

}

if (surroundingVoxels[2].getMaterial().equals(VoxelMaterial.Air)) {

cube[4] = 0;
cube[5] = 0;
cube[6] = 0;
cube[7] = 0;
bool = true;

}

if (surroundingVoxels[3].getMaterial().equals(VoxelMaterial.Air)) {

cube[0] = 0;
cube[1] = 0;
cube[2] = 0;
cube[3] = 0;
bool = true;

}

if (surroundingVoxels[4].getMaterial().equals(VoxelMaterial.Air)) {

cube[1] = 0;
cube[2] = 0;
cube[5] = 0;
cube[6] = 0;
bool = true;

}

if (surroundingVoxels[5].getMaterial().equals(VoxelMaterial.Air)) {

cube[2] = 0;
cube[3] = 0;
cube[6] = 0;
cube[7] = 0;
bool = true;

}

return bool;
}

private static Voxel[] getSurroundingVoxels(Voxel[][][] voxels, int x, int y, int z) {

int maxLength = voxels.length;
List<Voxel> voxelList = new ArrayList<Voxel>();

if (y - 1 > 0 && y - 1 < maxLength) {
} else {
}

if (x - 1 > 0 && x - 1 < maxLength) {
} else {
}

if (z - 1 > 0 && z - 1 < maxLength) {
} else {
}

if (z + 1 > 0 && z + 1 < maxLength) {
} else {
}

if (x + 1 > 0 && x + 1 < maxLength) {
} else {
}

if (y + 1 > 0 && y + 1 < maxLength) {
} else {
}

return voxelList.toArray(new Voxel[voxelList.size()]);
}

// MarchCube performs the Marching Cubes algorithm on a single cube
private static void MarchCube(Vector3f pos, float[] cube, List<Vector3f> vertList, List<Integer> indexList) {
int i, j, vert, idx;
int flagIndex = 0;
float offset = 0.0f;

Vector3f[] edgeVertex = new Vector3f[12];

for (int inter = 0; inter < 12; inter++) {
edgeVertex[inter] = new Vector3f();
}

// Find which vertices are inside of the surface and which are outside
for (i = 0; i < 8; i++) {
if (cube[i] <= target) {
flagIndex |= 1 << i;
}
}

// Find which edges are intersected by the surface
int edgeFlags = MarchingCubesCases.cubeEdgeFlags[flagIndex];

// If the cube is entirely inside or outside of the surface, then there will be
// no intersections
if (edgeFlags == 0)
return;

// Find the point of intersection of the surface with each edge
for (i = 0; i < 12; i++) {

// if there is an intersection on this edge
if ((edgeFlags & (1 << i)) != 0) {
offset = GetOffset(cube[MarchingCubesCases.edgeConnection[i][0]],
cube[MarchingCubesCases.edgeConnection[i][1]]);

edgeVertex[i].x = pos.x + (vertexOffset[MarchingCubesCases.edgeConnection[i][0]][0]
+ offset * MarchingCubesCases.edgeDirection[i][0]);
edgeVertex[i].y = pos.y + (vertexOffset[MarchingCubesCases.edgeConnection[i][0]][1]
+ offset * MarchingCubesCases.edgeDirection[i][1]);
edgeVertex[i].z = pos.z + (vertexOffset[MarchingCubesCases.edgeConnection[i][0]][2]
+ offset * MarchingCubesCases.edgeDirection[i][2]);

}
}

// Save the triangles that were found. There can be up to five per cube
for (i = 0; i < 5; i++) {

if (MarchingCubesCases.triangleConnectionTable[flagIndex][3 * i] < 0) {
break;
}

idx = vertList.size();

for (j = 0; j < 3; j++) {
vert = MarchingCubesCases.triangleConnectionTable[flagIndex][3 * i + j];
}

}
}

// GetOffset finds the approximate point of intersection of the surface
// between two points with the values v1 and v2
private static float GetOffset(float v1, float v2) {
float delta = v2 - v1;
return (delta == 0.0f) ? 0.5f : (target - v1) / delta;
}
}

I can attach the look up tables if needed. The MeshData class is just a class to hold verts, indices, etc. The voxel data is generated using the generateVoxels method and it is for a size of 16. Finally the voxel material only maters if the material is air as then the voxel will need to be rendered. Any help would be amazing.

Thanks

Euan

Edited by thelordposeidon

##### Share on other sites

Your images are terrible quality, but it looks like you are not getting a manifold mesh out of your algorithm, so I expect you've got the cases wrong. Perhaps with larger, better lit images it would be clearer? While I'm not going to review your cases, I've recently posted a marching cubes tutorial, so you can look over my cases instead? I have unit tests for the case table, you could port that to see if your own table passes.

Otherwise, I'd start debugging your code. Marching Cubes is very easy to test a single cube in isolation, so I'd start with one you know to be wrong.

Edited by Boris The Brave
Extra text

##### Share on other sites

Thanks for the advice, I'll get some better quality images tomorrow for you, unfortunately I had to take them under some time pressure but tomorrow I shouldn't have that issue. I'll take a look at the tutorial and thanks for the unit tests, again I'll look at them tomorrow.

##### Share on other sites

Can you link to a pasteboard of the tables. I'm not sure why your marching cubes uses a windingOrder table (unless your culling direction is the wrong way)?

##### Share on other sites

Here's the pastebin : here, and the pictures will go up later. I added it because I was having some issues I think with direction culling and it seemed to help. This was awhile ago so I can't quite remember what I was doing.

##### Share on other sites

Well, your tables look like standard marching cubes tables, so you can probably rule out issues there.

##### Share on other sites
28 minutes ago, swiftcoder said:

Well, your tables look like standard marching cubes tables, so you can probably rule out issues there.

Yeah, I'm pretty sure it's me making a silly mistake or a mistake in logic

##### Share on other sites

So i took some more pictures and did some debugging. First and foremost here are some better pictures of the cube at the original size (16 x 16 x 16 in opengl world coords). I uploaded it to imgur here.

Next I tried some debuging. No cube shows when I have the grid size as 1 x 1 x 1. When it is 2 x 2 x 2 I get a small triangle (pic here) and finally when I do 4 x 4 x 4 I get this load of weirdness. Obviously my logic has gone wrong but honestly I have no idea where.

Any ideas would be amazing.

##### Share on other sites

It looks like your corner ordering is just incorrect. I'd try and validate the direction of each corner against a known-working marching cubes algorithm.

##### Share on other sites

Do you know of any off the top of your head that is similar enough that I can compare it easily?

Edit : So I found that good old scrawk's code is similar to mine (though in c# and using unity). So the plan is to try and use that as a debug tool as that is definitely confirmed working. See where the difference in logic and code is. If I find anything I'll post it here, if there's nothing feel free to offer suggestions on what's wrong in the code as I've probably not solved it.

Edited by thelordposeidon
uodate

## Create an account

Register a new account

• ### What is your GameDev Story?

In 2019 we are celebrating 20 years of GameDev.net! Share your GameDev Story with us.

• 15
• 14
• 46
• 22
• 27
• ### Forum Statistics

• Total Topics
634051
• Total Posts
3015254
×