/// <summary> /// Creates a new VoxelBlob from the provided filestream. /// </summary> /// <returns> /// The from file. /// </returns> /// <param name='aFile'> /// A file. /// </param> /// <param name='aCallback'> /// A callback. /// </param> public static IEnumerator NewFromFile(System.IO.FileStream aFile, bool trackVoxelBounds, DeserilizationCompleted aCallback) { VoxelBlob result; using (System.IO.BinaryReader fin = new System.IO.BinaryReader(aFile)) { int width, height, depth; int3 start, end; if (!ReadHeader(fin, out height, out width, out depth, out start, out end)) { aCallback(new VoxelBlob(kTestSize, kTestSize, kTestSize, trackVoxelBounds)); } result = new VoxelBlob(width, height, depth, trackVoxelBounds); for (int aLayer = start.y; aLayer <= end.y; ++aLayer) { for (int aRow = start.z; aRow <= end.z; ++aRow) { for (int aCol = start.x; aCol <= end.x; ++aCol) { result[aCol, aLayer, aRow] = fin.ReadByte(); if (Scheduler.ShouldYield()) { yield return(null); } } } } fin.Close(); } aCallback(result); }
/// <summary> /// Makes a new blob that should strain the chunk regeneration /// </summary> public static VoxelBlob NewFpsTestBlob() { VoxelBlob blob = new VoxelBlob(kTestSize, kTestSize, kTestSize, true); int on = 0; for (int x = 0; x < 300; ++x) { if ((x % 2) == 0) { on = (on + 2) % 4; } for (int y = 0; y < 128; ++y) { if ((y % 2) == 0) { on = (on + 2) % 4; } for (int z = 0; z < 300; ++z) { if (on > 1 && !(x == 17 && z == 17)) { blob[x, y, z] = MeshManager.kVoxelFirstMat; } on = (on + 1) % 4; } } } return(blob); }
public static VoxelBlob NewTestDisc() { VoxelBlob blob = new VoxelBlob(kTestSize, kTestSize, kTestSize, false); int origin = kTestSize / 2; // Disc with ~25mm radius. for (int aLayer = 0; aLayer < 30; ++aLayer) { for (float r = 0; r < 24.85f / kVoxelSizeInMm; ++r) { for (float angle = 0.0f; angle < 90.0f; angle += 0.25f) { float radians = angle * Mathf.Deg2Rad; float x = Mathf.Cos(radians); float y = Mathf.Sin(radians); PlaceRadialBlock(blob, origin + r * x, aLayer, origin + r * y); } } } return(blob); }
public VoxelRegionEnumerator(VoxelBlob aBlob, int aLayer, bool isReverse) { bool isEmpty; int2 minBoundary; int2 maxBoundary; aBlob.GetLayer(aLayer, ref m_layer, out isEmpty, out minBoundary, out maxBoundary); m_width = m_layer.GetLength(0); m_depth = m_layer.GetLength(1); m_region = new VoxelRegion(m_width, m_depth, minBoundary, maxBoundary); m_minVals = minBoundary; m_maxVals = maxBoundary; if (isReverse) { m_x = maxBoundary.x - 1; m_z = maxBoundary.y - 1; DirectedMoveNext = ReverseMoveNext; } else { m_x = minBoundary.x; m_z = minBoundary.y; DirectedMoveNext = ForwardMoveNext; } // Positioned before the first region when created; // <http://msdn.microsoft.com/en-us/library/system.collections.ienumerator.movenext(v=vs.110).aspx> }
public static VoxelBlob NewFromFile(System.IO.FileStream aFile, bool trackVoxelBounds) { VoxelBlob result = null; using (System.IO.BinaryReader fin = new System.IO.BinaryReader(aFile)) { int width, height, depth; int3 start, end; if (!ReadHeader(fin, out height, out width, out depth, out start, out end)) { return(new VoxelBlob(kTestSize, kTestSize, kTestSize, trackVoxelBounds)); } result = new VoxelBlob(width, height, depth, trackVoxelBounds); for (int aLayer = start.y; aLayer <= end.y; ++aLayer) { for (int aRow = start.z; aRow <= end.z; ++aRow) { for (int aCol = start.x; aCol <= end.x; ++aCol) { result[aCol, aLayer, aRow] = fin.ReadByte(); } } } fin.Close(); } return(result); }
public void Apply(MeshManager manager) { VoxelBlob targetData = manager.m_blob; byte newMat = material; material = targetData[width, layer, depth]; targetData[width, layer, depth] = newMat; manager.MarkChunksForRegenForPoint(width, layer, depth); }
public void Update() { if (addBlob) { addBlob = false; VoxelBlob tempBlob = new VoxelBlob(targetVoxelLength, 1, targetVoxelLength, false); myManager.AddVoxelBlob(Convert(tempBlob)); Text.Log("added picture"); } }
static void PlaceRadialBlock(VoxelBlob aBlob, float rawX, int aLayer, float rawZ) { int lowX = Mathf.FloorToInt(rawX); int lowZ = Mathf.FloorToInt(rawZ); aBlob[lowX, aLayer, lowZ] = 1; int highX = Mathf.CeilToInt(rawX); int highZ = Mathf.CeilToInt(rawZ); aBlob[highX, aLayer, highZ] = 1; }
IEnumerator DoApply(MeshManager manager, DeltaDoneDelegate onDone, bool undo) { VoxelBlob targetData = manager.m_blob; foreach (BlobHolder holder in blobs.Values) { if (Scheduler.ShouldYield()) { yield return(null); } VoxelBlob blob = holder.blob; if (holder.unDone == undo) { continue; } for (int x = 0; x < blob.width; ++x) { for (int y = 0; y < blob.height; ++y) { for (int z = 0; z < blob.depth; ++z) { byte newMat = blob[x, y, z]; if (newMat != System.Convert.ToByte(0)) { int dataX = x + (int)blob.position.x; int dataY = y + (int)blob.position.y; int dataZ = z + (int)blob.position.z; byte oldMat = targetData[dataX, dataY, dataZ]; if (oldMat == 0) { oldMat = MeshManager.kVoxelSubtract; } if (newMat == MeshManager.kVoxelSubtract) { newMat = 0; } blob[x, y, z] = oldMat; targetData[dataX, dataY, dataZ] = newMat; manager.MarkChunksForRegenForPoint(dataX, dataY, dataZ); } } } } holder.unDone = undo; } if (onDone != null) { onDone(); } }
/// <summary> /// Returns a voxel blob with the object moved closer /// to the origin. /// </summary> /// <returns> /// Returns a compacted voxel blob. /// </returns> public VoxelBlob CompactBlob() { VoxelBlob compacted = new VoxelBlob(width, depth, height, true); int xMin = minVoxelBounds[0]; int yMin = minVoxelBounds[1]; int zMin = minVoxelBounds[2]; if (xMin < 0 || yMin < 0 || zMin < 0) { return(this); } if (!m_trackVoxelBounds) { xMin = width; yMin = depth; zMin = height; for (int x = 0; x < width; ++x) { for (int y = 0; y < depth; ++y) { for (int z = 0; z < height; ++z) { int block = this[x, y, z]; if (block > 0) { xMin = Mathf.Min(x, xMin); yMin = Mathf.Min(y, yMin); zMin = Mathf.Min(z, zMin); } } // end z for } // end y for } // end x for } for (int x = xMin; x < width; ++x) { for (int y = yMin; y < depth; ++y) { for (int z = zMin; z < height; ++z) { compacted[x - xMin, y - yMin, z - zMin] = this[x, y, z]; } } } compacted.position = new Vector3(xMin, yMin, zMin); return(compacted); }
void Awake() { Dispatcher.AddListener(MenuController.kEventNewBlob, ClearMeshes); m_trans = transform; m_cameraTrans = Camera.main.transform; m_deltaFuture = new Stack <IDelta>(); m_deltaHistory = new Stack <IDelta>(); m_enabledMeshes = new List <VoxelMesh>(); if (useTestBlob) { m_blob = VoxelBlob.NewTestDisc(); } else if (useFpsTestBlob) { m_blob = VoxelBlob.NewFpsTestBlob(); } else { m_blob = new VoxelBlob(VoxelBlob.kTestSize, VoxelBlob.kTestSize, VoxelBlob.kTestSize, true); } string[] launchArguments = System.Environment.GetCommandLineArgs(); if (launchArguments != null) { for (int i = launchArguments.Length - 1; i > -1; i--) { if (launchArguments[i].Contains(".radiant") || launchArguments[i].Contains(".Radiant")) { if (System.IO.File.Exists(launchArguments[i])) { Dispatcher <string> .Broadcast(MenuController.kEventLoadScene, launchArguments[i]); i = -1; } } } } m_colliderCache = new BoxCollider[kColliderCacheDim * kColliderCacheDim * kColliderCacheDim]; m_chunkPositionCurrent = WorldToChunk(m_cameraTrans.position); // NOTE: When we load data in the future, we'll need to find a suitable // location for the player. CreateCollisionCache(); Scheduler.StartCoroutine(LoadVisualChunks()); Scheduler.StartCoroutine(UpdateVisualChunks()); Dispatcher.Broadcast(kOnForceRefresh); }
public IEnumerator GenerateSupport(byte support, VoxelBlob source) { System.Array.Copy(source.m_data, m_data, source.m_data.Length); for (int x = 0; x < width; ++x) { int minX = Mathf.Max(0, x - 1); int maxX = Mathf.Min(width - 1, x + 1); for (int z = 0; z < depth; ++z) { int minZ = Mathf.Max(0, z - 1); int maxZ = Mathf.Min(depth - 1, z + 1); bool isBlockPresent = this[x, height - 1, z] != 0; for (int y = height - 2; y >= 0; --y) { if (!isBlockPresent) { isBlockPresent = this[x, y, z] != 0; continue; } // First pass: Generate support under each block. if (this[minX, y, minZ] == 0 && this[minX, y, minZ] == 0 && this[minX, y, z] == 0 && this[minX, y, maxZ] == 0 && this[x, y, minZ] == 0 && this[x, y, z] == 0 && this[x, y, maxZ] == 0 && this[maxX, y, minZ] == 0 && this[maxX, y, z] == 0 && this[maxX, y, maxZ] == 0) { this[x, y, z] = support; } } if (Scheduler.ShouldYield()) { yield return(null); } } } }
/// <summary> /// Coalesce all of the blobs into one blob. /// </summary> public VoxelBlob MakeSingleBlob() { //find our bounds Vector3 lowerBound = Vector3.one * float.MaxValue; Vector3 upperBound = Vector3.one * float.MinValue; foreach (BlobHolder holder in blobs.Values) { VoxelBlob blob = holder.blob; int3 size = blob.size; for (int i = 0; i < 3; ++i) { lowerBound[i] = Mathf.Min(lowerBound[i], blob.position[i]); upperBound[i] = Mathf.Max(upperBound[i], blob.position[i] + size[i]); } } Vector3 blobSize = upperBound - lowerBound; VoxelBlob target = new VoxelBlob((int)blobSize[0], (int)blobSize[1], (int)blobSize[2], false); target.position = lowerBound; foreach (BlobHolder holder in blobs.Values) { VoxelBlob blob = holder.blob; Vector3 offset = blob.position - target.position; for (int x = 0; x < blob.width; ++x) { for (int y = 0; y < blob.height; ++y) { for (int z = 0; z < blob.depth; ++z) { target[x + (int)offset.x, y + (int)offset.y, z + (int)offset.z] = blob[x, y, z]; } } } } return(target); }
public byte this[int x, int y, int z] { set { int3 chunk = new int3(x, y, z) / blobSize; chunk *= blobSize; //if we already have that chunk, assign to that, otherwise create a new one VoxelBlob blob; if (blobs.ContainsKey(chunk)) { blob = blobs[chunk].blob; } else { blob = new VoxelBlob(blobSize, blobSize, blobSize, false); blob.position = new Vector3(chunk.x, chunk.y, chunk.z); blobs.Add(chunk, new BlobHolder(blob)); } blob[x - chunk.x, y - chunk.y, z - chunk.z] = value; } }
public VoxelBlob Convert(VoxelBlob aPart) { float minLength = Mathf.Min(image.width, image.height); int conversionFactor = Mathf.FloorToInt((float)minLength / (float)targetVoxelLength); int voxelCount = 0; for (int aRow = 0; aRow < targetVoxelLength; ++aRow) { for (int aCol = 0; aCol < targetVoxelLength; ++aCol) { Color sourceColor = image.GetPixel(aCol * conversionFactor, aRow * conversionFactor); if (sourceColor.r > redCutoff && sourceColor.g > greenCutoff && sourceColor.b > blueCutoff && sourceColor.a > alphaCutoff) { //Text.Log("A row = " + aRow + " a col = " + aCol); //Text.Log(aPart[aRow,0,0]); voxelCount++; aPart[aRow, 0, aCol] = 1; } } } Text.Log("Created this many voxels from the picture " + voxelCount); return(aPart); }
public static VoxelBlob NewExtrusionBlob() { VoxelBlob blob = new VoxelBlob(kTestSize, kTestSize, kTestSize, true); int origin = kTestSize / 2; for (int aLayer = 0; aLayer < 20; ++aLayer) { for (float r = 45 / kVoxelSizeInMm; r < 70 / kVoxelSizeInMm; ++r) { for (float angle = -45; angle <= 45.0f; angle += 0.25f) { float radians = angle * Mathf.Deg2Rad; float x = Mathf.Cos(radians); float y = Mathf.Sin(radians); PlaceRadialBlock(blob, origin + r * x, aLayer, origin + r * y); PlaceRadialBlock(blob, Mathf.Floor(origin + r * Mathf.Cos(75.0f * Mathf.Deg2Rad)), aLayer, Mathf.Floor(origin + r * Mathf.Sin(75.0f * Mathf.Deg2Rad))); PlaceRadialBlock(blob, Mathf.Floor(origin + r * Mathf.Cos(-75.0f * Mathf.Deg2Rad)), aLayer, Mathf.Floor(origin + r * Mathf.Sin(-75.0f * Mathf.Deg2Rad))); } } } return(blob); }
const int kTestBlockSize = 150; //150; /// <summary> /// Returns a test blob of the default test size. /// </summary> /// <returns> /// The test BLOB. /// </returns> public static VoxelBlob NewTestBlob() { VoxelBlob blob = new VoxelBlob(kTestSize, kTestSize, kTestSize, true); // A 20x20 square centered at the platform origin // for kTestSize = 100. int start = (kTestSize - kTestBlockSize) / 2; // -> 145.5 int spaceStart = (kTestBlockSize / 2) - 1 + start; int spaceEnd = spaceStart + 0; /*for (int aLayer = 0; aLayer < blob.height; ++aLayer) { * for (int aRow = 0; aRow < blob.width; ++aRow) { * for (int aCol = 0; aCol < blob.depth; ++aCol) { * blob[aRow, aLayer, aCol] = 1; * } * } * }*/ for (int aLayer = 2; aLayer < 4; ++aLayer) { for (int aRow = start; aRow < start + kTestBlockSize; ++aRow) { //for (int aRow = (kTestSize - 15) / 2; aRow < (kTestSize - 15) / 2 + 30; ++aRow) { for (int aCol = start; aCol < start + kTestBlockSize; ++aCol) { // Uncomment for a split square. if (aCol < spaceStart || aCol > spaceEnd || aRow % 2 == 0) { blob[aCol, aLayer, aRow] = 1; } } } } return(blob); }
IEnumerator SetVoxelsInBlob(byte threshold, VoxelBlob blob, byte[,,] data, byte[,,] debugData) { for (int x = scanVolumeStart.x; x < scanVolumeEnd.x; ++x) { for (int y = scanVolumeStart.y; y < scanVolumeEnd.y; ++y) { for (int z = scanVolumeStart.z; z < scanVolumeEnd.z; ++z) { if (data[x, y, z] <= threshold) { blob[x, y, z] = 1; } else { blob[x, y, z] = 0; } } } if (Scheduler.ShouldYield()) { yield return(null); } } }
public void SaveStlFromBlob(VoxelBlob blob, System.IO.Stream aStream, bool shouldClose) { Scheduler.StartCoroutine(GenFacesFromBlob(blob), this); Scheduler.StartCoroutine(WriteStlBinaryToStream(aStream, shouldClose), this); }
public VoxelSurfaceEnumerator(VoxelBlob aBlob, VoxelRegion sourceRegion, int voxelLayer, int printLayer, float layerHeight, bool isReverse) { // We don't want to surface the first layer, we want 100% infill instead. if (printLayer == 0) { DirectedMoveNext = Empty; return; } float logicalHeight = Mathf.Repeat(printLayer * layerHeight, VoxelBlob.kVoxelSizeInMm); if (!(Mathf.Approximately(logicalHeight, 0) || Mathf.Approximately(logicalHeight + layerHeight, VoxelBlob.kVoxelSizeInMm))) { // We're neither at the bottom of a voxel nor // at the top, so we don't care about surfacing. DirectedMoveNext = Empty; return; } // NOTE: Caching the information means that we're not thread safe! if (m_width != aBlob.width || m_depth != aBlob.depth) { m_currentLayer = new byte[aBlob.width, aBlob.depth]; m_checkLayer = new byte[aBlob.width, aBlob.depth]; m_otherCheckLayer = new byte[aBlob.width, aBlob.depth]; } bool isEmpty; bool checkedFirstLayer = false; // Grab the adjacent layers to check for space. if (Mathf.Approximately(logicalHeight, 0.0f) && voxelLayer > 0) { // At the bottom of a voxel, so we need to check the lower layer. aBlob.GetLayer(voxelLayer - 1, ref m_checkLayer, out isEmpty, out m_minVals, out m_maxVals); checkedFirstLayer = true; } if (Mathf.Approximately(logicalHeight + layerHeight, VoxelBlob.kVoxelSizeInMm) && voxelLayer + 1 < aBlob.height) { if (!checkedFirstLayer) { aBlob.GetLayer(voxelLayer + 1, ref m_checkLayer, out isEmpty, out m_minVals, out m_maxVals); } else { aBlob.GetLayer(voxelLayer + 1, ref m_otherCheckLayer, out isEmpty, out m_minVals, out m_maxVals); for (int x = m_minVals.x; x <= m_maxVals.x; x++) { for (int y = m_minVals.y; y <= m_maxVals.y; y++) { m_checkLayer[x, y] = (byte)Mathf.Min(m_checkLayer[x, y], m_otherCheckLayer[x, y]); } } } } // Grab the current layer for later comparison. aBlob.GetLayer(voxelLayer, ref m_currentLayer, out isEmpty, out m_minVals, out m_maxVals); if (isEmpty) { DirectedMoveNext = Empty; return; } m_width = m_checkLayer.GetLength(0); m_depth = m_checkLayer.GetLength(1); m_region = new VoxelRegion(m_width, m_depth, m_minVals, m_maxVals); m_sourceRegion = sourceRegion; if (isReverse) { // This means we're actually within a voxel, and so we // shouldn't do anything. m_x = m_maxVals.x - 1; m_z = m_maxVals.y - 1; DirectedMoveNext = ReverseMoveNext; } else { m_x = m_minVals.x; m_z = m_minVals.y; DirectedMoveNext = ForwardMoveNext; } // Positioned before the first region when created; // <http://msdn.microsoft.com/en-us/library/system.collections.ienumerator.movenext(v=vs.110).aspx> }
void LoadComplete(VoxelBlob loadedBlob) { }
void NormalMenu() { float yInitial = (Screen.height - (kButtonHeight + kMargin) * 6) / 2.0f; Rect buttonRect = new Rect((Screen.width - kButtonWidth) / 4.0f, yInitial, kButtonWidth, kButtonHeight); // Left column //////////////////////////////////////////////////////// if (GUI.Button(buttonRect, m_workingPrinter.isAwake ? "Sleep" : "Wake")) { if (!m_workingPrinter.isAwake) { pc.WakePrinter(m_workingPrinter); } else { pc.SleepPrinter(m_workingPrinter); } } buttonRect.y += kButtonHeight + kMargin; if (GUI.Button(buttonRect, "Print Test")) { // Print pc.SchedulePrint(VoxelBlob.NewTestDisc()); HandleMenu = PrintingMenu; Dispatcher <float> .AddListener(PrinterController.kOnPrintingProgress, OnPrintingProgress); } buttonRect.y += kButtonHeight + kMargin; if (GUI.Button(buttonRect, @"Print Test Scene")) { string filePath; string[] extensions = new string[] { "radiant" }; string[] extensionNames = new string[] { "Radiant scene" }; if (FileDialogs.ShowOpenFileDialog(out filePath, extensions, extensionNames)) { System.IO.FileStream stream = new System.IO.FileStream(filePath, System.IO.FileMode.Open); VoxelBlob blob = VoxelBlob.NewFromFile(stream, false); pc.SchedulePrint(blob); HandleMenu = PrintingMenu; Dispatcher <float> .AddListener(PrinterController.kOnPrintingProgress, OnPrintingProgress); } else { Text.Log(@"Aborted opening."); } } /* * buttonRect.y += kButtonHeight + kMargin; * if (GUI.Button(buttonRect, "Request Token Test")) { * StartCoroutine(OAuth1.GetRequestToken(ExternalSite.ShapeWays, RequestResponse)); * HandleMenu = AuthorizationMenu; * } */ /* * GUI.enabled = !m_isSaved; * buttonRect.y += kButtonHeight + kMargin; * if (GUI.Button(buttonRect, "Save")) { * string filePath = NativePanels.SaveFileDialog("model.radiant", "radiant"); * SaveBlob(filePath); * Text.Log("Saved " + filePath); * m_isSaved = true; * Dispatcher<Sfx>.Broadcast(AudioManager.kPlaySfx, Sfx.Select); * } * * GUI.enabled = true; * buttonRect.y += kButtonHeight + kMargin; * if (GUI.Button(buttonRect, "Load")) { * //PlayerPrefs.SetString(VoxelBlob.kSerializedKey, serializedBlob); * string filePath = NativePanels.OpenFileDialog(new string[]{"radiant"}); * LoadBlob(filePath); * m_isSaved = true; * Dispatcher<Sfx>.Broadcast(AudioManager.kPlaySfx, Sfx.Select); * } */ // Right column /////////////////////////////////////////////////////// buttonRect.x = (Screen.width - kButtonWidth) * 0.75f; buttonRect.y = yInitial; buttonRect.height = kButtonHeight; buttonRect.width = kButtonWidth / 3.0f; buttonRect.x += buttonRect.width + kMargin; if (GUI.Button(buttonRect, "^")) { pc.BeginMotorChanges(m_workingPrinter); pc.MoveVerticallyBy(-10.0f, Change.Execute); pc.EndMotorChanges(); } buttonRect.y += kButtonHeight + kMargin; buttonRect.x = buttonRect.x - buttonRect.width - kMargin; if (GUI.Button(buttonRect, "<")) { pc.BeginMotorChanges(m_workingPrinter); pc.MoveHorizontallyBy(10.0f, Change.Execute); pc.EndMotorChanges(); } buttonRect.x += buttonRect.width + kMargin; if (GUI.Button(buttonRect, "v")) { pc.BeginMotorChanges(m_workingPrinter); pc.MoveVerticallyBy(10.0f, Change.Execute); pc.EndMotorChanges(); } buttonRect.x += buttonRect.width + kMargin; if (GUI.Button(buttonRect, ">")) { pc.BeginMotorChanges(m_workingPrinter); pc.MoveHorizontallyBy(-10.0f, Change.Execute); pc.EndMotorChanges(); } }
public void SaveStlFromBlob(VoxelBlob blob, string fileName) { Scheduler.StartCoroutine(GenFacesFromBlob(blob), this); Scheduler.StartCoroutine(WriteStlBinary(fileName), this); }
public void InitFromBlob(VoxelBlob blob) { Scheduler.StartCoroutine(GenFacesFromBlob(blob), this); }
byte VoxelAt(int x, int y, int z, VoxelBlob blob) { return(blob[x + position.x, y + position.y, z + position.z]); }
public BlobHolder(VoxelBlob blob) { this.blob = blob; unDone = false; }
byte VoxelAt(int3 pos, VoxelBlob blob) { return(VoxelAt(pos.x, pos.y, pos.z, blob)); }
IEnumerator GenFacesFromBlob(VoxelBlob blob) { float currentProgress = 0; float maxProgress = blob.width * blob.height * blob.depth; loadProgress = 0; faces = new List <Face>(); for (int x = 0; x < blob.width; ++x) { for (int y = 0; y < blob.height; ++y) { for (int z = 0; z < blob.depth; ++z) { if (Scheduler.ShouldYield()) { yield return(null); } if (blob[x, y, z] == MeshManager.kVoxelEmpty) { continue; } //figure out if each face is a surface face Vector3 block = new Vector3(x, y, z); for (int dim = 0; dim < 3; ++dim) { for (int dir = -1; dir < 2; dir += 2) { Vector3 neighbor = block; neighbor[dim] += dir; bool onSurface = true; if (blob.IsValidPoint((int)neighbor.x, (int)neighbor.y, (int)neighbor.z) && blob[(int)neighbor.x, (int)neighbor.y, (int)neighbor.z] != MeshManager.kVoxelEmpty) { onSurface = false; } if (onSurface) { int axis1 = (dir < 0 ? (dim + 2) % 3 : (dim + 1) % 3); int axis2 = (dir < 0 ? (dim + 1) % 3 : (dim + 2) % 3); Vector3 p0; if (dir < 0) { p0 = block; } else { p0 = block + Vector3.one; } Vector3 p1 = p0; p1[axis1] -= dir; Vector3 p2 = p0; p2[axis2] -= dir; Face face = new Face(p0, p1, p2); face.Init(); faces.Add(face); Vector3 p3 = p1; p3[axis2] -= dir; face = new Face(p3, p2, p1); face.Init(); faces.Add(face); } } } } } currentProgress += blob.height * blob.depth; loadProgress = currentProgress / maxProgress; } MoveFacesToOrigin(); m_loaded = true; }
/// <summary> /// Builds the chunk's mesh. /// </summary> public void RegenerateVisualMesh(float aVoxelScale) { //float startTime = Time.realtimeSinceStartup; VoxelBlob blob = manager.m_blob; int3 blobSize = blob.size; if (sm_regenInUse) { Debug.Log("Somehow calling two regens at the same time"); //throw new System.Exception("Cannot run two RegenerateVisualMesh at the same time. If needed, make more static RegenData"); return; } sm_regenInUse = true; sm_regenData.Clear(); needsRegen = false; int chunkSize = manager.chunkSize; for (int i = 0; i < 6; ++i) { m_hasBuild[0][i] = false; m_hasWater[i] = false; m_hasPattern[i] = false; } m_mesh.Clear(); m_mesh.subMeshCount = kSubMeshCount; int3 currVoxel = new int3(); bool hasFaces = false; int3 maxVals = blobSize - position; for (int i = 0; i < 3; ++i) { maxVals[i] = Mathf.Min(maxVals[i], chunkSize); } //Debug.Log("Starting main block"); for (int z = 0; z < maxVals.z && z + position.z < blobSize.z; z += 2) { for (int y = 0; y < maxVals.y && y + position.y < blobSize.y; y += 2) { for (int x = 0; x < maxVals.x && x + position.x < blobSize.x; x += 2) { currVoxel.x = x; currVoxel.y = y; currVoxel.z = z; int2[][] buildIndex = new int2[kNumBuildMats][]; for (int i = 0; i < kNumBuildMats; ++i) { buildIndex[i] = new int2[6]; } int2[] waterIndex = new int2[6]; int2[] patternIndex = new int2[6]; byte voxel; for (int i = 0; i < 2 && x + i + position.x < blobSize.x; ++i) { for (int j = 0; j < 2 && y + j + position.y < blobSize.y; ++j) { for (int k = 0; k < 2 && z + k + position.z < blobSize.z; ++k) { int3 curr = new int3(currVoxel.x + i, currVoxel.y + j, currVoxel.z + k); voxel = VoxelAt(curr, blob); if (voxel != 0) { int2[] voxelIndex = null; switch (voxel) { case MeshManager.kVoxelWater: voxelIndex = waterIndex; break; case MeshManager.kVoxelObjectDef: voxelIndex = patternIndex; break; default: voxelIndex = buildIndex[(int)(voxel - MeshManager.kVoxelFirstMat)]; break; } if (curr.x + position.x == 0 || VoxelAt(curr.x - 1, curr.y, curr.z, blob) == 0) { voxelIndex[0][i] += (1 << (j * 2 + k)); } if (curr.x + position.x == blobSize.x - 1 || VoxelAt(curr.x + 1, curr.y, curr.z, blob) == 0) { voxelIndex[1][i] += (1 << (j * 2 + k)); } if (curr.y + position.y == 0 || VoxelAt(curr.x, curr.y - 1, curr.z, blob) == 0) { voxelIndex[2][j] += (1 << (k * 2 + i)); } if (curr.y + position.y == blobSize.y - 1 || VoxelAt(curr.x, curr.y + 1, curr.z, blob) == 0) { voxelIndex[3][j] += (1 << (k * 2 + i)); } if (curr.z + position.z == 0 || VoxelAt(curr.x, curr.y, curr.z - 1, blob) == 0) { voxelIndex[4][k] += (1 << (i * 2 + j)); } if (curr.z + position.z == blobSize.z - 1 || VoxelAt(curr.x, curr.y, curr.z + 1, blob) == 0) { voxelIndex[5][k] += (1 << (i * 2 + j)); } } } } } for (int i = 0; i < kNumBuildMats; ++i) { GenNegXFaces(currVoxel, ref hasFaces, m_hasBuild[i], buildIndex[i], m_buildOffsets[i]); GenPosXFaces(currVoxel, ref hasFaces, m_hasBuild[i], buildIndex[i], m_buildOffsets[i]); GenNegYFaces(currVoxel, ref hasFaces, m_hasBuild[i], buildIndex[i], m_buildOffsets[i]); GenPosYFaces(currVoxel, ref hasFaces, m_hasBuild[i], buildIndex[i], m_buildOffsets[i]); GenNegZFaces(currVoxel, ref hasFaces, m_hasBuild[i], buildIndex[i], m_buildOffsets[i]); GenPosZFaces(currVoxel, ref hasFaces, m_hasBuild[i], buildIndex[i], m_buildOffsets[i]); } GenNegXFaces(currVoxel, ref hasFaces, m_hasWater, waterIndex, kWaterOffset); GenNegXFaces(currVoxel, ref hasFaces, m_hasPattern, patternIndex, kPatternOffset); GenPosXFaces(currVoxel, ref hasFaces, m_hasWater, waterIndex, kWaterOffset); GenPosXFaces(currVoxel, ref hasFaces, m_hasPattern, patternIndex, kPatternOffset); GenNegYFaces(currVoxel, ref hasFaces, m_hasWater, waterIndex, kWaterOffset); GenNegYFaces(currVoxel, ref hasFaces, m_hasPattern, patternIndex, kPatternOffset); GenPosYFaces(currVoxel, ref hasFaces, m_hasWater, waterIndex, kWaterOffset); GenPosYFaces(currVoxel, ref hasFaces, m_hasPattern, patternIndex, kPatternOffset); GenNegZFaces(currVoxel, ref hasFaces, m_hasWater, waterIndex, kWaterOffset); GenNegZFaces(currVoxel, ref hasFaces, m_hasPattern, patternIndex, kPatternOffset); GenPosZFaces(currVoxel, ref hasFaces, m_hasWater, waterIndex, kWaterOffset); GenPosZFaces(currVoxel, ref hasFaces, m_hasPattern, patternIndex, kPatternOffset); } } } //Debug.Log("Finished main block"); if (!hasFaces) { sm_regenInUse = false; return; } m_mesh.name = "Visual Mesh"; m_mesh.vertices = sm_regenData.verts.ToArray(); for (int i = 0; i < kSubMeshCount; ++i) { if (sm_regenData.tris[i].Count > 0) { m_mesh.SetTriangles(sm_regenData.tris[i].ToArray(), i); } } if (m_mesh.vertexCount > 0) { manager.EnableMesh(this); } else { manager.DisableMesh(this); } m_mesh.Optimize(); sm_regenInUse = false; }
IEnumerator GenColorFacesFromBlob(VoxelBlob blob) { float currentProgress = 0; float maxProgress = blob.width * blob.height * blob.depth; loadProgress = 0; int3 minVals = new int3(0, 0, 0); int3 maxVals = new int3(blob.width, blob.height, blob.depth); if (blob.minVoxelBounds.x != -1) { minVals = blob.minVoxelBounds; maxVals = blob.maxVoxelBounds; } multicolorFaces = new List <List <Face> >(); for (int mat = 1; mat < 5; mat++) { faces = new List <Face>(); for (int x = minVals.x; x < maxVals.x; ++x) { for (int y = minVals.y; y < maxVals.y; ++y) { for (int z = minVals.z; z < maxVals.z; ++z) { if (Scheduler.ShouldYield()) { yield return(null); } if (blob[x, y, z] != mat) { continue; } //figure out if each face is a surface face Vector3 block = new Vector3(x, y, z); for (int dim = 0; dim < 3; ++dim) { for (int dir = -1; dir < 2; dir += 2) { Vector3 neighbor = block; neighbor[dim] += dir; bool onSurface = true; if (blob.IsValidPoint((int)neighbor.x, (int)neighbor.y, (int)neighbor.z) && blob[(int)neighbor.x, (int)neighbor.y, (int)neighbor.z] == mat) { onSurface = false; } if (onSurface) { int axis1 = (dir < 0 ? (dim + 2) % 3 : (dim + 1) % 3); int axis2 = (dir < 0 ? (dim + 1) % 3 : (dim + 2) % 3); Vector3 p0; if (dir < 0) { p0 = block; } else { p0 = block + Vector3.one; } Vector3 p1 = p0; p1[axis1] -= dir; Vector3 p2 = p0; p2[axis2] -= dir; Face face = new Face(p0, p1, p2); face.Init(); faces.Add(face); Vector3 p3 = p1; p3[axis2] -= dir; face = new Face(p3, p2, p1); face.Init(); faces.Add(face); } } } } } currentProgress += blob.height * blob.depth; loadProgress = currentProgress / maxProgress; } multicolorFaces.Add(faces); } m_loaded = true; }