I am writing custom voxel engine in Java with JME3, but it is very slow, for simplicity I am rendering cubes instead of faces, also border detection messes up output mesh (doesn't draw cubes on chunk edges).

I would be very thankful if someone with more skill looked into it.

I have included all the code so you won't miss anything.
You could have a look at `CubicalMeshificator` and improve on it, lets say by making only necessary faces not whole cubes.

You can find rest of the code here:
<http://pastebin.com/7S90L1Bd>

`CubicalMeshificator` (extracts mesh from voxel data)

```
public class CubicalMeshificator {
    private static LinkedList<Vector3f> verticesPosition = new LinkedList<Vector3f>();
    private static LinkedList<Vector3f> verticesNormal = new LinkedList<Vector3f>();
    private static LinkedList<Vector2f> verticesUV = new LinkedList<Vector2f>();
    private static LinkedList<Integer> indices = new LinkedList<Integer>();

    public static Mesh createMesh(Voxel [][][] voxels, Vector3f size, float voxelSize) {
        for(int x = 0; x < size.x; x++) {
            for(int y = 0; y < size.y; y++) {
                for(int z = 0; z < size.z; z++) {
                    if(x-1 >= 0 && x+1 < size.x &&
                       y-1 >= 0 && y+1 < size.y &&
                       z-1 >= 0 && z+1 < size.z)
                    if(voxels[x][y][z].getId() != EVoxel.Air &&
                        (voxels[x+1][y][z].getId() == EVoxel.Air ||
                        voxels[x-1][y][z].getId() == EVoxel.Air ||
                        voxels[x][y][z+1].getId() == EVoxel.Air ||
                        voxels[x][y][z-1].getId() == EVoxel.Air ||
                        voxels[x][y+1][z].getId() == EVoxel.Air ||
                        voxels[x][y-1][z].getId() == EVoxel.Air) ) {
                        verticesPosition.add(new Vector3f(x*voxelSize, y*voxelSize, z*voxelSize));
                        verticesPosition.add(new Vector3f(x*voxelSize+voxelSize, y*voxelSize, z*voxelSize));
                        verticesPosition.add(new Vector3f(x*voxelSize, y*voxelSize+voxelSize, z*voxelSize));
                        verticesPosition.add(new Vector3f(x*voxelSize+voxelSize, y*voxelSize+voxelSize, z*voxelSize));
                        verticesPosition.add(new Vector3f(x*voxelSize, y*voxelSize, z*voxelSize+voxelSize));
                        verticesPosition.add(new Vector3f(x*voxelSize+voxelSize, y*voxelSize, z*voxelSize+voxelSize));
                        verticesPosition.add(new Vector3f(x*voxelSize, y*voxelSize+voxelSize, z*voxelSize+voxelSize));
                        verticesPosition.add(new Vector3f(x*voxelSize+voxelSize, y*voxelSize+voxelSize, z*voxelSize+voxelSize));

                       indices.add(verticesPosition.size() + 3);
                       indices.add(verticesPosition.size() + 1);
                       indices.add(verticesPosition.size() + 0);
                       indices.add(verticesPosition.size() + 0);
                       indices.add(verticesPosition.size() + 2);
                       indices.add(verticesPosition.size() + 3);

                       indices.add(verticesPosition.size() + 7);
                       indices.add(verticesPosition.size() + 5);
                       indices.add(verticesPosition.size() + 1);
                       indices.add(verticesPosition.size() + 1);
                       indices.add(verticesPosition.size() + 3);
                       indices.add(verticesPosition.size() + 7);

                       indices.add(verticesPosition.size() + 6);
                       indices.add(verticesPosition.size() + 4);
                       indices.add(verticesPosition.size() + 5);
                       indices.add(verticesPosition.size() + 5);
                       indices.add(verticesPosition.size() + 7);
                       indices.add(verticesPosition.size() + 6);

                       indices.add(verticesPosition.size() + 2);
                       indices.add(verticesPosition.size() + 0);
                       indices.add(verticesPosition.size() + 4);
                       indices.add(verticesPosition.size() + 4);
                       indices.add(verticesPosition.size() + 6);
                       indices.add(verticesPosition.size() + 2);

                       indices.add(verticesPosition.size() + 7);
                       indices.add(verticesPosition.size() + 3);
                       indices.add(verticesPosition.size() + 2);
                       indices.add(verticesPosition.size() + 2);
                       indices.add(verticesPosition.size() + 6);
                       indices.add(verticesPosition.size() + 7);

                       indices.add(verticesPosition.size() + 1);
                       indices.add(verticesPosition.size() + 5);
                       indices.add(verticesPosition.size() + 4);
                       indices.add(verticesPosition.size() + 4);
                       indices.add(verticesPosition.size() + 0);
                       indices.add(verticesPosition.size() + 1);
                    }
                }
            }
        }

        Mesh mesh = new Mesh();
        mesh.setBuffer(VertexBuffer.Type.Position, 3, BufferUtils.createFloatBuffer(verticesPosition.toArray(new Vector3f[0])));
        mesh.setBuffer(VertexBuffer.Type.Normal, 3, BufferUtils.createFloatBuffer(verticesNormal.toArray(new Vector3f[0])));
        mesh.setBuffer(VertexBuffer.Type.TexCoord, 2, BufferUtils.createFloatBuffer(verticesUV.toArray(new Vector2f[0])));
        mesh.setBuffer(VertexBuffer.Type.Index, 3, listToBuffer(indices));
        mesh.scaleTextureCoordinates(new Vector2f(5, 5));
        mesh.updateBound();

        return mesh;
    }

    public static IntBuffer listToBuffer(List<Integer> list)
    {
        IntBuffer buff = BufferUtils.createIntBuffer(list.size());
        buff.clear();
        for (Integer e : list) {
            buff.put(e.intValue());
        }
        buff.flip();
        return buff;
    }
}

```