public override bool Calculate() { VoxelBlock <T> block = input.GetValue <VoxelBlock <T> >(); if (block == null || block.Layers == null) { return(false); } CalculationSetup(block); bool success = true; for (int i = 0; i < block.Layers.Count(); i++) { if (!CalculateLayer(block.Layers[i], i - block.Overlap)) { success = false; break; } } CalculationTeardown(); output.SetValue(block); return(success); }
protected void apply(Application app, VoxelBlock block, Index pos) { Index cornerChild = pos.getChild(); for (byte c = 0; c < VoxelBlock.CHILD_COUNT; ++c) { // TODO: use min and max to reduce number of values considered Index childPos = cornerChild.getNeighbor(c); Action action = checkMutation(app, childPos); if (!action.modify) { continue; } Action maskAction = checkMasks(app.tree, childPos); if (!maskAction.modify) { continue; } if (childPos.depth < app.tree.maxDetail && (maskAction.doTraverse || action.doTraverse)) { apply(app, block.expand(childPos.xLocal, childPos.yLocal, childPos.zLocal), childPos); } else { block.children[childPos.xLocal, childPos.yLocal, childPos.zLocal] = mutate(app, childPos, action, block.children[childPos.xLocal, childPos.yLocal, childPos.zLocal].toVoxel()); } if (childPos.depth == app.tree.maxDetail - VoxelRenderer.VOXEL_COUNT_POWER && (action.modify)) { block.updateAll(childPos.x, childPos.y, childPos.z, childPos.depth, app.tree, true); } } }
protected override void CalculationSetup(VoxelBlock <Voxel> block) { width = block.Width; height = block.Height; length = block.Length; offset = block.Offset; }
public override bool Calculate() { VoxelBlock <T> block = new VoxelBlock <T>(); block.Offset = Offset; output.SetValue(InitBlock(block)); return(true); }
public List <VoxelBlock> findPath(VoxelBlock start, VoxelBlock goal) { var closedset = new HashSet <VoxelBlock>(); var openset = new HashSet <VoxelBlock>(); openset.Add(start); var came_from = new Dictionary <VoxelBlock, VoxelBlock>(); var g_score = new Dictionary <VoxelBlock, float>(); var f_score = new Dictionary <VoxelBlock, float>(); //came_from := the empty map // The map of navigated nodes. g_score[start] = 0; // Cost from start along best known path. // Estimated total cost from start to goal through y. f_score[start] = g_score[start] + heuristic_cost_estimate(start, goal); int numIts = 100; while (openset.Count > 0) { numIts--; if (numIts < 0) { return(null); } //openset.Sort((a, b) => f_score[a] < f_score[b] ? -1 : f_score[a] > f_score[b] ? 1 : 0); var current = openset.OrderBy(o => f_score[o]).First(); // the node in openset having the lowest f_score[] value if (current.Equals(goal)) { return(reconstruct_path(came_from, goal)); } openset.Remove(current); //remove current from openset closedset.Add(current); //add current to closedset foreach (var neighbor in connected_nodes(current)) { //TW.Graphics.LineManager3D.AddCenteredBox(neighbor.Position + MathHelper.One*0.5f,0.5f, new Color4(0,0,1)); if (closedset.Contains(neighbor)) { continue; } var tentative_g_score = g_score[current] + dist_between(current, neighbor); if (!openset.Contains(neighbor) || tentative_g_score <= g_score[neighbor]) { came_from[neighbor] = current; g_score[neighbor] = tentative_g_score; f_score[neighbor] = g_score[neighbor] + heuristic_cost_estimate(neighbor, goal); if (!openset.Contains(neighbor)) { openset.Add(neighbor); } } } } return(null); }
public override bool Calculate() { if (!block1Connection.connected() || !block2Connection.connected()) { return(false); } VoxelBlock <Voxel> block1 = block1Connection.GetValue <VoxelBlock <Voxel> >(); VoxelBlock <Voxel> block2 = block2Connection.GetValue <VoxelBlock <Voxel> >(); int overlap = block1.Overlap; int width = block1.Width; int height = block1.Height; int length = block1.Length; for (int y = 0; y < height + 2 * overlap; y++) { VoxelLayer <Voxel> l1 = block1.Layers[y]; VoxelLayer <Voxel> l2 = block2.Layers[y]; for (int x = 0; x < width + 2 * overlap; x++) { for (int z = 0; z < length + 2 * overlap; z++) { var v1 = l1.Layer[x, z]; var v2 = l2.Layer[x, z]; switch (mode) { case CombiningMode.Average: v1.Data = (v1.Data + v2.Data) / 2; break; case CombiningMode.Add: v1.Data = v1.Data + v2.Data; break; case CombiningMode.Subtract: v1.Data = v1.Data - v2.Data; break; case CombiningMode.Divide: if (v2.Data != 0) { v1.Data = v1.Data / v2.Data; } break; case CombiningMode.Multiply: v1.Data = v1.Data * v2.Data; break; } } } } outputConnection.SetValue(block1); return(true); }
public void ReInit(VoxelBlock <Voxel> block) { int overlap = block.Overlap; int blockHeight = block.Height + 2 * overlap; int blockWidth = block.Width + 2 * overlap; int blockLength = block.Length + 2 * overlap; if (initHeight == blockHeight && initWidth == blockWidth && initLength == blockLength) { // we are already set up to process blocks of this size return; } Debug.LogFormat("reinit block ({0}, {1}, {2}) => ({3}, {4}, {5})", initWidth, initHeight, initLength, blockWidth, blockHeight, blockLength); initWidth = blockWidth; initHeight = blockHeight; initLength = blockLength; float[] dummyVoxels = new float[blockHeight * blockWidth * blockLength]; addPadding(ref dummyVoxels, ref blockWidth, ref blockHeight, ref blockLength); numBlocks = new Vector3Int((blockWidth - 1) / blockSize.x, (blockHeight - 1) / blockSize.y, (blockLength - 1) / blockSize.z); if (voxelBuffer != null) { voxelBuffer.Dispose(); } voxelBuffer = new ComputeBuffer(dummyVoxels.Length, sizeof(float)); if (minMaxBuffer != null) { minMaxBuffer.Dispose(); } minMaxBuffer = new ComputeBuffer(numBlocks.x * numBlocks.y * numBlocks.z, 2 * sizeof(float)); if (compactedBlkArray != null) { compactedBlkArray.Dispose(); } compactedBlkArray = new ComputeBuffer(numBlocks.x * numBlocks.y * numBlocks.z, sizeof(int)); PMBShader.SetBuffer(minMaxKernelIndex, "voxelBuffer", voxelBuffer); PMBShader.SetBuffer(minMaxKernelIndex, "minMaxBuffer", minMaxBuffer); PMBShader.SetInts("size", new int[] { blockWidth, blockHeight, blockLength }); PMBShader.SetInts("numBlocks", new int[] { numBlocks.x, numBlocks.y, numBlocks.z }); PMBShader.SetBuffer(compactActiveBlocksKernelIndex, "activeBlkNum", activeBlkNum); PMBShader.SetBuffer(compactActiveBlocksKernelIndex, "minMaxBuffer", minMaxBuffer); PMBShader.SetBuffer(compactActiveBlocksKernelIndex, "compactedBlkArray", compactedBlkArray); PMBShader.SetBuffer(generateTrianglesKernelIndex, "marchingCubesEdgeTable", marchingCubesEdgeTableBuffer); PMBShader.SetBuffer(generateTrianglesKernelIndex, "globalVertexOffset", globalVertexOffset); PMBShader.SetBuffer(generateTrianglesKernelIndex, "voxelBuffer", voxelBuffer); PMBShader.SetBuffer(generateTrianglesKernelIndex, "compactedBlkArray", compactedBlkArray); }
private float heuristic_cost_estimate(VoxelBlock start, VoxelBlock goal) { var a = terrain.GetPositionOf(start); var b = terrain.GetPositionOf(goal); float dist = 0; for (int i = 0; i < 3; i++) { dist += (float)Math.Abs(a[i] - b[i]); } return(dist); }
private IEnumerable <VoxelBlock> connected_nodes(VoxelBlock current) { bool inAir = !getBelow(current).Filled; // give neighbours with soil under foreach (var n in neighbor_nodes(current).Where(n => !n.Filled)) { if (n.RelativePosition.Y != current.RelativePosition.Y) { continue; // no vertical movement } VoxelBlock it = n; int fallDepth = 3; //TODO fix staying in air when once in air if (inAir) { fallDepth = 1; } for (int i = 0; i < fallDepth; i++) { it = getBelow(it); if (it != null && it.Filled) { if (n.Filled) { throw new InvalidOperationException(); } yield return(n); } } } if (!inAir) { var up = getUp(current); if (up != null && !up.Filled) { if (up.Filled) { throw new InvalidOperationException(); } yield return(up); } } else { if (getBelow(current).Filled) { throw new InvalidOperationException(); } yield return(getBelow(current)); } }
public VoxelBlock(VoxelBlock <T> b) { if (b == null) { return; } this.Offset = b.Offset; if (b.Layers != null) { this.layers = new VoxelLayer <T> [b.layers.Count()]; for (int i = 0; i < b.layers.Count(); i++) { this.layers[i] = new VoxelLayer <T>(b.layers[i]); } } this.Overlap = b.Overlap; }
public override bool Calculate() { VoxelBlock <T> block = input.GetValue <VoxelBlock <T> >(); if (block == null || block.Layers == null) { return(false); } CalculationSetup(block); bool success = block.Layers.AsParallel().Select((layer, i) => CalculateLayer(layer, i)).All(x => x); CalculationTeardown(); output.SetValue(block); return(success); }
private IEnumerable <VoxelBlock> neighbor_nodes(VoxelBlock current) { for (int i = 0; i < 3; i++) { var axis = new Point3(); axis[i] = 1; var n1 = terrain.GetVoxelAt(terrain.GetPositionOf(current) + axis); var n2 = terrain.GetVoxelAt(terrain.GetPositionOf(current) - axis); if (n1 != null) { yield return(n1); } if (n2 != null) { yield return(n2); } } }
VoxelBlock <Voxel> InitBlock(Vector3Int size) { VoxelBlock <Voxel> block = new VoxelBlock <Voxel>(); VoxelLayer <Voxel>[] layers = new VoxelLayer <Voxel> [size.y]; for (int y = 0; y < size.y; y++) { Voxel[,] voxelLayer = new Voxel[size.x, size.z]; for (int x = 0; x < size.x; x++) { for (int z = 0; z < size.z; z++) { voxelLayer[x, z] = new Voxel(); } } layers[y] = new VoxelLayer <Voxel>(voxelLayer); } block.Layers = layers; return(block); }
protected void apply(Application app, VoxelBlock block, Index pos) { Index cornerChild = pos.getChild(); for(byte c = 0; c<VoxelBlock.CHILD_COUNT; ++c) { // TODO: use min and max to reduce number of values considered Index childPos = cornerChild.getNeighbor(c); Action action = checkMutation(app, childPos); if (!action.modify) continue; Action maskAction = checkMasks(app.tree, childPos); if (!maskAction.modify) continue; if (childPos.depth < app.tree.maxDetail && (maskAction.doTraverse || action.doTraverse)) apply(app, block.expand(childPos.xLocal, childPos.yLocal, childPos.zLocal), childPos); else block.children[childPos.xLocal, childPos.yLocal, childPos.zLocal] = mutate(app, childPos, action, block.children[childPos.xLocal, childPos.yLocal, childPos.zLocal].toVoxel()); if (childPos.depth == app.tree.maxDetail - VoxelRenderer.VOXEL_COUNT_POWER && (action.modify)) block.updateAll(childPos.x, childPos.y, childPos.z, childPos.depth, app.tree, true); } }
protected override VoxelBlock <Voxel> InitBlock(VoxelBlock <Voxel> block) { int size = 64; VoxelLayer <Voxel>[] layers = new VoxelLayer <Voxel> [64]; for (int y = 0; y < size; y++) { Voxel[,] voxelLayer = new Voxel[size, size]; for (int x = 0; x < size; x++) { for (int z = 0; z < size; z++) { voxelLayer[x, z] = new Voxel(); if (y < size / 2) { voxelLayer[x, z].Data = 1.0f; } } } layers[y] = new VoxelLayer <Voxel>(voxelLayer); } block.Layers = layers; return(block); }
public void Weld( VoxelBlock block2 , int dir2 , int p1 , int p2 ) { if (block2!=null && block2.faces[dir2]!=null) Weld( block2.faces[dir2], p1, p2, true); }
protected virtual void CalculationSetup(VoxelBlock <T> block) { }
//same as above, but works only when no p1 (for cross-block) public void Weld( VoxelBlock block2 , int dir2 , int p1 , int p2 , bool check ) { if (verts[p1]==null && block2!=null && block2.faces[dir2]!=null && block2.faces[dir2].verts[p2]==null) Weld( block2.faces[dir2], p1, p2, true); }
public List <VoxelBlock> reconstruct_path(Dictionary <VoxelBlock, VoxelBlock> came_from, VoxelBlock current_node) { var ret = new List <VoxelBlock>(); for (int i = 0; i < 200; i++) { ret.Add(current_node); if (!came_from.ContainsKey(current_node)) { break; } current_node = came_from[current_node]; } return(ret); //if came_from[current_node] in set // p := reconstruct_path(came_from, came_from[current_node]) // return (p + current_node) //else // return current_node }
//welding three poins (side) using mid-point number public void Weld( VoxelBlock block2 , int dir2 , int pA1 , int pA2 , int pA3 , int pB1 , int pB2 , int pB3 ) { if (verts[pA2]==null && block2!=null && block2.faces[dir2]!=null && block2.faces[dir2].verts[pB2]==null) { VoxelFace fB = block2.faces[dir2]; Weld(fB, pA1, pB1); Weld(fB, pA2, pB2); Weld(fB, pA3, pB3); } }
private VoxelBlock getUp(VoxelBlock block) { return(terrain.GetVoxelAt(terrain.GetPositionOf(block) + MathHelper.Up)); }
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; }
private float dist_between(VoxelBlock current, VoxelBlock neighbor) { return(1); }
protected abstract VoxelBlock <T> InitBlock(VoxelBlock <T> block);
protected override void CalculationSetup(VoxelBlock <Voxel> block) { dInput = inputUpperBound - inputLowerBound; dOutput = outputUpperBound - outputLowerBound; }
private VoxelBlock getBelow(VoxelBlock block) { return(terrain.GetVoxelAt(terrain.GetPositionOf(block) + MathHelper.Down)); }
public IEnumerator <object> genericTest(Tests type, string name, int cpuLimit, int pmbLimit, Func <Vector3Int, int, int, int, float> voxelGenerator) { int CPU_LIMIT = cpuLimit; int PMB_LIMIT = pmbLimit; UnityEngine.Debug.Log("Starting Test " + name); perfData[(int)type] = new PerfData { testName = name, sizes = new TestSize[testSizes.Length], }; int limitCounter = 0; for (int i = 0; i < testSizes.Length; i++) { Vector3Int size = (Vector3Int)testSizes[i]; UnityEngine.Debug.Log("size: " + size); perfData[(int)type].sizes[i] = new TestSize { sizeName = string.Format("({0}, {1}, {2})", size.x, size.y, size.z), cpuTime = new int[ROUNDS], pmbTime = new int[ROUNDS], cpuTriangles = 0, pmbTriangles = 0, }; float[] voxel; string path = Path.Combine(performanceDataDir, string.Format("{0}{1}.dat", name, perfData[(int)type].sizes[i].sizeName)); if (File.Exists(path)) { UnityEngine.Debug.Log("loading voxelData from file:"); Stream voxelStream = File.OpenRead(path); BinaryFormatter deserializer = new BinaryFormatter(); voxel = (float[])deserializer.Deserialize(voxelStream); voxelStream.Close(); } else { UnityEngine.Debug.Log("recreating voxelData:"); voxel = new float[size.x * size.y * size.z]; for (int x = 0; x < size.x; x++) { for (int y = 0; y < size.y; y++) { for (int z = 0; z < size.z; z++) { voxel[z * size.x * size.y + y * size.x + x] = voxelGenerator(size, x, y, z); } } } Stream SaveFileStream = File.Create(path); BinaryFormatter serializer = new BinaryFormatter(); serializer.Serialize(SaveFileStream, voxel); SaveFileStream.Close(); } UnityEngine.Debug.Log("executing Test:"); for (int round = 0; round < ROUNDS; round++) { Stopwatch watch = Stopwatch.StartNew(); if (limitCounter < CPU_LIMIT) { List <Vector3> verts = new List <Vector3>(); List <int> indices = new List <int>(); List <Vector3> normals = new List <Vector3>(); marching.Generate(voxel, size.x, size.y, size.z, verts, indices, normals); watch.Stop(); UnityEngine.Debug.LogFormat("\tCPU took {0}ms", watch.ElapsedMilliseconds); perfData[(int)type].sizes[i].cpuTime[round] = (int)watch.ElapsedMilliseconds; perfData[(int)type].sizes[i].cpuTriangles = indices.Count / 3; } else { UnityEngine.Debug.Log("\tCPU skipped"); perfData[(int)type].sizes[i].cpuTime[round] = -1; } if (limitCounter < PMB_LIMIT) { VoxelBlock <Voxel> block = InitBlock(size); UnityEngine.Debug.Log(voxel.Length + " " + voxel[0] + " " + voxel[1] + " " + voxel[2] + " " + voxel[3] + " " + voxel[4] + " " + voxel[5] + " " + voxel[6] + " " + voxel[7]); helper.scheduleOnMainThread(() => { watch = Stopwatch.StartNew(); pmb.ReInit(block); RenderBuffers buffers = pmb.calculate(voxel, size.x, size.y, size.z, 0.5f); int[] args = new int[4]; buffers.argsBuffer.GetData(args); watch.Stop(); UnityEngine.Debug.LogFormat("\tPMB took {0}ms", watch.ElapsedMilliseconds); perfData[(int)type].sizes[i].pmbTime[round] = (int)watch.ElapsedMilliseconds; perfData[(int)type].sizes[i].pmbTriangles = args[0] / 3; buffers.vertexBuffer.Dispose(); buffers.indexBuffer.Dispose(); buffers.normalBuffer.Dispose(); buffers.argsBuffer.Dispose(); UnityEngine.Debug.Log("PMB triags inside thread: " + perfData[(int)type].sizes[i].pmbTriangles); }).wait(); UnityEngine.Debug.Log("PMB triags after thread: " + perfData[(int)type].sizes[i].pmbTriangles); } else { UnityEngine.Debug.Log("\tPMB skipped"); perfData[(int)type].sizes[i].pmbTime[round] = -1; watch.Stop(); } yield return(null); } limitCounter++; } }
public override bool Calculate() { VoxelBlock <T> block = input.GetValue <VoxelBlock <T> >(); if (block == null || block.Layers == null) { return(false); } CalculationSetup(block); Vector3Int voxelCount = block.VoxelCount; bool success = true; for (int x = 0; x < voxelCount.x && success; x++) { for (int z = 0; z < voxelCount.z; z++) { float height; if (!CalculateHeight(out height, x - block.Overlap, z - block.Overlap)) { success = false; break; } for (int y = -block.Overlap; y < voxelCount.y - block.Overlap; y++) { float voxelHeight = y / (float)block.Height; if (height > voxelHeight) { float nextVoxelHeight = (y + 1) / (float)block.Height; if (height >= nextVoxelHeight) { block[x - block.Overlap, y, z - block.Overlap].Data = 1.0f; } else { block[x - block.Overlap, y, z - block.Overlap].Data = (height - voxelHeight) * (float)block.Height; } } else { block[x - block.Overlap, y, z - block.Overlap].Data = 0.0f; } } } } if (!success) { CalculationTeardown(); return(false); } CalculationTeardown(); output.SetValue(block); return(true); }
public override bool Calculate() { Meshes = new List <GameObject>(); VoxelBlock <Voxel> block = input.GetValue <VoxelBlock <Voxel> >(); Marching marching = null; if (mode == MarchingMode.Tetrahedron) { marching = new MarchingTertrahedron(); } else { marching = new MarchingCubes(); } //Surface is the value that represents the surface of mesh //For example the perlin noise has a range of -1 to 1 so the mid point is where we want the surface to cut through. //The target value does not have to be the mid point it can be any value with in the range. // //This should be accesible by an input marching.Surface = 0.5f; //The size of voxel array. int width = block.Width; int height = block.Height; int length = block.Length; float[] voxels = new float[width * height * length]; for (int y = 0; y < height; y++) { Voxel[,] voxelLayer = block.Layers[y].Layer; for (int x = 0; x < width; x++) { for (int z = 0; z < length; z++) { int idx = x + y * width + z * width * height; voxels[idx] = voxelLayer[x, z].GetValue(); } } } List <Vector3> verts = new List <Vector3>(); List <int> indices = new List <int>(); //The mesh produced is not optimal. There is one vert for each index. //Would need to weld vertices for better quality mesh. marching.Generate(voxels, width, height, length, verts, indices); int generatedVerts = verts.Count; int generatedIndices = indices.Count; weldVertices(verts, indices); Debug.Log("Vertex Welding: " + generatedVerts + "=>" + verts.Count); Debug.Log("Vertex Welding indices: " + generatedIndices + "=>" + indices.Count); Debug.LogError("Out of Bounds: " + indices.Find(i => i >= verts.Count)); //A mesh in unity can only be made up of 65000 verts. //Need to split the verts between multiple meshes. int maxVertsPerMesh = 30000; //must be divisible by 3, ie 3 verts == 1 triangle int numMeshes = verts.Count / maxVertsPerMesh + 1; for (int i = 0; i < numMeshes; i++) { List <Vector3> splitVerts = new List <Vector3>(); List <int> splitIndices = new List <int>(); for (int j = 0; j < maxVertsPerMesh; j++) { int idx = i * maxVertsPerMesh + j; if (idx < verts.Count) { splitVerts.Add(verts[idx]); splitIndices.Add(j); } } if (splitVerts.Count == 0) { continue; } splitVerts = verts; splitIndices = indices; Mesh mesh = new Mesh(); mesh.SetVertices(splitVerts); mesh.SetTriangles(splitIndices, 0); mesh.RecalculateBounds(); mesh.RecalculateNormals(); GameObject go = new GameObject("Mesh"); // go.transform.parent = transform; go.AddComponent <MeshFilter>(); go.AddComponent <MeshRenderer>(); // go.GetComponent<Renderer>().material = m_material; go.GetComponent <MeshFilter>().mesh = mesh; go.transform.localPosition = new Vector3(-width / 2, -height / 2, -length / 2); go.transform.localScale = new Vector3(1.0f, 1.0f, 1.0f); Meshes.Add(go); } VertexDisplay.RenderNewMeshes(Meshes); return(true); }
public override bool Calculate() { bool isPMB = false; if (!input.connected()) { return(false); } VoxelBlock <Voxel> block = input.GetValue <VoxelBlock <Voxel> >(); if (surfaceConnection.connected()) { surface = surfaceConnection.GetValue <float>(); } Marching marching = null; switch (mode) { case VerteGenerationMode.Tetrahedron: marching = new MarchingTertrahedron(); break; case VerteGenerationMode.Cubes: marching = new MarchingCubes(); break; case VerteGenerationMode.Voxel: marching = new VoxelGeneration(); break; case VerteGenerationMode.PMB: isPMB = true; break; } //The size of voxel array. Vector3Int count = block.VoxelCount; int width = count.x; int height = count.y; int length = count.z; float[] voxels = new float[width * height * length]; for (int y = 0; y < height; y++) { Voxel[,] voxelLayer = block.Layers[y].Layer; for (int x = 0; x < width; x++) { for (int z = 0; z < length; z++) { int idx = x + y * width + z * width * height; voxels[idx] = voxelLayer[x, z].GetValue(); } } } if (isPMB) { var pmbTask = MainThreadHelper.instance().scheduleOnMainThread(() => { pmb.ReInit(block); Stopwatch pmbWatch = Stopwatch.StartNew(); buffers = pmb.calculate(voxels, width, height, length, surface); pmbWatch.Stop(); UnityEngine.Debug.LogFormat("PMB took {0}ms\n\t{1} voxels\n\t{2} triangles", pmbWatch.ElapsedMilliseconds, voxels.Count(), buffers.indexBuffer.count / 3); }); pmbTask.wait(); if (!pmbTask.completed) { return(false); } Block = block; return(true); } //Surface is the value that represents the surface of mesh //For example the perlin noise has a range of -1 to 1 so the mid point is where we want the surface to cut through. //The target value does not have to be the mid point it can be any value with in the range. // //This should be accesible by an input marching.Surface = surface; List <Vector3> verts = new List <Vector3>(); List <int> indices = new List <int>(); List <Vector3> normals = new List <Vector3>(); Stopwatch sw = Stopwatch.StartNew(); marching.Generate(voxels, width, height, length, verts, indices, normals); sw.Stop(); UnityEngine.Debug.LogFormat("Marching took {0}ms\n\t{1} vertices; {2} triangles", sw.ElapsedMilliseconds, verts.Count(), indices.Count() / 3); sw.Restart(); weldVertices(verts, indices, normals); sw.Stop(); UnityEngine.Debug.LogFormat("Vertex welding took {0}ms\n\t {1} vertices left", sw.ElapsedMilliseconds, verts.Count()); var task = MainThreadHelper.instance().scheduleOnMainThread(() => { buffers = new RenderBuffers { vertexBuffer = new ComputeBuffer(verts.Count, sizeof(float) * 3), indexBuffer = new ComputeBuffer(indices.Count, sizeof(int)), normalBuffer = new ComputeBuffer(normals.Count, sizeof(float) * 3), argsBuffer = new ComputeBuffer(4, sizeof(int), ComputeBufferType.IndirectArguments), }; buffers.vertexBuffer.SetData(verts); buffers.indexBuffer.SetData(indices); buffers.normalBuffer.SetData(normals); buffers.argsBuffer.SetData(new int[] { indices.Count, 1, 0, 0 }); }); task.wait(); if (!task.completed) { return(false); } Block = block; return(true); }