//removing v2, public void Replace( VoxelVert v2 ) { //assigning this to all v2 faces for (int f = 0; f<6; f++) if (v2.faces[f]!=null) for (int v=0; v<8; v++) if (v2.faces[f].verts[v] == v2) v2.faces[f].verts[v] = this; for (int i = 0; i<6; i++) { //if (v2.neigs[i]!=null) AddNeig(v2.neigs[i]); if (v2.faces[i]!=null) AddFace(v2.faces[i]); } }
public void CalculateTerrain() { terrainProgress = Progress.threadStarted; //bool isMainThread = System.Threading.Thread.CurrentThread.ManagedThreadId == Voxel.mainThreadId; //bool isMainThread = false; int x=0; int y=0; int z=0; //int nx=0; int ny=0; int nz=0; int dir = 0; int v=0; int f=0; int i = 0; VoxelBlock block; VoxelFace face; VoxelVert vert;// VoxelFace nface; //Vector3 pos; System.Collections.Generic.List<VoxelFace> faces = new System.Collections.Generic.List<VoxelFace>(); #region Calculating top and bottom points int topPoint = land.data.GetTopPoint(offsetX, offsetZ, offsetX+size, offsetZ+size)+1; int bottomPoint = Mathf.Max(0, land.data.GetBottomPoint(offsetX, offsetZ, offsetX+size, offsetZ+size)-2); int shortHeight = topPoint - bottomPoint; //emergency exit if chunk contains no blocks if (topPoint<=1) { visibleFaces.Clear(); terrainProgress = Progress.calculated; return; } #endregion bool[] existMatrix = new bool[size*size*shortHeight]; land.data.GetExistMatrix (existMatrix, offsetX, bottomPoint, offsetZ, offsetX+size, topPoint, offsetZ+size); VoxelBlock[] blocks = new VoxelBlock[size*shortHeight*size]; #region Creating all faces //for (y=bottomPoint; y<topPoint; y++) for (y=0; y<shortHeight; y++) for (x=0; x<size; x++) for (z=0; z<size; z++) { i = z*shortHeight*size + y*size + x; //if exists //if (land.data.GetExist(x+offsetX,y,z+offsetZ)) if (existMatrix[z*size*shortHeight + y*size + x]) for (dir = 0; dir<6; dir++) { //if has face at this side if (x+VoxelFace.dirToPosX[dir] >= 0 && x+VoxelFace.dirToPosX[dir] < size && //cap sides here y+VoxelFace.dirToPosY[dir] >= 0 && y+VoxelFace.dirToPosY[dir] < shortHeight && z+VoxelFace.dirToPosZ[dir] >= 0 && z+VoxelFace.dirToPosZ[dir] < size && !existMatrix[ (z+VoxelFace.dirToPosZ[dir])*size*shortHeight + (y+VoxelFace.dirToPosY[dir])*size + x+VoxelFace.dirToPosX[dir] ]) { if (blocks[i]==null) { blocks[i] = new VoxelBlock(x,y+bottomPoint,z); if (x<land.overlap || x>=size-land.overlap || z<land.overlap || z>=size-land.overlap || y == 0) blocks[i].visible = false; else blocks[i].visible = true; byte typeNum = land.data.GetBlock(x+offsetX, y+bottomPoint, z+offsetZ); if (typeNum < land.types.Length) blocks[i].type = land.types[typeNum]; else blocks[i].type = land.types[0]; blocks[i].chunk = this; } face = new VoxelFace(); faces.Add(face); blocks[i].faces[dir] = face; face.block = blocks[i]; face.dir = (byte)dir; //setting face type, and adding it to used types array //face.type = (byte)land.data.GetBlock(x+offsetX, y+bottomPoint, z+offsetZ); //if (!usedTypes.Contains(face.type)) usedTypes.Add(face.type); face.visible = face.block.type.filled; //land.data.exist[face.block.type]; //land.types[face.block.type].visible; //setting coords for (v=0;v<9;v++) { //pos = VoxelVert.posTable[ dir*9 + v ] + new Vector3(x,y,z); //face.coords[v] = 1000000 + pos.x*20000 + pos.y*200 + pos.z*2; } } } } #endregion #region Welding internal, Welding neig int maxSize = size-1; int maxHeight = shortHeight-1; for (y=0; y<shortHeight; y++) for (x=0; x<size; x++) for (z=0; z<size; z++) { int stepz = shortHeight*size; i = z*stepz + y*size + x; if (blocks[i]!=null) for (dir = 0; dir<6; dir++) { block = blocks[i]; face = block.faces[dir]; if (face==null) continue; //weld this block switch (dir) { case 0: face.Weld( block, 5, 0,1,2, 2,1,0); face.Weld( block, 2, 2,3,4, 2,1,0); face.Weld( block, 4, 4,5,6, 2,1,0); face.Weld( block, 3, 6,7,0, 2,1,0); if (x>0) face.Weld( blocks[i-1], 0, 6,7,0, 4,3,2); if (z>0) face.Weld( blocks[i-stepz], 0, 4,5,6, 2,1,0); break; case 1: face.Weld( block, 5, 0,1,2, 6,5,4); face.Weld( block, 3, 2,3,4, 6,5,4); face.Weld( block, 4, 4,5,6, 6,5,4); face.Weld( block, 2, 6,7,0, 6,5,4); if (x>0) face.Weld( blocks[i-1], 1, 2,3,4, 0,7,6); if (z>0) face.Weld( blocks[i-stepz], 1, 4,5,6, 2,1,0); break; case 2: face.Weld( block, 0, 0,1,2, 4,3,2); face.Weld( block, 5, 2,3,4, 0,7,6); face.Weld( block, 1, 4,5,6, 0,7,6); face.Weld( block, 4, 6,7,0, 4,3,2); if (y>0) face.Weld( blocks[i-size], 2, 4,5,6, 2,1,0); if (z>0) face.Weld( blocks[i-stepz], 2, 6,7,0, 4,3,2); break; case 3: face.Weld( block, 0, 0,1,2, 0,7,6); face.Weld( block, 4, 2,3,4, 0,7,6); face.Weld( block, 1, 4,5,6, 4,3,2); face.Weld( block, 5, 6,7,0, 4,3,2); if (y>0) face.Weld( blocks[i-size], 3, 4,5,6, 2,1,0); if (z>0) face.Weld( blocks[i-stepz], 3, 2,3,4, 0,7,6); break; case 4: face.Weld( block, 0, 0,1,2, 6,5,4); face.Weld( block, 2, 2,3,4, 0,7,6); face.Weld( block, 1, 4,5,6, 6,5,4); face.Weld( block, 3, 6,7,0, 4,3,2); if (y>0) face.Weld( blocks[i-size], 4, 4,5,6, 2,1,0); if (x>0) face.Weld( blocks[i-1], 4, 6,7,0, 4,3,2); break; case 5: face.Weld( block, 0, 0,1,2, 2,1,0); face.Weld( block, 3, 2,3,4, 0,7,6); face.Weld( block, 1, 4,5,6, 2,1,0); face.Weld( block, 2, 6,7,0, 4,3,2); if (y>0) face.Weld( blocks[i-size], 5, 4,5,6, 2,1,0); if (x>0) face.Weld( blocks[i-1], 5, 2,3,4, 0,7,6); break; } } } #endregion #region Cross-welding for (y=0; y<shortHeight; y++) for (x=0; x<size; x++) for (z=0; z<size; z++) { int stepz = shortHeight*size; i = z*stepz + y*size + x; int j = i; if (blocks[i]!=null) for (dir = 0; dir<6; dir++) { face = blocks[i].faces[dir]; if (face==null) continue; //weld cross block if (dir==0 && y<maxHeight) { j = i+size; if (x>0) face.Weld( blocks[j-1], 2, 6,7,0, 6,5,4); //x-1,y+1,z if (z>0) face.Weld( blocks[j-stepz], 5, 4,5,6, 6,5,4); //x,y+1,z-1 if (x<maxSize) face.Weld( blocks[j+1], 3, 2,3,4, 6,5,4); //x+1,y+1,z if (z<maxSize) face.Weld( blocks[j+stepz], 4, 0,1,2, 6,5,4); //x,y+1,z+1 } else if (dir==1 && y>0) { j = i-size; if (x>0) face.Weld( blocks[j-1], 2, 2,3,4, 2,1,0); //x-1,y-1,z if (z>0) face.Weld( blocks[j-stepz], 5, 4,5,6, 2,1,0); //x,y-1,z-1 if (x<maxSize) face.Weld( blocks[j+1], 3, 6,7,0, 2,1,0); //x+1,y-1,z if (z<maxSize) face.Weld( blocks[j+stepz], 4, 0,1,2, 2,1,0); //x,y-1,z+1 } else if (dir==2 && x<maxSize) { j = i+1; if (y>0) face.Weld( blocks[j-size], 0, 4,5,6, 0,7,6); //x+1,y-1,z if (z>0) face.Weld( blocks[j-stepz], 5, 6,7,0, 4,3,2); //x+1,y,z-1 if (y<maxHeight) face.Weld( blocks[j+size], 1, 0,1,2, 4,3,2);//x+1,y+1,z if (z<maxSize) face.Weld( blocks[j+stepz], 4, 2,3,4, 0,7,6); //x+1,y,z+1 } else if (dir==3 && x>0) { j = i-1; if (y>0) face.Weld( blocks[j-size], 0, 4,5,6, 4,3,2); //x-1,y-1,z if (z>0) face.Weld( blocks[j-stepz], 5, 2,3,4, 0,7,6); //x-1,y,z-1 if (y<maxHeight) face.Weld( blocks[j+size], 1, 0,1,2, 0,7,6);//x-1,y+1,z if (z<maxSize) face.Weld( blocks[j+stepz], 4, 6,7,0, 4,3,2); //x-1,y,z+1 } else if (dir==4 && z>0) { j = i-stepz; if (y>0) face.Weld( blocks[j-size], 0, 4,5,6, 2,1,0); //x,y-1,z-1 if (x>0) face.Weld( blocks[j-1], 2, 6,7,0, 4,3,2); //x-1,y,z-1 if (y<maxHeight) face.Weld( blocks[j+size], 1, 0,1,2, 2,1,0);//x,y+1,z-1 if (x<maxSize) face.Weld( blocks[j+1], 3, 2,3,4, 0,7,6); //x+1,y,z-1 } else if (dir==5 && z<maxSize) { j = i+stepz; if (y>0) face.Weld( blocks[j-size], 0, 4,5,6, 6,5,4); //x,y-1,z+1 if (x>0) face.Weld( blocks[j-1], 2, 2,3,4, 0,7,6); //x-1,y,z+1 if (y<maxHeight) face.Weld( blocks[j+size], 1, 0,1,2, 6,5,4);//x,y+1,z+1 if (x<maxSize) face.Weld( blocks[j+1], 3, 6,7,0, 4,3,2); //x+1,y,z+1 } for (v=0;v<9;v++) { vert = face.verts[v]; //setting new vert if (vert==null) { vert = new VoxelVert(); face.verts[v] = vert; } vert.pos = VoxelVert.posTable[ dir*9 + v ] + new Vector3(x,y,z); vert.AddFace(face); } //face.LinkVerts(); } } #endregion #region Linking (adding verts neigs) for (f=0;f<faces.Count;f++) faces[f].LinkVerts(); #endregion #region Lifting on BottomPoint for (f=0;f<faces.Count;f++) { face = faces[f]; for (v=0;v<9;v++) if (!face.verts[v].processed) { face.verts[v].pos += new Vector3(0,bottomPoint,0); face.verts[v].processed = true; } } for (f=0;f<faces.Count;f++) //clearing for (v=0;v<9;v++) faces[f].verts[v].processed = false; #endregion #region Relaxing //setting vert relax for (f=0;f<faces.Count;f++) { for (v=0;v<9;v++) { faces[f].verts[v].relax += faces[f].block.type.smooth; faces[f].verts[v].relaxCount += 1; } } for (f=0;f<faces.Count;f++) for (v=0;v<9;v++) if (faces[f].verts[v].relaxCount != 0) { faces[f].verts[v].relax = faces[f].verts[v].relax / faces[f].verts[v].relaxCount; faces[f].verts[v].relaxCount = 0; } //averaging corners for (f=0;f<faces.Count;f++) { face = faces[f]; if (!face.verts[0].processed) { face.verts[0].pos += face.verts[0].GetRelax()*2; face.verts[0].processed=true; } if (!face.verts[2].processed) { face.verts[2].pos += face.verts[2].GetRelax()*2; face.verts[2].processed=true; } if (!face.verts[4].processed) { face.verts[4].pos += face.verts[4].GetRelax()*2; face.verts[4].processed=true; } if (!face.verts[6].processed) { face.verts[6].pos += face.verts[6].GetRelax()*2; face.verts[6].processed=true; } } //averaging mid verts for (f=0;f<faces.Count;f++) { face = faces[f]; face.verts[1].pos = (face.verts[0].pos + face.verts[2].pos) * 0.5f; face.verts[3].pos = (face.verts[2].pos + face.verts[4].pos) * 0.5f; face.verts[5].pos = (face.verts[4].pos + face.verts[6].pos) * 0.5f; face.verts[7].pos = (face.verts[6].pos + face.verts[0].pos) * 0.5f; face.verts[8].pos = (face.verts[0].pos + face.verts[2].pos + face.verts[4].pos + face.verts[6].pos) * 0.25f; //returning processed flags face.verts[0].processed = false; face.verts[2].processed = false; face.verts[4].processed = false; face.verts[6].processed = false; } //seconary relax for (f=0;f<faces.Count;f++) { face = faces[f]; for (v=0;v<9;v++) if (!face.verts[v].processed) { face.verts[v].relaxed = face.verts[v].GetRelax(); face.verts[v].processed = true; } } for (f=0;f<faces.Count;f++) for (v=0;v<9;v++) faces[f].verts[v].processed = false; for (f=0;f<faces.Count;f++) { face = faces[f]; for (v=0;v<9;v++) if (!face.verts[v].processed) { face.verts[v].pos += face.verts[v].relaxed; face.verts[v].processed = true; } } #endregion #region Setting normals for (f=0;f<faces.Count;f++) { face = faces[f]; face.verts[0].normal += Vector3.Cross(face.verts[1].pos-face.verts[0].pos, face.verts[7].pos-face.verts[0].pos).normalized; face.verts[2].normal += Vector3.Cross(face.verts[3].pos-face.verts[2].pos, face.verts[1].pos-face.verts[2].pos).normalized; face.verts[4].normal += Vector3.Cross(face.verts[5].pos-face.verts[4].pos, face.verts[3].pos-face.verts[4].pos).normalized; face.verts[6].normal += Vector3.Cross(face.verts[7].pos-face.verts[6].pos, face.verts[5].pos-face.verts[6].pos).normalized; face.verts[1].normal += Vector3.Cross(face.verts[8].pos-face.verts[1].pos, face.verts[0].pos-face.verts[1].pos).normalized + Vector3.Cross(face.verts[2].pos-face.verts[1].pos, face.verts[8].pos-face.verts[1].pos).normalized; face.verts[3].normal += Vector3.Cross(face.verts[8].pos-face.verts[3].pos, face.verts[2].pos-face.verts[3].pos).normalized + Vector3.Cross(face.verts[4].pos-face.verts[3].pos, face.verts[8].pos-face.verts[3].pos).normalized; face.verts[5].normal += Vector3.Cross(face.verts[8].pos-face.verts[5].pos, face.verts[4].pos-face.verts[5].pos).normalized + Vector3.Cross(face.verts[6].pos-face.verts[5].pos, face.verts[8].pos-face.verts[5].pos).normalized; face.verts[7].normal += Vector3.Cross(face.verts[8].pos-face.verts[7].pos, face.verts[6].pos-face.verts[7].pos).normalized + Vector3.Cross(face.verts[0].pos-face.verts[7].pos, face.verts[8].pos-face.verts[7].pos).normalized; face.verts[8].normal = Vector3.Cross(face.verts[1].pos-face.verts[5].pos, face.verts[3].pos-face.verts[7].pos).normalized; } if (land.normalsRandom > 0.01f) { for (x=0; x<size; x++) for (z=0; z<size; z++) for (y=0; y<shortHeight; y++) { i = z*shortHeight*size + y*size + x; if (blocks[i]==null) continue; if (!blocks[i].visible) continue; Vector3 normalRandom = new Vector3(Random.value-0.5f, Random.value-0.5f, Random.value-0.5f)*1; for (f=0;f<6;f++) if (blocks[i].faces[f]!=null && blocks[i].faces[f].visible) for (v=0;v<9;v++) blocks[i].faces[f].verts[v].normal += normalRandom; } } #endregion #region Set visible faces //visibleFaces.Clear(); visibleFaces = new System.Collections.Generic.List<VoxelFace>(); for (x=0; x<size; x++) for (z=0; z<size; z++) for (y=0; y<shortHeight; y++) { i = z*shortHeight*size + y*size + x; if (blocks[i]==null) continue; if (!blocks[i].visible) continue; for (f=0;f<6;f++) if (blocks[i].faces[f]!=null && blocks[i].faces[f].visible) visibleFaces.Add(blocks[i].faces[f]); } #endregion #region Set collider hierarchy boundsMin = new Vector2(offsetX + land.overlap, offsetZ + land.overlap); boundsMax = new Vector2(offsetX - land.overlap*2 + size, offsetZ - land.overlap*2 + size); boundsCenter = (boundsMin+boundsMax) / 2f; faceHolders = new FaceHolder[16]; int facesPerHolder = Mathf.CeilToInt((size-land.overlap*2) / 4f); for (x=0; x<4; x++) for (z=0; z<4; z++) { faceHolders[z*4+x] = new FaceHolder(); faceHolders[z*4+x].faces = new List<VoxelFace>(); faceHolders[z*4+x].min = new Vector2(boundsMin.x + facesPerHolder*x, boundsMin.y + facesPerHolder*z); faceHolders[z*4+x].center = faceHolders[z*4+x].min + new Vector2(facesPerHolder/2f, facesPerHolder/2f); if (x==3) faceHolders[z*4+x].max = new Vector2(boundsMax.x, boundsMin.y + facesPerHolder*(z+1)); else if (z==3) if (x==3) faceHolders[z*4+x].max = new Vector2(boundsMin.x + facesPerHolder*(x+1), boundsMax.y); else faceHolders[z*4+x].max = new Vector2(boundsMin.x + facesPerHolder*(x+1), boundsMin.y + facesPerHolder*(z+1)); } for (f=0; f<visibleFaces.Count; f++) { face = visibleFaces[f]; x = face.block.x / facesPerHolder; z = face.block.z / facesPerHolder; faceHolders[z*4+x].faces.Add(face); } #endregion terrainProgress = Progress.calculated; }
public void AddNeig( VoxelVert vert ) { if (neigs==null) neigs = new VoxelVert[7]; if (neigCount==0) { neigs[0]=vert; neigCount=1; return; } switch (neigCount) { case 0: neigs[0]=vert; neigCount=1; break; case 1: if (neigs[0].coords!=vert.coords) { neigs[1]=vert; neigCount=2; } break; default: for (int i=0; i<neigCount; i++) if (neigs[i].coords == vert.coords) return; //already added neigs[neigCount]=vert; neigCount++; break; } }