Example #1
0
        // Build voxel object
        public override float Build(Storage voxels, Bounds bounds, Informer informer, object parameter)
        {
            // Check for given array
            if (voxels != null)
            {
                GameObject subContainer;
                int        width = voxels.Width;
                int        height = voxels.Height;
                int        depth = voxels.Depth;
                int        sides = voxels.FacesCount;
                int        x, y, z;

                // Check for non-empty array
                if (width * height * depth * sides > 0)
                {
                    if (mainContainer == null)
                    {
                        // Check if texture is required
                        if (mainTextureTarget || emissiveTextureTarget)
                        {
                            // Create voxel texture, if required
                            if (voxelTexture2D == null)
                            {
                                voxelTexture2D = new Texture2D.Process();
                            }

                            // Build texture
                            if (voxelTexture2D != null && voxelTexture2D.CurrentProgress < 1)
                            {
                                return(voxelTexture2D.Build(voxels, bounds) * 0.5f);
                            }
                        }
                        else
                        {
                            voxelTexture2D = null;
                        }

                        // Get iterator
                        iterator = voxels.GetIterator();

                        // Create empty game object
                        mainContainer = new GameObject(targetName);
                        if (mainContainer != null)
                        {
                            // Hide new container
                            mainContainer.hideFlags |= HideFlags.HideAndDontSave;

                            // Create empty list to store groups to
                            groups = new Dictionary <Material, GameObject>();

                            // Create empty list to store mesh data interfaces to
                            meshDataInterfaces       = new List <IMeshData>();
                            currentMeshDataInterface = 0;

                            // Copy position from source object
                            mainContainer.transform.position = gameObject.transform.position;

                            // Copy static flag
                            mainContainer.isStatic = staticContainers;

                            // Calculate total scaling for one block
                            globalScaling = new Vector3(2.0f * bounds.extents.x / (float)width, 2.0f * bounds.extents.y / (float)height, 2.0f * bounds.extents.z / (float)depth);

                            // Check for given mesh
                            if (mesh != null)
                            {
                                // Calculate offset and scaling for one voxel mesh
                                offset     = -mesh.bounds.center;
                                scaling.x  = 0.5f / mesh.bounds.extents.x;
                                scaling.y  = 0.5f / mesh.bounds.extents.y;
                                scaling.z  = 0.5f / mesh.bounds.extents.z;
                                offset.x  *= scaling.x;
                                offset.y  *= scaling.y;
                                offset.z  *= scaling.z;
                                scaling.x *= globalScaling.x;
                                scaling.y *= globalScaling.y;
                                scaling.z *= globalScaling.z;
                            }
                            else
                            {
                                // Unset translation und scaling
                                offset  = Vector3.zero;
                                scaling = Vector3.one;
                            }

                            // Add offset for half voxel
                            offset += new Vector3(0.5f * globalScaling.x, 0.5f * globalScaling.y, 0.5f * globalScaling.z);

                            // Move to match position of the original object
                            offset += bounds.center - gameObject.transform.position - bounds.extents;
                        }
                    }

                    // Check for main container and voxel iterator
                    if (mainContainer != null && iterator != null)
                    {
                        // Process voxels in steps
                        for (int number = 0; number < 10; ++number)
                        {
                            // Retrieve material for current coordinate
                            int      iteratorIndex = iterator.Number;
                            Color    color;
                            Material material = iterator.GetNextMaterial(out color, out x, out y, out z);

                            // Check for valid voxel
                            if (material != null)
                            {
                                //// Replace material, if texture template is set
                                //if (textureMaterialTemplate != null && voxelTexture != null)
                                //{
                                //    material = textureMaterialTemplate;
                                //    material.SetTexture("_VoxelTex", voxelTexture.target);
                                //}

                                // Check for existing material groups
                                if (groups != null)
                                {
                                    // Check for new group
                                    if (!groups.TryGetValue(material, out subContainer) || (subContainer == null))
                                    {
                                        // Create empty game object
                                        subContainer = new GameObject(material.name == null || material.name.Length == 0 ? (groups.Count + 1).ToString() : material.name);
                                        if (subContainer != null)
                                        {
                                            // Attach it to this main object
                                            subContainer.transform.parent = mainContainer.transform;

                                            // Unset local transformation
                                            subContainer.transform.localPosition = Vector3.zero;
                                            subContainer.transform.localScale    = Vector3.one;
                                            subContainer.transform.localRotation = Quaternion.identity;

                                            // Copy static flag
                                            subContainer.isStatic = staticContainers;

                                            // Set layer number by transparency property
                                            if (material.HasProperty("_Color"))
                                            {
                                                if (material.color.a < 1)
                                                {
                                                    subContainer.layer = 1;
                                                }
                                                else
                                                {
                                                    subContainer.layer = 0;
                                                }
                                            }

                                            try
                                            {
                                                // Add group to list
                                                groups.Add(material, subContainer);
                                            }
                                            catch (System.Exception exception)
                                            {
                                                Debug.Log(exception.Message);
                                            }
                                        }
                                    }
                                }
                                else
                                {
                                    // Unset container for first material
                                    subContainer = null;
                                }

                                // Calculate current voxel position
                                Vector3 currentPosition = new Vector3((float)x * globalScaling.x + offset.x, (float)y * globalScaling.y + offset.y, (float)z * globalScaling.z + offset.z);

                                // material container as parent for the current voxel
                                GameObject parent = subContainer;

                                // Create empty game object
                                if (containerTemplate != null)
                                {
                                    subContainer = Instantiate(containerTemplate);
                                }
                                else
                                {
                                    subContainer = new GameObject();
                                }
                                if (subContainer != null)
                                {
                                    // Change name of the voxel container to current coordinate
                                    subContainer.name = x.ToString() + ", " + y.ToString() + ", " + z.ToString();

                                    if (parent != null)
                                    {
                                        // Attach it to material container
                                        subContainer.transform.parent = parent.transform;
                                    }
                                    else
                                    {
                                        // Attach it to main object
                                        subContainer.transform.parent = mainContainer.transform;
                                    }

                                    // Set transformation to position and scale current cell
                                    subContainer.transform.localPosition = currentPosition;
                                    subContainer.transform.localScale    = scaling * sizeFactor;
                                    subContainer.transform.localRotation = Quaternion.identity;

                                    // Copy static flag
                                    if (containerTemplate == null)
                                    {
                                        subContainer.isStatic = staticContainers;
                                    }

                                    // Set layer number by transparency property
                                    if (material.HasProperty("_Color"))
                                    {
                                        if (material.color.a < 1)
                                        {
                                            subContainer.layer = 1;
                                        }
                                        else
                                        {
                                            subContainer.layer = 0;
                                        }
                                    }

                                    // Check for valid mesh
                                    if (mesh != null)
                                    {
                                        // Add mesh filter
                                        MeshFilter meshFilter = subContainer.AddComponent <MeshFilter>();
                                        if (meshFilter != null)
                                        {
                                            // Apply specified mesh as shared one for the sub container
                                            meshFilter.sharedMesh = mesh;

                                            // Check for vertex color utilization
                                            if (vertexColors)
                                            {
                                                // Create new array, if size does not match
                                                if (colors == null || colors.Length != mesh.vertexCount)
                                                {
                                                    colors    = new Color[mesh.vertexCount];
                                                    lastColor = colors[0];
                                                }

                                                // Fill and apply new vertex colors array
                                                if (colors != null)
                                                {
                                                    if (lastColor != color)
                                                    {
                                                        for (int index = 0; index < colors.Length; ++index)
                                                        {
                                                            colors[index] = color;
                                                        }
                                                        lastColor = color;
                                                    }

                                                    meshFilter.mesh.colors = colors;
                                                }
                                            }

                                            // Check for existing voxel map
                                            if (voxelTexture2D != null)
                                            {
                                                // Retrieve texture coordinate for current voxel
                                                Vector2 textureCoordinate = voxelTexture2D.GetTextureCoordinate(voxels, iteratorIndex);
                                                if (!float.IsNaN(textureCoordinate.x))
                                                {
                                                    //// Encode iterator index into texture coordinate
                                                    //textureCoordinate.x += (float)iteratorIndex;

                                                    // Create new array, if size does not match
                                                    if (textureCoordinates == null || textureCoordinates.Length != mesh.vertexCount)
                                                    {
                                                        textureCoordinates = new Vector2[mesh.vertexCount];
                                                    }

                                                    // Fill and apply new UV coordinates array
                                                    if (textureCoordinates != null)
                                                    {
                                                        for (int index = 0; index < textureCoordinates.Length; ++index)
                                                        {
                                                            textureCoordinates[index] = textureCoordinate;
                                                        }

                                                        meshFilter.mesh.uv = textureCoordinates;
                                                    }

                                                    //Debug.Log(textureCoordinate);

                                                    // Apply texture to material
                                                    if (mainTextureTarget)
                                                    {
                                                        material.SetTexture("_MainTex", voxelTexture2D.Texture);
                                                    }
                                                    if (emissiveTextureTarget)
                                                    {
                                                        material.SetTexture("_EmissionMap", voxelTexture2D.Texture);
                                                    }
                                                }
                                            }

                                            //// Check for active volume texture
                                            //if (voxelTexture != null && voxelTexture.target != null)
                                            //{
                                            //    // Instantiate mesh
                                            //    Mesh newMesh = meshFilter.mesh;

                                            //    // Compute texture coordinate center for current voxel
                                            //    Vector3 textureCoordinate = new Vector3((x + 0.5f) / (float)voxelTexture.target.width, (y + 0.5f) / (float)voxelTexture.target.height, (z + 0.5f) / (float)voxelTexture.target.depth);

                                            //    // Fill list of UVs for every vertex
                                            //    List<Vector3> textureCoordinates = new List<Vector3>(newMesh.vertexCount);
                                            //    for (int vertex = 0; vertex < mesh.vertexCount; ++vertex)
                                            //    {
                                            //        textureCoordinates.Add(textureCoordinate);
                                            //    }

                                            //    // Apply them to the mesh
                                            //    newMesh.SetUVs(0, textureCoordinates);
                                            //}

                                            // Add mesh renderer
                                            MeshRenderer meshRenderer = subContainer.AddComponent <MeshRenderer>();
                                            if (meshRenderer != null)
                                            {
                                                // Hide object
                                                meshRenderer.enabled = false;

                                                // Set material to renderer
                                                if (material != null)
                                                {
                                                    meshRenderer.material = material;
                                                }
                                            }

                                            // Check for mesh data and add indices
                                            IMeshData[] meshDataComponents = subContainer.GetComponents <IMeshData>();
                                            if (meshDataComponents != null)
                                            {
                                                foreach (IMeshData meshData in meshDataComponents)
                                                {
                                                    meshData.SetVoxelIndices(new int[1] {
                                                        iteratorIndex
                                                    });
                                                    meshDataInterfaces.Add(meshData);
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                            else
                            {
                                iterator = null;
                                break;
                            }
                        }

                        // Return current progress when building has not been finished
                        if (iterator != null)
                        {
                            return(((float)iterator.Number / (float)(voxels.Count + 1) * (mergeMeshes ? 0.5f : 1.0f)) * ((voxelTexture2D != null) ? 0.5f : 1.0f) + ((voxelTexture2D != null) ? 0.5f : 0.0f));
                        }
                    }
                }
            }

            // Check for groups of materials
            if (groups != null && groups.Count > 0)
            {
                GameObject meshContainer;

                // Initialize group enumerator
                if (currentGroup == null)
                {
                    currentGroup = groups.GetEnumerator();
                    if (currentGroup != null)
                    {
                        if (!currentGroup.MoveNext())
                        {
                            currentGroup = null;
                        }
                    }
                }

                // Check for mesh baking
                if (mergeMeshes)
                {
                    int count, index;
                    int vertexCount, indexCount;
                    int iteratorNumber;

                    // Process collected material groups
                    if (currentGroup != null)
                    {
                        // Check if semi-transparent meshes should be merged or if current group is opaque
                        if (!opaqueOnly || (textureMaterialTemplate != null && voxelTexture != null) || (!currentGroup.Current.Key.HasProperty("_Color") || currentGroup.Current.Key.color.a <= 0 || currentGroup.Current.Key.color.a >= 1))
                        {
                            if (materialContainer == null)
                            {
                                // Create empty game object for the material
                                materialContainer = new GameObject(currentGroup.Current.Value.name);
                                if (materialContainer != null)
                                {
                                    // Attach it to this main object
                                    materialContainer.transform.parent = mainContainer.transform;

                                    // Unset relative transformation
                                    materialContainer.transform.localPosition = Vector3.zero;
                                    materialContainer.transform.localScale    = Vector3.one;
                                    materialContainer.transform.localRotation = Quaternion.identity;

                                    // Copy static flag
                                    materialContainer.isStatic = staticContainers;

                                    // Get meshes of the current group and create array to store flags of processed meshes
                                    meshFilters     = currentGroup.Current.Value.GetComponentsInChildren <MeshFilter>();
                                    processedMeshes = new bool[meshFilters.Length];

                                    // Initialize processing flags and count meshes to merge
                                    for (meshCount = 0, index = 0; index < meshFilters.Length; ++index)
                                    {
                                        if (meshFilters[index].gameObject != currentGroup.Current.Value)
                                        {
                                            processedMeshes[index] = false;

                                            ++meshCount;
                                        }
                                        else
                                        {
                                            processedMeshes[index] = true;
                                        }
                                    }

                                    if (meshCount == 0)
                                    {
                                        materialContainer = null;
                                    }

                                    currentMesh = 0;
                                }
                            }
                        }
                        else
                        {
                            materialContainer = null;
                        }

                        if (materialContainer != null)
                        {
                            // Count number of meshes and total vertices and indices count for current target
                            for (iteratorNumber = 0, vertexCount = 0, indexCount = 0, count = 0, index = 0; index < meshFilters.Length; ++index)
                            {
                                // Check if mesh has not already been processed
                                if (!processedMeshes[index])
                                {
                                    // Check for vertex, index and voxels count limit
                                    if (vertexCount + meshFilters[index].sharedMesh.vertexCount < 65536 && indexCount + meshFilters[index].sharedMesh.triangles.Length < 65536 && (objectVoxelLimit == 0 || count < objectVoxelLimit))
                                    {
                                        // Increase number of vertices and indices
                                        vertexCount += meshFilters[index].sharedMesh.vertexCount;
                                        indexCount  += meshFilters[index].sharedMesh.triangles.Length;

                                        // Increase voxels count
                                        ++count;

                                        // Get mesh data interface
                                        IMeshData meshData = meshFilters[index].gameObject.GetComponent <IMeshData>();
                                        if (meshData != null)
                                        {
                                            // Get indices
                                            int[] indices = meshData.GetVoxelIndices();

                                            // Increase number of voxel indices
                                            if (indices != null)
                                            {
                                                iteratorNumber += indices.Length;
                                            }
                                        }
                                    }
                                    else
                                    {
                                        break;
                                    }
                                }
                            }

                            // Create array to store meshes to merge to
                            CombineInstance[] subMeshes = new CombineInstance[count];

                            // Create array to store voxel indices for current mesh to
                            int[] iteratorIndices = new int[iteratorNumber];

                            // Create empty list to store unused mesh data interface to
                            List <IMeshData> unusedMeshDataInterfaces = new List <IMeshData>();

                            // Process meshes of the current group
                            for (iteratorNumber = 0, vertexCount = 0, indexCount = 0, count = 0, index = 0; index < meshFilters.Length; ++index)
                            {
                                // Check if mesh is not already processed
                                if (!processedMeshes[index])
                                {
                                    // Check for vertex and index limit
                                    if (vertexCount + meshFilters[index].sharedMesh.vertexCount < 65536 && indexCount + meshFilters[index].sharedMesh.triangles.Length < 65536 && (objectVoxelLimit == 0 || count < objectVoxelLimit))
                                    {
                                        // Increase vertices and indices counts for current target mesh
                                        vertexCount += meshFilters[index].sharedMesh.vertexCount;
                                        indexCount  += meshFilters[index].sharedMesh.triangles.Length;

                                        // Store mesh instance and calculate transformation relative to parent object
                                        subMeshes[count].mesh      = meshFilters[index].sharedMesh;
                                        subMeshes[count].transform = currentGroup.Current.Value.transform.worldToLocalMatrix * meshFilters[index].transform.localToWorldMatrix;

                                        // Set flag to skip mesh at next iteration
                                        processedMeshes[index] = true;

                                        // Get mesh data interface
                                        IMeshData[] meshDataComponents = meshFilters[index].gameObject.GetComponents <IMeshData>();
                                        if (meshDataComponents != null && meshDataComponents.Length >= 1)
                                        {
                                            // Get indices
                                            int[] indices = meshDataComponents[0].GetVoxelIndices();

                                            // Check for valid voxel indices
                                            if (indices != null)
                                            {
                                                // Copy indices
                                                System.Array.Copy(indices, 0, iteratorIndices, iteratorNumber, indices.Length);
                                                iteratorNumber += indices.Length;
                                            }

                                            // Add interfaces for mesh data to list of unused ones
                                            unusedMeshDataInterfaces.AddRange(meshDataComponents);
                                        }

                                        // Increase sub meshes count for current merge target
                                        ++count;
                                    }
                                }
                            }

                            // Create object for current mesh to merge
                            if (containerTemplate != null)
                            {
                                meshContainer = Instantiate(containerTemplate);
                            }
                            else
                            {
                                meshContainer = new GameObject("Part");
                            }
                            if (meshContainer != null)
                            {
                                // Attach it to this material object
                                meshContainer.transform.parent = materialContainer.transform;

                                // Unset relative transformation
                                meshContainer.transform.localPosition = Vector3.zero;
                                meshContainer.transform.localScale    = Vector3.one;
                                meshContainer.transform.localRotation = Quaternion.identity;

                                // Copy static flag
                                if (containerTemplate == null)
                                {
                                    meshContainer.isStatic = staticContainers;
                                }

                                // Add mesh filter
                                MeshFilter meshFilter = meshContainer.GetComponent <MeshFilter>();
                                if (meshFilter == null)
                                {
                                    meshFilter = meshContainer.AddComponent <MeshFilter>();
                                }

                                if (meshFilter != null)
                                {
                                    // Create empty mesh object
                                    UnityEngine.Mesh mesh = new UnityEngine.Mesh();
                                    if (mesh != null)
                                    {
                                        // Merge all collected meshes into new one
                                        mesh.CombineMeshes(subMeshes, true, true);

                                        // Set mesh to filter
                                        meshFilter.mesh = mesh;

                                        // Add mesh renderer
                                        MeshRenderer meshRenderer = meshContainer.GetComponent <MeshRenderer>();
                                        if (meshRenderer == null)
                                        {
                                            meshRenderer = meshContainer.AddComponent <MeshRenderer>();
                                        }

                                        // Set material
                                        if (meshRenderer != null)
                                        {
                                            meshRenderer.material = currentGroup.Current.Key;
                                            //meshRenderer.material = groups[group].material;

                                            meshRenderer.enabled = false;
                                        }

                                        // Get texture coordinates to manipulate them
                                        textureCoordinates = mesh.uv2;

                                        // Encode iterator indices into texture coordinates
                                        iteratorNumber = 0;
                                        vertexCount    = 0;
                                        foreach (CombineInstance subMesh in subMeshes)
                                        {
                                            for (int vertexNumber = 0; vertexNumber < subMesh.mesh.vertexCount; ++vertexNumber, ++vertexCount)
                                            {
                                                textureCoordinates[vertexCount].x += (float)iteratorNumber;
                                            }

                                            ++iteratorNumber;
                                        }

                                        // Store manipulated UVs
                                        mesh.uv2 = textureCoordinates;

                                        // Remove mesh data interface of the merge meshes
                                        if (unusedMeshDataInterfaces != null)
                                        {
                                            foreach (IMeshData meshData in unusedMeshDataInterfaces)
                                            {
                                                meshDataInterfaces.Remove(meshData);
                                            }
                                        }

                                        // Check for mesh data and add indices
                                        IMeshData[] meshDataComponents = meshContainer.GetComponents <IMeshData>();
                                        if (meshDataComponents != null)
                                        {
                                            foreach (IMeshData meshData in meshDataComponents)
                                            {
                                                meshData.SetVoxelIndices(iteratorIndices);
                                                meshDataInterfaces.Add(meshData);
                                            }
                                        }
                                    }
                                }
                            }

                            // Decrease number of remaining objects
                            currentMesh += count;
                            if (currentMesh >= meshCount)
                            {
                                // Unset objects for current group
                                materialContainer = null;

                                // Remove original game object
                                DestroyImmediate(currentGroup.Current.Value);
                                //DestroyImmediate(groups[group].gameObject);
                            }
                        }
                    }



                    // Increase number of the current group, if it has been finished
                    if (materialContainer == null)
                    {
                        if (currentGroup.MoveNext())
                        {
                            ++groupNumber;
                        }
                        else
                        {
                            currentGroup = null;
                        }
                    }

                    // Return current progress when building has not been finished
                    if (currentGroup != null)
                    {
                        return((((float)groupNumber + ((float)currentMesh / (float)(meshCount + 1))) / (float)groups.Count * 0.5f + 0.5f) * ((voxelTexture2D != null) ? 0.5f : 1.0f) + ((voxelTexture2D != null) ? 0.5f : 0.0f));
                    }
                }

                // Clear groups list
                groups.Clear();
                groups = null;
            }

            // Check for mesh data interfaces
            if (currentMeshDataInterface < meshDataInterfaces.Count)
            {
                // Transfer given voxels using the current interface
                float progress = meshDataInterfaces[currentMeshDataInterface].ProcessVoxels(voxels, bounds);
                if (progress >= 1)
                {
                    ++currentMeshDataInterface;
                    progress = 0;
                }

                if (currentMeshDataInterface < meshDataInterfaces.Count)
                {
                    return(((float)currentMeshDataInterface + progress) / (float)meshDataInterfaces.Count);
                }
            }

            // Reset current processing data
            //currentDepth = 0;
            //currentHeight = 0;
            currentGroup       = null;
            groupNumber        = 0;
            meshFilters        = null;
            processedMeshes    = null;
            colors             = null;
            voxelTexture2D     = null;
            meshDataInterfaces = null;

            if (mainContainer != null)
            {
                // Show new main container and enable its renderers
                mainContainer.hideFlags &= ~HideFlags.HideAndDontSave;
                ShowRenderer(mainContainer);


                //Debug.Log("mainContainer = " + mainContainer.gameObject );
                //GameObject prefab = PrefabUtility.CreatePrefab("Assets/Prefabs/test.prefab", mainContainer.gameObject, ReplacePrefabOptions.ReplaceNameBased);

                //StaticBatchingUtility.Combine(mainContainer);

#if UNITY_EDITOR
                // Add object creation undo operation
                if (!Application.isPlaying)
                {
                    UnityEditor.Undo.RegisterCreatedObjectUndo(mainContainer, "\"" + targetName + "\" Creation");
                }
#endif

                // Execute informer callback
                if (informer != null)
                {
                    informer(new UnityEngine.Object[] { mainContainer }, parameter);
                }

                mainContainer = null;
            }

            return(1);
        }
Example #2
0
            // 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);
            }
Example #3
0
            // 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);
            }