ok so, i’ve been working on a voxel project for a while now (with slopes) and i’ve been stuck on this problem for about a week or more and just can’t push past it and was hoping that you guys would be able to give me some insight.
I’m storing the information of each of the voxels (vertex data, indices etc) inside each “BlockData” class when I create the mesh and whenever a block is removed it sets a variable in all of the adjacent blocks to say “needsUpdate” this then re-checks which faces are visible and re-builds the mesh from the data in each of the “BlockData” classes within a 3d array.
if I comment out the part of my code which only re-builds the vertex data within each of the blocks when they need to be updated and make all blocks re-create it every time a block is destroyed everything works perfectly with no stretching… however otherwise I get stretching across the entire chunk of blocks. Below is the chunk code. Also if anyone would like a full copy of the project, just ask and i’ll try to get an uploaded version.
[java]/*
- To change this template, choose Tools | Templates
- and open the template in the editor.
*/
package mygame;
import com.jme3.material.Material;
import com.jme3.math.FastMath;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.math.Vector4f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.VertexBuffer.Type;
import com.jme3.scene.control.AbstractControl;
import com.jme3.scene.control.Control;
import com.jme3.util.BufferUtils;
import java.util.ArrayList;
/**
*
-
@author Azura
/
public class ChunkManager extends AbstractControl
{
private static final float BLOCK_SIZE = 1f;
private static final float HALF_BLOCK_SIZE = .5f;
private static final int FACE_DOWN = 0, FACE_UP = 1, FACE_LEFT = 2, FACE_RIGHT = 3, FACE_FRONT = 4, FACE_BACK = 5;
private static final Vector3f NORMAL_DOWN = new Vector3f(0, -1, 0);
private static final Vector3f NORMAL_UP = new Vector3f(0, 1, 0);
private static final Vector3f NORMAL_LEFT = new Vector3f(-1, 0, 0);
private static final Vector3f NORMAL_RIGHT = new Vector3f(1, 0, 0);
private static final Vector3f NORMAL_FRONT = new Vector3f(0, 0, 1);
private static final Vector3f NORMAL_BACK = new Vector3f(0, 0, -1);
private static final Vector2f TEX_COORD_0 = new Vector2f(0.0f,0f);
private static final Vector2f TEX_COORD_1 = new Vector2f(1,0f);
private static final Vector2f TEX_COORD_2 = new Vector2f(0.0f,1f);
private static final Vector2f TEX_COORD_3 = new Vector2f(1f,1f);
private static final Vector2f TEX_COORD_4 = new Vector2f(.5f,.5f);
private ArrayList<Vector3f> vertices = new ArrayList<Vector3f>(); // points
private ArrayList<Vector3f> normals = new ArrayList<Vector3f>(); // normals
private ArrayList<Vector2f> texCoord = new ArrayList<Vector2f>(); // tex cords
private ArrayList<Integer> indexes = new ArrayList<Integer>(); // indexes
private ArrayList<Vector4f> verticesColor = new ArrayList<Vector4f>(); // Colors
private float updateCounter = 0;
private Material matTilesheet;
private BlockData[][][] blockMap;
private int[][] heightMap;
private Vector3f size;
private Node parentNode;
public ChunkManager(Material matTilesheet, BlockData[][][] blockMap, int[][] heightMap, Vector3f size, Node parentNode)
{
this.matTilesheet = matTilesheet;
this.blockMap = blockMap;
this.heightMap = heightMap;
this.size = size;
this.parentNode = parentNode;
//areaMesh.setDynamic();
buildChunk();
}
@Override
protected void controlUpdate(float tpf)
{
updateCounter += tpf;
if(updateCounter > 5.5f)
{
updateCounter -= 5.5f;
removeBlock();
buildChunk();
//System.out.println("hm.");
}
//throw new UnsupportedOperationException("Not supported yet.");
}
private void removeBlock()
{
int x = FastMath.nextRandomInt(1,(int)size.x-2);
int y = FastMath.nextRandomInt(1,(int)size.y-2);
int z = FastMath.nextRandomInt(1,(int)size.z-2);
if(blockMap[x][y][z] != null)
{
blockMap[x][y][z] = null;
if(blockMap[x-1][y][z] != null){blockMap[x-1][y][z].setNeedsUpdate(true);}
if(blockMap[x+1][y][z] != null){blockMap[x+1][y][z].setNeedsUpdate(true);}
if(blockMap[x][y-1][z] != null){blockMap[x][y-1][z].setNeedsUpdate(true);}
if(blockMap[x][y+1][z] != null){blockMap[x][y+1][z].setNeedsUpdate(true);}
if(blockMap[x][y][z-1] != null){blockMap[x][y][z-1].setNeedsUpdate(true);}
if(blockMap[x][y][z+1] != null){blockMap[x][y][z+1].setNeedsUpdate(true);}
}
}
private void buildChunk()
{
boolean updateMesh = false;
vertices.clear();
normals.clear();
texCoord.clear();
indexes.clear();
verticesColor.clear();
if(vertices.size() > 0 || normals.size() > 0 || texCoord.size() > 0 || verticesColor.size() > 0)
{
System.out.println("YOU FUCKER!");
}
for(int x = 1; x < size.x-1; x++)
{
for(int y = 1; y < size.y-1; y++)
{
for(int z = 1; z < size.z-1; z++)
{
if(blockMap[x][y][z] != null)
{
if(blockMap[x][y][z].isNeedsUpdate())
{
checkDownVerts(x,y,z);
}
}
}
}
}
for(int x = 1; x < size.x-1; x++)
{
for(int y = 1; y < size.y-1; y++)
{
for(int z = 1; z < size.z-1; z++)
{
if(blockMap[x][y][z] != null)
{
if(blockMap[x][y][z].isNeedsUpdate())
{
/blockMap[x][y][z].getVertices().clear();
blockMap[x][y][z].getVertices().clear();
blockMap[x][y][z].getNormals().clear();
blockMap[x][y][z].getTexCoord().clear();
blockMap[x][y][z].getIndexes().clear();
blockMap[x][y][z].getVerticesColor().clear();/
checkFaces(x,y,z);
ArrayList<Vector3f> tempVerts = new ArrayList<Vector3f>();
tempVerts.addAll(blockMap[x][y][z].getVertices()); // points
if(tempVerts.equals(blockMap[x][y][z].getVertices()))
{
}
else
{
System.out.println("FUCK YOU!");
}
if(blockMap[x][y][z].getNumOfFaces() > 0)
{
createBlock(x,y,z);
}
blockMap[x][y][z].setNeedsUpdate(false);
}
vertices.addAll(blockMap[x][y][z].getVertices());
normals.addAll(blockMap[x][y][z].getNormals());
texCoord.addAll(blockMap[x][y][z].getTexCoord());
indexes.addAll(blockMap[x][y][z].getIndexes());
verticesColor.addAll(blockMap[x][y][z].getVerticesColor());
updateMesh = true;
}
}
}
}
//if(updateMesh)
{
Vector4f[] c4 = verticesColor.toArray(new Vector4f[verticesColor.size()]);
int colorIndex = 0;
float[] colorArray = new float[verticesColor.size()4];
//Set custom RGBA value for each Vertex. Values range from 0.0f to 1.0f
for(int i = 0; i < verticesColor.size(); i++)
{
// Red value (is increased by .2 on each next vertex here)
colorArray[colorIndex++]= c4.x; //0.1f+(.2fi);
// Green value (is reduced by .2 on each next vertex)
colorArray[colorIndex++]= c4.y; //0.9f-(0.2fi);
// Blue value (remains the same in our case)
colorArray[colorIndex++]= c4.z;
// Alpha value (no transparency set here)
colorArray[colorIndex++]= c4.w;
}
Vector3f[] v3 = vertices.toArray(new Vector3f[vertices.size()]);
Vector3f[] n3 = normals.toArray(new Vector3f[normals.size()]);
Vector2f[] v2 = texCoord.toArray(new Vector2f[texCoord.size()]);
int[] indx = convertIntegers(indexes);
Mesh areaMesh = new Mesh();
areaMesh = new Mesh();
areaMesh.setBuffer(Type.Position, 3, BufferUtils.createFloatBuffer(v3));
areaMesh.setBuffer(Type.Normal, 3, BufferUtils.createFloatBuffer(n3));
areaMesh.setBuffer(Type.TexCoord, 2, BufferUtils.createFloatBuffer(v2));
areaMesh.setBuffer(Type.Index, 1, BufferUtils.createIntBuffer(indx));
areaMesh.setBuffer(Type.Color, 4, colorArray);
areaMesh.updateBound();
parentNode.detachChildNamed("islandMesh");
// Creating a geometry, and apply a single color material to it
Geometry levelGeom = new Geometry("islandMesh", areaMesh);
levelGeom.setMaterial(matTilesheet);
parentNode.attachChild(levelGeom);
}
}
private void createBlock(int x, int y, int z)
{
float bx, by, bz;
int verticesSize;
ArrayList<Vector3f> blockVerts = new ArrayList<Vector3f>(); // points
ArrayList<Vector3f> blockNorms = new ArrayList<Vector3f>(); // normals
ArrayList<Vector2f> blockTexCoords = new ArrayList<Vector2f>(); // tex cords
ArrayList<Integer> blockIndexes = new ArrayList<Integer>(); // indexes
ArrayList<Vector4f> blockVertsColors = new ArrayList<Vector4f>(); // Colors
bx = blockMap[x][y][z].getX();
by = blockMap[x][y][z].getY();
bz = blockMap[x][y][z].getZ();
Vector3f pa = new Vector3f(bx-HALF_BLOCK_SIZE, by-HALF_BLOCK_SIZE, bz+HALF_BLOCK_SIZE);
Vector3f pb = new Vector3f(bx+HALF_BLOCK_SIZE, by-HALF_BLOCK_SIZE, bz+HALF_BLOCK_SIZE);
Vector3f pc;
if(blockMap[x][y][z].getDownVert(0))
{
pc = new Vector3f(bx-HALF_BLOCK_SIZE, by-HALF_BLOCK_SIZE, bz+HALF_BLOCK_SIZE);
}
else
{
pc = new Vector3f(bx-HALF_BLOCK_SIZE, by+HALF_BLOCK_SIZE, bz+HALF_BLOCK_SIZE);
}
Vector3f pd;
if(blockMap[x][y][z].getDownVert(1))
{
pd = new Vector3f(bx+HALF_BLOCK_SIZE, by-HALF_BLOCK_SIZE, bz+HALF_BLOCK_SIZE);
}
else
{
pd = new Vector3f(bx+HALF_BLOCK_SIZE, by+HALF_BLOCK_SIZE, bz+HALF_BLOCK_SIZE);
}
Vector3f pe = new Vector3f(bx-HALF_BLOCK_SIZE, by-HALF_BLOCK_SIZE, bz-HALF_BLOCK_SIZE);
Vector3f pf = new Vector3f(bx+HALF_BLOCK_SIZE, by-HALF_BLOCK_SIZE, bz-HALF_BLOCK_SIZE);
Vector3f pg;
if(blockMap[x][y][z].getDownVert(2))
{
pg = new Vector3f(bx-HALF_BLOCK_SIZE, by-HALF_BLOCK_SIZE, bz-HALF_BLOCK_SIZE);
}
else
{
pg = new Vector3f(bx-HALF_BLOCK_SIZE, by+HALF_BLOCK_SIZE, bz-HALF_BLOCK_SIZE);
}
Vector3f ph;
if(blockMap[x][y][z].getDownVert(3))
{
ph = new Vector3f(bx+HALF_BLOCK_SIZE, by-HALF_BLOCK_SIZE, bz-HALF_BLOCK_SIZE);
}
else
{
ph = new Vector3f(bx+HALF_BLOCK_SIZE, by+HALF_BLOCK_SIZE, bz-HALF_BLOCK_SIZE);
}
Vector3f ps;
if(blockMap[x][y][z].getDownCount() == 2 || blockMap[x][y][z].getDownCount() == 4)
{
ps = new Vector3f(bx, by, bz);
}
else if(blockMap[x][y][z].getDownCount() == 3)
{
ps = new Vector3f(bx, by-HALF_BLOCK_SIZE, bz);
}
else
{
ps = new Vector3f(bx, by+HALF_BLOCK_SIZE, bz);
}
//y = -
if(blockMap[x][y][z].getFace(FACE_UP) == true)
{
verticesSize = blockVerts.size() + vertices.size();
blockVerts.add(pc);
blockVerts.add(pd);
blockVerts.add(pg);
blockVerts.add(ph);
blockVerts.add(ps);
blockNorms.add(NORMAL_UP);
blockNorms.add(NORMAL_UP);
blockNorms.add(NORMAL_UP);
blockNorms.add(NORMAL_UP);
blockNorms.add(NORMAL_UP);
blockTexCoords.add(TEX_COORD_0);
blockTexCoords.add(TEX_COORD_1);
blockTexCoords.add(TEX_COORD_2);
blockTexCoords.add(TEX_COORD_3);
blockTexCoords.add(TEX_COORD_4);
blockIndexes.add(verticesSize+2);
blockIndexes.add(verticesSize+0);
blockIndexes.add(verticesSize+4);
blockIndexes.add(verticesSize+4);
blockIndexes.add(verticesSize+0);
blockIndexes.add(verticesSize+1);
blockIndexes.add(verticesSize+1);
blockIndexes.add(verticesSize+3);
blockIndexes.add(verticesSize+4);
blockIndexes.add(verticesSize+4);
blockIndexes.add(verticesSize+3);
blockIndexes.add(verticesSize+2);
blockVertsColors.add(new Vector4f(1f,1f,1f,1f));
blockVertsColors.add(new Vector4f(1f,1f,1f,1f));
blockVertsColors.add(new Vector4f(1f,1f,1f,1f));
blockVertsColors.add(new Vector4f(1f,1f,1f,1f));
blockVertsColors.add(new Vector4f(1f,1f,1f,1f));
}
//y = +
if(blockMap[x][y][z].getFace(FACE_DOWN) == true)
{
verticesSize = blockVerts.size() + vertices.size();
blockVerts.add(pe);
blockVerts.add(pf);
blockVerts.add(pa);
blockVerts.add(pb);
blockNorms.add(NORMAL_DOWN);
blockNorms.add(NORMAL_DOWN);
blockNorms.add(NORMAL_DOWN);
blockNorms.add(NORMAL_DOWN);
blockTexCoords.add(TEX_COORD_0);
blockTexCoords.add(TEX_COORD_1);
blockTexCoords.add(TEX_COORD_2);
blockTexCoords.add(TEX_COORD_3);
blockIndexes.add(verticesSize+2);
blockIndexes.add(verticesSize+0);
blockIndexes.add(verticesSize+1);
blockIndexes.add(verticesSize+1);
blockIndexes.add(verticesSize+3);
blockIndexes.add(verticesSize+2);
/
blockVertsColors.add(new Vector4f(.5f,.5f,.5f,1f));
blockVertsColors.add(new Vector4f(.5f,.5f,.5f,1f));
blockVertsColors.add(new Vector4f(.5f,.5f,.5f,1f));
blockVertsColors.add(new Vector4f(.5f,.5f,.5f,1f));/
blockVertsColors.add(new Vector4f(1f,1f,1f,1f));
blockVertsColors.add(new Vector4f(1f,1f,1f,1f));
blockVertsColors.add(new Vector4f(1f,1f,1f,1f));
blockVertsColors.add(new Vector4f(1f,1f,1f,1f));
}
// x = -
if(blockMap[x][y][z].getFace(FACE_LEFT) == true)
{
verticesSize = blockVerts.size() + vertices.size();
blockVerts.add(pe);
blockVerts.add(pa);
blockVerts.add(pg);
blockVerts.add(pc);
blockNorms.add(NORMAL_LEFT);
blockNorms.add(NORMAL_LEFT);
blockNorms.add(NORMAL_LEFT);
blockNorms.add(NORMAL_LEFT);
blockTexCoords.add(TEX_COORD_0);
blockTexCoords.add(TEX_COORD_1);
blockTexCoords.add(TEX_COORD_2);
blockTexCoords.add(TEX_COORD_3);
blockIndexes.add(verticesSize+2);
blockIndexes.add(verticesSize+0);
blockIndexes.add(verticesSize+1);
blockIndexes.add(verticesSize+1);
blockIndexes.add(verticesSize+3);
blockIndexes.add(verticesSize+2);
/*
blockVertsColors.add(new Vector4f(.75f,.75f,.75f,1f));
blockVertsColors.add(new Vector4f(.75f,.75f,.75f,1f));
blockVertsColors.add(new Vector4f(.75f,.75f,.75f,1f));
blockVertsColors.add(new Vector4f(.75f,.75f,.75f,1f));
-
/
blockVertsColors.add(new Vector4f(1f,1f,1f,1f));
blockVertsColors.add(new Vector4f(1f,1f,1f,1f));
blockVertsColors.add(new Vector4f(1f,1f,1f,1f));
blockVertsColors.add(new Vector4f(1f,1f,1f,1f));
}
// x = +
if(blockMap[x][y][z].getFace(FACE_RIGHT) == true)
{
verticesSize = blockVerts.size() + vertices.size();
blockVerts.add(pb);
blockVerts.add(pf);
blockVerts.add(pd);
blockVerts.add(ph);
blockNorms.add(NORMAL_RIGHT);
blockNorms.add(NORMAL_RIGHT);
blockNorms.add(NORMAL_RIGHT);
blockNorms.add(NORMAL_RIGHT);
blockTexCoords.add(TEX_COORD_0);
blockTexCoords.add(TEX_COORD_1);
blockTexCoords.add(TEX_COORD_2);
blockTexCoords.add(TEX_COORD_3);
blockIndexes.add(verticesSize+2);
blockIndexes.add(verticesSize+0);
blockIndexes.add(verticesSize+1);
blockIndexes.add(verticesSize+1);
blockIndexes.add(verticesSize+3);
blockIndexes.add(verticesSize+2);
/
blockVertsColors.add(new Vector4f(.75f,.75f,.75f,1f));
blockVertsColors.add(new Vector4f(.75f,.75f,.75f,1f));
blockVertsColors.add(new Vector4f(.75f,.75f,.75f,1f));
blockVertsColors.add(new Vector4f(.75f,.75f,.75f,1f));/
blockVertsColors.add(new Vector4f(1f,1f,1f,1f));
blockVertsColors.add(new Vector4f(1f,1f,1f,1f));
blockVertsColors.add(new Vector4f(1f,1f,1f,1f));
blockVertsColors.add(new Vector4f(1f,1f,1f,1f));
}
if(blockMap[x][y][z].getFace(FACE_FRONT) == true)
{
verticesSize = blockVerts.size() + vertices.size();
blockVerts.add(pa);
blockVerts.add(pb);
blockVerts.add(pc);
blockVerts.add(pd);
blockNorms.add(NORMAL_FRONT);
blockNorms.add(NORMAL_FRONT);
blockNorms.add(NORMAL_FRONT);
blockNorms.add(NORMAL_FRONT);
blockTexCoords.add(TEX_COORD_0);
blockTexCoords.add(TEX_COORD_1);
blockTexCoords.add(TEX_COORD_2);
blockTexCoords.add(TEX_COORD_3);
blockIndexes.add(verticesSize+2);
blockIndexes.add(verticesSize+0);
blockIndexes.add(verticesSize+1);
blockIndexes.add(verticesSize+1);
blockIndexes.add(verticesSize+3);
blockIndexes.add(verticesSize+2);
blockVertsColors.add(new Vector4f(1f,1f,1f,1f));
blockVertsColors.add(new Vector4f(1f,1f,1f,1f));
blockVertsColors.add(new Vector4f(1f,1f,1f,1f));
blockVertsColors.add(new Vector4f(1f,1f,1f,1f));
}
if(blockMap[x][y][z].getFace(FACE_BACK) == true)
{
verticesSize = blockVerts.size() + vertices.size();
blockVerts.add(pf);
blockVerts.add(pe);
blockVerts.add(ph);
blockVerts.add(pg);
blockNorms.add(NORMAL_BACK);
blockNorms.add(NORMAL_BACK);
blockNorms.add(NORMAL_BACK);
blockNorms.add(NORMAL_BACK);
blockTexCoords.add(TEX_COORD_0);
blockTexCoords.add(TEX_COORD_1);
blockTexCoords.add(TEX_COORD_2);
blockTexCoords.add(TEX_COORD_3);
blockIndexes.add(verticesSize+2);
blockIndexes.add(verticesSize+0);
blockIndexes.add(verticesSize+1);
blockIndexes.add(verticesSize+1);
blockIndexes.add(verticesSize+3);
blockIndexes.add(verticesSize+2);
/
blockVertsColors.add(new Vector4f(.5f,.5f,.5f,1f));
blockVertsColors.add(new Vector4f(.5f,.5f,.5f,1f));
blockVertsColors.add(new Vector4f(.5f,.5f,.5f,1f));
blockVertsColors.add(new Vector4f(.5f,.5f,.5f,1f));*/
blockVertsColors.add(new Vector4f(1f,1f,1f,1f));
blockVertsColors.add(new Vector4f(1f,1f,1f,1f));
blockVertsColors.add(new Vector4f(1f,1f,1f,1f));
blockVertsColors.add(new Vector4f(1f,1f,1f,1f));
}
verticesSize = 0;
blockMap[x][y][z].setVertices(blockVerts);
blockMap[x][y][z].setNormals(blockNorms);
blockMap[x][y][z].setTexCoord(blockTexCoords);
blockMap[x][y][z].setIndexes(blockIndexes);
blockMap[x][y][z].setVerticesColor(blockVertsColors);
}
private void checkDownVerts(int x, int y, int z)
{
int counter = 0;
boolean[] downVerts = {false, false, false, false};
int[] nextX = {x-1, x+1, x-1, x+1};
int[] nextZ = {z+1, z+1, z-1, z-1};
int aboveCounter = 0;
for(int i = 0; i < 4; i++)
{
if(blockMap[nextX][y+1][z] == null || blockMap[x][y+1][nextZ] == null || blockMap[nextX][y+1][nextZ] == null)
{
aboveCounter++;
}
}
for(int i = 0; i < 4; i++)
{
if(blockMap[nextX][y][z] == null || blockMap[x][y][nextZ] == null || blockMap[nextX][y][nextZ] == null)
{
if(blockMap[x][y+1][z] == null)
{
downVerts = true;
counter++;
}
else if(blockMap[x][y+2][z] == null)
{
if(((blockMap[nextX][y+1][z] == null && blockMap[x][y+1][nextZ] == null)) &&
!(aboveCounter == 0 || aboveCounter == 4))
{
downVerts = true;
counter++;
}
}
}
}
blockMap[x][y][z].setDownVerts(downVerts);
blockMap[x][y][z].setDownCount(counter);
}
private void checkFaces(int x, int y, int z)
{
int counter = 0;
boolean[] faces = {false, false, false, false, false, false};
// up face
if(blockMap[x][y+1][z] == null || blockMap[x][y+1][z].getDownCount() == 3)
{
faces[FACE_UP] = true;
counter++;
}
//down face
if(blockMap[x][y-1][z] == null){
faces[FACE_DOWN] = true;
counter++;
}
// left face
if(blockMap[x-1][y][z] == null)
{
faces[FACE_LEFT] = true;
counter++;
}
// right face
if(blockMap[x+1][y][z] == null){faces[FACE_RIGHT] = true; counter++;}
// front face
if(blockMap[x][y][z+1] == null || ((blockMap[x][y][z+1].getDownVert(2) || blockMap[x][y][z+1].getDownVert(3)) && blockMap[x][y+1][z] != null))
{
faces[FACE_FRONT] = true; counter++;
}
// back face
if(blockMap[x][y][z-1] == null){faces[FACE_BACK] = true; counter++;}
blockMap[x][y][z].setFaces(faces);
blockMap[x][y][z].setNumOfFaces(counter);
}
@Override
protected void controlRender(RenderManager rm, ViewPort vp)
{
//throw new UnsupportedOperationException("Not supported yet.");
}
public Control cloneForSpatial(Spatial spatial)
{
throw new UnsupportedOperationException("Not supported yet.");
}
private static int[] convertIntegers(ArrayList<Integer> integers)
{
int[] ret = new int[integers.size()];
for (int i=0; i < ret.length; i++)
{
ret = integers.get(i).intValue();
}
return ret;
}
}[/java]