// Build voxel object public virtual float Build(Storage voxels, Bounds bounds) { // Check for given array if (voxels != null) { if (!building) { int existingIndex; int x, y, z; // Get iterator if (iterator == null) { iterator = voxels.GetIterator(); currentIndex = 0; currentProgress = 0; } if (colorAssignments == null) { // Create empty list to color assignments to colorAssignments = new Dictionary <Color, int>(); } else { // Get current color index from existing hash map currentIndex = colorAssignments.Count; } // Process voxels in steps for (int number = 0; number < 256; ++number) { // Retrieve color and coordinate for current cell Color color = iterator.GetNextColor(out x, out y, out z); // Check for valid voxel if (color.a > 0) { // Add assignment between color and vertex index, if it is not already included if (!colorAssignments.TryGetValue(color, out existingIndex)) { colorAssignments.Add(color, currentIndex++); } } else { iterator = null; break; } } // Return current progress when building has not been finished if (iterator != null) { return(currentProgress = (float)iterator.Number / (float)(voxels.Count + 1) * 0.5f); } else { building = true; texture = null; } } if (colorAssignments != null) { CoordinateAssignment assignment; int column = 0, line = 0; // Compute resolution to fit all voxels into a 2D surface int textureWidth = (int)Math.Pow(2, Math.Ceiling(Math.Log(Math.Sqrt(colorAssignments.Count)) / Math.Log(2))); int textureHeight = (int)Math.Ceiling((double)colorAssignments.Count / (double)textureWidth); // Make height 2^n, too, if flag is set if (powerOfTwo) { textureHeight = (int)Math.Pow(2, Math.Ceiling(Math.Log((float)textureHeight) / Math.Log(2))); } //// Change resolution, if current does not match the required resolution //if (texture != null && ((texture.width != textureWidth) || (texture.height != textureHeight))) //{ // try // { // texture.Resize(textureWidth, textureHeight, TextureFormat.ARGB32, false); // // Fill texture and calculate texture coordinates // foreach (KeyValuePair<Color, int> currentPixel in colorAssignments) // { // texture.SetPixel(column = currentPixel.Value % texture.width, line = currentPixel.Value / texture.width, currentPixel.Key); // } // iterator = null; // } // catch (System.Exception) // { // texture = null; // } //} if (texture == null) { if (textureWidth != 0 && textureHeight != 0) { // Create new texture instance texture = new UnityEngine.Texture2D(textureWidth, textureHeight, TextureFormat.ARGB32, false); if (texture != null) { texture.filterMode = FilterMode.Point; texture.wrapMode = TextureWrapMode.Clamp; } } iterator = null; } if (texture != null) { // Check for non-empty array if (voxels.Count > 0) { // Get iterator if (iterator == null) { iterator = voxels.GetIterator(); currentIndex = 0; currentProgress = 0; // Create array to store coordinates to coordinateAssignments = new CoordinateAssignment[voxels.Count]; } // Process voxels in steps for (int number = 0; number < texture.width; ++number) { // Retrieve color and coordinate for current cell int index = iterator.Number; Color color = iterator.GetNextColor(out assignment.source.x, out assignment.source.y, out assignment.source.z); // Check for valid voxel if (color.a > 0) { // Get index for current color if (colorAssignments.TryGetValue(color, out currentIndex)) { // Store color as pixel texture.SetPixel(column = currentIndex % texture.width, line = currentIndex / texture.width, color); // Calculate coordinate for center of the current texel assignment.target.x = ((float)column + 0.5f) / (float)texture.width; assignment.target.y = ((float)line + 0.5f) / (float)texture.height; // Store assigned coordinates to array coordinateAssignments[index] = assignment; } } else { iterator = null; break; } } // Return current progress when building has not been finished if (iterator != null) { return(currentProgress = (float)iterator.Number / (float)(voxels.Count + 1) * 0.5f + 0.5f); } // Unset remaining texels for (column = colorAssignments.Count % texture.width, line = colorAssignments.Count / texture.width; line < texture.height; ++line) { for (; column < texture.width; ++column) { texture.SetPixel(column, line, Color.clear); } column = 0; } } } } } // Check for texture and color array if (texture != null) { // Apply color changes on texture texture.Apply(); } // Reset current processing data currentIndex = 0; iterator = null; colorAssignments = null; building = false; return(currentProgress = 1); }
// Build voxel object public virtual float Build(Storage voxels, Bounds bounds) { // Check for given array if (voxels != null) { //if (colorAssignments != null) { // Check for non-empty array if (voxels.Count > 0) { // Get iterator if (iterator == null) { iterator = voxels.GetIterator(); currentProgress = 0; } if (texture == null) { if (superSamplingCount <= 0) { superSamplingCount = 1; } // Calculate target resolution int textureWidth = (voxels.Width + superSamplingCount - 1) / superSamplingCount; int textureHeight = (voxels.Height + superSamplingCount - 1) / superSamplingCount; int textureDepth = (voxels.Depth + superSamplingCount - 1) / superSamplingCount; // Make resolution 2^n, if flag is set if (powerOfTwo) { textureWidth = (int)Math.Pow(2, Math.Ceiling(Math.Log((float)textureWidth) / Math.Log(2))); textureHeight = (int)Math.Pow(2, Math.Ceiling(Math.Log((float)textureHeight) / Math.Log(2))); textureDepth = (int)Math.Pow(2, Math.Ceiling(Math.Log((float)textureDepth) / Math.Log(2))); } if (textureWidth != 0 && textureHeight != 0 && textureDepth != 0) { texels = new Color[textureWidth * textureHeight * textureDepth]; counts = new float[textureWidth * textureHeight * textureDepth]; hdr |= voxels.HasHDR(); // Create new texture instance texture = new UnityEngine.Texture3D(textureWidth, textureHeight, textureDepth, hdr ? TextureFormat.RGBAHalf : TextureFormat.RGBA32, 4); if (texture != null) { //texture.filterMode = FilterMode.Point; texture.wrapMode = TextureWrapMode.Clamp; } } } if (texture != null) { // Process voxels in steps for (int number = 0; number < 10; ++number) { // Retrieve color and coordinate for current cell int x, y, z; Color color = iterator.GetNextColor(out x, out y, out z); // Check for valid voxel if (color.a > 0) { var index = x / superSamplingCount + (y / superSamplingCount + z / superSamplingCount * texture.height) * texture.width; // Store color to texels array texels[index] += color; ++counts[index]; } else { iterator = null; break; } } // Return current progress when building has not been finished if (iterator != null) { return(currentProgress = (float)iterator.Number / (float)(voxels.Count + 1)); } else { // Calculate weight factor for every source cell var samplingFactor = 1f / (superSamplingCount * superSamplingCount * superSamplingCount); // Normalize colors and expand edges or blend with background for (int index = 0; index < texels.Length; ++index) { if (counts[index] > 0) { if (expandEdges) { texels[index].r /= counts[index]; texels[index].g /= counts[index]; texels[index].b /= counts[index]; texels[index].a *= samplingFactor; } else { texels[index] /= counts[index]; texels[index] += backgroundColor * (1 - texels[index].a); } } else { if (!expandEdges) { texels[index] = backgroundColor; } } } if (expandEdges) { bool repeat; do { repeat = false; // Process all cells for (int index = 0; index < texels.Length; ++index) { // Check if current cell is empty if (counts[index] == 0) { var column = index % texture.width; var row = index / texture.width % texture.height; var slice = index / texture.width / texture.height; var color = new Color(0, 0, 0, 0); var count = 0f; // Sum up all colors of direct neighbor cells for (int offset = 0; offset < 6; ++offset) { // Get offset by current index var offsetX = offset == 0 ? -1 : offset == 1 ? 1 : 0; var offsetY = offset == 2 ? -1 : offset == 3 ? 1 : 0; var offsetZ = offset == 4 ? -1 : offset == 5 ? 1 : 0; var offsetColumn = column + offsetX; if (offsetColumn >= 0 && offsetColumn < texture.width) { var offsetRow = row + offsetY; if (offsetRow >= 0 && offsetRow < texture.height) { var offsetSlice = slice + offsetZ; if (offsetSlice >= 0 && offsetSlice < texture.depth) { var offsetIndex = offsetColumn + (offsetRow + offsetSlice * texture.height) * texture.width; // Check if neighbor includes an original color or one that has been set in a previous iteration if (counts[offsetIndex] > 0) { // Sum color components and increase quantity counter for later normalization color += texels[offsetIndex]; ++count; } } } } } if (count > 0) { // Normalize target color but set full transparency texels[index].r = color.r / count; texels[index].g = color.g / count; texels[index].b = color.b / count; texels[index].a = 0; // Flag index as processed in this loop and enable next one counts[index] = -count; repeat = true; } } } // Unset processing flags for next iteration for (int index = 0; index < texels.Length; ++index) { if (counts[index] < 0) { counts[index] = -counts[index]; } } }while (repeat); } // Transfer all texel colors to the texture texture.SetPixels(texels); } } } } } // Check for texture and color array if (texture != null) { // Apply color changes on texture texture.Apply(); } // Reset current processing data iterator = null; return(currentProgress = 1); }