static void March(float[, ,] voxels, Fragment minMax, ThreadSafeVoxelisation.Voxelization.AABCGrid grid, KDTree surface, List <Vector3> parentVerts, List <Vector3> verts, List <int> index)
    {
        Dictionary <string, int> indices = new Dictionary <string, int>();

        float[] cube = new float[8];

        for (int x = minMax.minX - 1; x <= minMax.maxX + 1; x++)
        {
            for (int y = minMax.minY - 1; y <= minMax.maxY + 1; y++)
            {
                for (int z = minMax.minZ - 1; z <= minMax.maxZ + 1; z++)
                {
                    if (x < 0 || y < 0 || z < 0)
                    {
                        continue;
                    }
                    if (x >= voxels.GetLength(0) - 1 || y >= voxels.GetLength(1) - 1 || z >= voxels.GetLength(2) - 1)
                    {
                        continue;
                    }
                    //Get the values in the 8 neighbours which make up a cube
                    FillCube(x, y, z, voxels, cube);
                    //Perform algorithm
                    Mode_Func(new Vector3(x, y, z), cube, verts, index, grid, indices, surface, parentVerts);
                }
            }
        }
    }
    static public MeshInfo CreateMeshClamp(float[, ,] voxels, Fragment minMax, ThreadSafeVoxelisation.Voxelization.AABCGrid grid, KDTree surface, List <Vector3> parentVerts)
    {
        List <Vector3> verts = new List <Vector3>();
        List <int>     index = new List <int>();

        March(voxels, minMax, grid, surface, parentVerts, verts, index);

        MeshInfo mesh = new MeshInfo(verts.ToArray(), index.ToArray(), minMax);

        return(mesh);
    }
    static public MeshInfo CreateMesh(float[, ,] voxels, Fragment minMax, ThreadSafeVoxelisation.Voxelization.AABCGrid grid)
    {
        List <Vector3> verts = new List <Vector3>();
        List <int>     index = new List <int>();

        March(voxels, minMax, grid, null, null, verts, index);

        MeshInfo mesh = new MeshInfo(verts.ToArray(), index.ToArray(), minMax);

        return(mesh);
    }
Beispiel #4
0
    public MeshInfo StartMarching(short[, ,] colouredVoxels, Fragment minMax, ThreadSafeVoxelisation.Voxelization.AABCGrid grid)
    {
        PrepareMarch();

        float[, ,] voxels = new float[colouredVoxels.GetLength(0), colouredVoxels.GetLength(1), colouredVoxels.GetLength(2)];

        PrepareGrid(colouredVoxels, voxels, minMax);

        MeshInfo mesh = ThreadSafeMarchingCubes.CreateMesh(voxels, minMax, grid);

        return(mesh);
    }
Beispiel #5
0
    public Dictionary <short, Fragment> Fragment(ThreadSafeVoxelisation.Voxelization.AABCGrid grid, Vector3 hitPoint, float hitForce, PhysicalProperties physicalProperties)
    {
        this.aabcGrid           = grid;
        this.hitPoint           = hitPoint;
        this.hitForce           = hitForce;
        this.physicalProperties = physicalProperties;

        findHitVoxel(hitPoint);
        generateVoronoiPoints(calcRadius(hitForce), calcNumberOfPoints(hitForce));
        colourVoxels();
        FindIslands();
        return(fragmentExtents);
    }
Beispiel #6
0
    public MeshInfo StartMarchingClamp(short[, ,] colouredVoxels, Fragment minMax, ThreadSafeVoxelisation.Voxelization.AABCGrid grid, KDTree surface, List <Vector3> parentVerts)
    {
        PrepareMarch();

        float[, ,] voxels = new float[colouredVoxels.GetLength(0), colouredVoxels.GetLength(1), colouredVoxels.GetLength(2)];

        PrepareGrid(colouredVoxels, voxels, minMax);

        foreach (Vector3 v in minMax.vertices)
        {
            voxels[(int)v.x, (int)v.y, (int)v.z] = -999f;
        }

        MeshInfo mesh = ThreadSafeMarchingCubes.CreateMeshClamp(voxels, minMax, grid, surface, parentVerts);

        return(mesh);
    }
Beispiel #7
0
    public void SplitDestroy(Vector3 hitPoint, float hitForce, PhysicalProperties physicalProperties)
    {
        messages.Add("Starting");
        float time      = Time.realtimeSinceStartup;
        float startTime = time;

        voxelisationDriver.StartVoxelise(gameObject);


        messages.Add("Voxelisation: " + (Time.realtimeSinceStartup - time));
        csvList.Add((Time.realtimeSinceStartup - time) + " ");
        time = Time.realtimeSinceStartup;

        grid = voxelisationDriver.GetGrid();

        fragments = destruction.Fragment(grid, hitPoint, hitForce, physicalProperties);

        messages.Add("Destruction: " + (Time.realtimeSinceStartup - time));
        csvList.Add((Time.realtimeSinceStartup - time) + " ");
        time = Time.realtimeSinceStartup;

        colouring = destruction.getVoronoiDiagram();

        foreach (Fragment c in fragments.Values)
        {
            c.vertices.Clear();
        }

        short[, ,] borderColouring = new short[colouring.GetLength(0), colouring.GetLength(1), colouring.GetLength(2)];

        List <Vector3> vectors = new List <Vector3>();

        for (int i = 0; i < colouring.GetLength(0); i++)
        {
            for (int j = 0; j < colouring.GetLength(1); j++)
            {
                for (int k = 0; k < colouring.GetLength(2); k++)
                {
                    short c          = colouring[i, j, k];
                    bool  neighbours = false;
                    bool  exterior   = false;
                    if (c == 0)
                    {
                        continue;
                    }
                    for (int x = -1; x <= 1; x++)
                    {
                        for (int y = -1; y <= 1; y++)
                        {
                            for (int z = -1; z <= 1; z++)
                            {
                                if (i + x < 0 || j + y < 0 || k + z < 0)
                                {
                                    continue;
                                }
                                if (i + x >= colouring.GetLength(0) || j + y >= colouring.GetLength(1) || k + z >= colouring.GetLength(2))
                                {
                                    continue;
                                }
                                if (colouring[i + x, j + y, k + z] != c && colouring[i + x, j + y, k + z] != 0)
                                {
                                    neighbours = true;
                                }
                                if (colouring[i + x, j + y, k + z] == 0)
                                {
                                    exterior = true;
                                }
                            }
                        }
                    }
                    if (exterior)
                    {
                        vectors.Add(new Vector3(i, j, k));
                    }
                    if (neighbours)
                    {
                        borderColouring[i, j, k] = c;
                    }
                    if (neighbours && exterior)
                    {
                        Fragment colour;
                        if (fragments.TryGetValue(c, out colour))
                        {
                            colour.vertices.Add(new Vector3(i, j, k));
                        }
                    }
                }
            }
        }

        KDTree tree = KDTree.MakeFromPoints(vectors.ToArray());

        messages.Add("KDTree: " + (Time.realtimeSinceStartup - time));
        time = Time.realtimeSinceStartup;

        MeshInfo original = new MeshInfo(gameObject.GetComponent <MeshFilter>().mesh.vertices, gameObject.GetComponent <MeshFilter>().mesh.triangles, new Fragment(0));

        Dictionary <short, MeshInfo> meshes = splitMesh.Split(original, tree, vectors, colouring, grid.GetSize());

        messages.Add("Split: " + (Time.realtimeSinceStartup - time));
        csvList.Add((Time.realtimeSinceStartup - time) + " ");
        time = Time.realtimeSinceStartup;


        if (!hollow)
        {
            csvList.Add("Meshing ");

            foreach (Fragment colour in fragments.Values)
            {
                if (colour == null)
                {
                    continue;
                }

                MeshInfo meshinfo, march;

                MeshInfo parent;
                bool     found = meshes.TryGetValue(colour.colour, out parent);

                colors.Add(colour.colour, new Color(Random.value, Random.value, Random.value));

                if (found)
                {
                    List <Vector3> edges    = parent.colour.vertices;
                    List <Vector3> exterior = new List <Vector3>();
                    foreach (Vector3 v in colour.vertices)
                    {
                        exterior.Add(toWorldSpace(v));
                    }

                    Vector3 voxelMid = new Vector3((colour.maxX - colour.minX) / 2, (colour.maxY - colour.minY) / 2, (colour.maxZ - colour.minZ) / 2);
                    voxelMid.x = voxelMid.x / grid.GetSize().x;
                    voxelMid.y = voxelMid.y / grid.GetSize().y;
                    voxelMid.z = voxelMid.z / grid.GetSize().z;
                    voxelMid  *= 2;

                    KDTree surface = KDTree.MakeFromPoints(edges.ToArray());
                    //meshinfo = holefill.Stitch(edges, colour, exterior);

                    meshinfo = marchingDriver.StartMarchingClamp(borderColouring, colour, grid, surface, edges);
                }
                else
                {
                    meshinfo = marchingDriver.StartMarching(borderColouring, colour, grid);
                    march    = marchingDriver.StartMarching(borderColouring, colour, grid);
                }
                //meshinfo = convexDriver.StartMeshing(colour);

                /*for (int c = 0; c < meshinfo.verts.Length; c++) {
                 *  meshinfo.verts[c] = new Vector3(meshinfo.verts[c].x / transform.lossyScale.x, meshinfo.verts[c].y / transform.lossyScale.y, meshinfo.verts[c].z / transform.lossyScale.z);
                 * }*/

                messages.Add("Meshing " + colour.colour + ": " + (Time.realtimeSinceStartup - time));
                csvList.Add((Time.realtimeSinceStartup - time) + " ");
                time = Time.realtimeSinceStartup;

                if (colour.colour == 0)
                {
                    continue;
                }
                else
                {
                    if (found)
                    {
                        List <Vector3> verts = new List <Vector3>(parent.verts);
                        int            count = verts.Count;
                        verts.AddRange(meshinfo.verts);

                        List <int> indices = new List <int>(parent.index);
                        foreach (int i in meshinfo.index)
                        {
                            indices.Add(i + count);
                        }

                        /*count = verts.Count;
                         * verts.AddRange(march.verts);
                         *
                         * foreach (int i in march.index) {
                         *  indices.Add(i + count);
                         * }*/

                        parent.verts       = verts.ToArray();
                        parent.index       = indices.ToArray();
                        parent.colour.mass = meshinfo.colour.mass;
                    }
                    else
                    {
                        meshes.Add(colour.colour, meshinfo);
                    }
                }
            }
        }

        csvList.Add("Building ");

        foreach (MeshInfo meshinfo in meshes.Values)
        {
            Mesh     mesh     = new Mesh();
            Fragment coloured = meshinfo.colour;

            fragments.TryGetValue(coloured.colour, out coloured);

            if (coloured.colour == 0)
            {
                continue;
            }

            mesh.vertices  = meshinfo.verts;
            mesh.triangles = meshinfo.index;

            //The diffuse shader wants uvs so just fill with a empty array, they're not actually used
            mesh.uv = new Vector2[mesh.vertices.Length];
            mesh.RecalculateNormals();
            mesh.RecalculateBounds();

            Mesh mesh1 = new Mesh();

            if (hollow)
            {
                List <int> indices = new List <int>(meshinfo.index);

                for (int i = 0; i < meshinfo.index.Length; i += 3)
                {
                    indices.Add(meshinfo.index[i + 2]);
                    indices.Add(meshinfo.index[i + 1]);
                    indices.Add(meshinfo.index[i + 0]);
                }

                meshinfo.index = indices.ToArray();

                /*List<Vector3> normals = new List<Vector3>(mesh.normals);
                 * for (int i = 0; i < mesh.normals.Length; i++)
                 *  normals.Add(-normals[i]);*/

                mesh1.vertices  = meshinfo.verts;
                mesh1.triangles = meshinfo.index;

                //The diffuse shader wants uvs so just fill with a empty array, they're not actually used
                mesh1.uv = new Vector2[mesh.vertices.Length];

                mesh1.normals = mesh.normals;
            }

            GameObject m_mesh = new GameObject("Fragment" + coloured.colour);
            m_mesh.AddComponent <MeshFilter>();
            m_mesh.AddComponent <MeshRenderer>();
            //MeshCollider col1 = m_mesh.AddComponent<MeshCollider>();
            MeshCollider col2 = m_mesh.AddComponent <MeshCollider>();

            m_mesh.AddComponent <Rigidbody>();
            //m_mesh.rigidbody.isKinematic = true;
            m_mesh.rigidbody.collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic;
            m_mesh.rigidbody.mass    = coloured.mass;
            m_mesh.renderer.material = m_material;

            //col1.sharedMesh = mesh;
            col2.sharedMesh = mesh;
            col2.convex     = true;

            m_mesh.GetComponent <MeshFilter>().mesh = hollow ? mesh1 : mesh;

            m_mesh.transform.localScale = transform.localScale;

            messages.Add("Built " + coloured.colour + ": " + (Time.realtimeSinceStartup - time));
            csvList.Add((Time.realtimeSinceStartup - time) + " ");
            time = Time.realtimeSinceStartup;
        }

        messages.Add("Done:" + (Time.realtimeSinceStartup - startTime));

        string csv = "";

        foreach (string str in csvList)
        {
            csv += str;
        }

        foreach (string str in messages)
        {
            Debug.Log(str);
        }

        //Debug.Log(csv);

        done = true;

        GameObject.Destroy(gameObject);
        if (breakP)
        {
            Debug.Break();
        }
    }
    //MarchCubeTetrahedron performs the Marching Tetrahedrons algorithm on a single cube
    static void MarchCubeTetrahedron(Vector3 pos, float[] cube, List <Vector3> vertList, List <int> indexList, ThreadSafeVoxelisation.Voxelization.AABCGrid grid, Dictionary <string, int> indices, KDTree surface, List <Vector3> parentVerts)
    {
        int i, j, vertexInACube;

        Vector3[] cubePosition        = new Vector3[8];
        Vector3[] tetrahedronPosition = new Vector3[4];
        float[]   tetrahedronValue    = new float[4];

        //Make a local copy of the cube's corner positions
        for (i = 0; i < 8; i++)
        {
            cubePosition[i] = new Vector3(pos.x + vertexOffset[i, 0], pos.y + vertexOffset[i, 1], pos.z + vertexOffset[i, 2]);
        }

        for (i = 0; i < 6; i++)
        {
            for (j = 0; j < 4; j++)
            {
                vertexInACube          = tetrahedronsInACube[i, j];
                tetrahedronPosition[j] = cubePosition[vertexInACube];
                tetrahedronValue[j]    = cube[vertexInACube];
            }

            MarchTetrahedron(tetrahedronPosition, tetrahedronValue, vertList, indexList, grid, indices, surface, parentVerts);
        }
    }
    //MarchTetrahedron performs the Marching Tetrahedrons algorithm on a single tetrahedron
    static void MarchTetrahedron(Vector3[] tetrahedronPosition, float[] tetrahedronValue, List <Vector3> vertList, List <int> indexList, ThreadSafeVoxelisation.Voxelization.AABCGrid grid, Dictionary <string, int> indices, KDTree surface, List <Vector3> parentVerts)
    {
        ThreadSafeVoxelisation.GridSize gridSize = grid.GetSize();

        int   i, j, vert, vert0, vert1, idx;
        int   flagIndex = 0, edgeFlags;
        float offset, invOffset;

        bool boundary = false;

        Vector3[] edgeVertex = new Vector3[6];

        //Find which vertices are inside of the surface and which are outside
        for (i = 0; i < 4; i++)
        {
            if (tetrahedronValue[i] == -999f)
            {
                boundary = true;
            }
            if (tetrahedronValue[i] <= target)
            {
                flagIndex |= 1 << i;
            }
        }

        //Find which edges are intersected by the surface
        edgeFlags = tetrahedronEdgeFlags[flagIndex];

        //If the tetrahedron is entirely inside or outside of the surface, then there will be no intersections
        if (edgeFlags == 0)
        {
            return;
        }

        //Find the point of intersection of the surface with each edge
        for (i = 0; i < 6; i++)
        {
            //if there is an intersection on this edge
            if ((edgeFlags & (1 << i)) != 0)
            {
                vert0           = tetrahedronEdgeConnection[i, 0];
                vert1           = tetrahedronEdgeConnection[i, 1];
                offset          = GetOffset(tetrahedronValue[vert0], tetrahedronValue[vert1]);
                invOffset       = 1.0f - offset;
                edgeVertex[i].x = ((invOffset * tetrahedronPosition[vert0].x + offset * tetrahedronPosition[vert1].x) - (gridSize.x * 0.5f)) * gridSize.side / 2.1f;
                edgeVertex[i].y = ((invOffset * tetrahedronPosition[vert0].y + offset * tetrahedronPosition[vert1].y) - (gridSize.y * 0.5f)) * gridSize.side / 2.1f;
                edgeVertex[i].z = ((invOffset * tetrahedronPosition[vert0].z + offset * tetrahedronPosition[vert1].z) - (gridSize.z * 0.5f)) * gridSize.side / 2.1f;
            }
        }

        Vector3[] oEdgeVertex = new Vector3[6];

        if (boundary)
        {
            for (int c = 0; c < edgeVertex.Length; c++)
            {
                oEdgeVertex[c] = edgeVertex[c];
                int index = surface.FindNearest(edgeVertex[c]);
                edgeVertex[c] = parentVerts[index];
            }
        }
        else
        {
            for (int c = 0; c < edgeVertex.Length; c++)
            {
                oEdgeVertex[c] = edgeVertex[c];
                Vector3 random = Random.insideUnitSphere;
                random       *= 1f / 4f;
                random.x      = (random.x) * gridSize.side / 2.1f;
                random.y      = (random.y) * gridSize.side / 2.1f;
                random.z      = (random.z) * gridSize.side / 2.1f;
                edgeVertex[c] = edgeVertex[c] + random;
            }
        }

        //Save the triangles that were found. There can be up to 2 per tetrahedron
        for (i = 0; i < 2; i++)
        {
            if (tetrahedronTriangles[flagIndex, 3 * i] < 0)
            {
                break;
            }

            for (j = 0; j < 3; j++)
            {
                idx  = vertList.Count;
                vert = tetrahedronTriangles[flagIndex, 3 * i + windingOrder[j]];

                Vector3 vertex = edgeVertex[vert];

                string points = oEdgeVertex[vert].x + "," + oEdgeVertex[vert].y + "," + oEdgeVertex[vert].z;

                int index = -1;

                bool found = indices.TryGetValue(points, out index);

                if (found)
                {
                    indexList.Add(index);
                }
                else
                {
                    indexList.Add(idx);
                    vertList.Add(edgeVertex[vert]);
                    indices.Add(points, idx);
                }
            }
        }
    }
    //MarchCube performs the Marching Cubes algorithm on a single cube
    static void MarchCube(Vector3 pos, float[] cube, List <Vector3> vertList, List <int> indexList, ThreadSafeVoxelisation.Voxelization.AABCGrid grid, Dictionary <string, int> indices, KDTree surface, List <Vector3> parentVerts)
    {
        int   i, j, vert, idx;
        int   flagIndex = 0;
        float offset    = 0.0f;

        ThreadSafeVoxelisation.GridSize gridSize = grid.GetSize();

        Vector3[] edgeVertex = new Vector3[12];

        //Find which vertices are inside of the surface and which are outside
        for (i = 0; i < 8; i++)
        {
            if (cube[i] <= target)
            {
                flagIndex |= 1 << i;
            }
        }

        //Find which edges are intersected by the surface
        int edgeFlags = cubeEdgeFlags[flagIndex];

        //If the cube is entirely inside or outside of the surface, then there will be no intersections
        if (edgeFlags == 0)
        {
            return;
        }

        //Find the point of intersection of the surface with each edge
        for (i = 0; i < 12; i++)
        {
            //if there is an intersection on this edge
            if ((edgeFlags & (1 << i)) != 0)
            {
                offset = GetOffset(cube[edgeConnection[i, 0]], cube[edgeConnection[i, 1]]);

                edgeVertex[i].x = pos.x + (vertexOffset[edgeConnection[i, 0], 0] + offset * edgeDirection[i, 0]);
                edgeVertex[i].y = pos.y + (vertexOffset[edgeConnection[i, 0], 1] + offset * edgeDirection[i, 1]);
                edgeVertex[i].z = pos.z + (vertexOffset[edgeConnection[i, 0], 2] + offset * edgeDirection[i, 2]);
            }
        }

        //Save the triangles that were found. There can be up to five per cube

        /*for (i = 0; i < 5; i++) {
         *  if (triangleConnectionTable[flagIndex, 3 * i] < 0) break;
         *
         *  for (j = 0; j < 3; j++) {
         *      idx = vertList.Count;
         *      vert = triangleConnectionTable[flagIndex, 3 * i + windingOrder[j]];
         *
         *      Vector3 vertex = edgeVertex[vert];
         *      string points = vertex.x + "" + vertex.y + "" + vertex.z;
         *      int index = -1;
         *
         *      bool found = indices.TryGetValue(points, out index);
         *
         *      if (found) {
         *          indexList.Add(index);
         *      } else {
         *          indexList.Add(idx);
         *          vertList.Add(edgeVertex[vert]);
         *          indices.Add(points, idx);
         *      }
         *  }
         *
         * }*/

        for (i = 0; i < 5; i++)
        {
            if (triangleConnectionTable[flagIndex, 3 * i] < 0)
            {
                break;
            }

            idx = vertList.Count;

            for (j = 0; j < 3; j++)
            {
                vert = triangleConnectionTable[flagIndex, 3 * i + j];
                indexList.Add(idx + windingOrder[j]);
                vertList.Add(edgeVertex[vert]);
            }
        }
    }