Scrawk / CGALDotNetUnity

CGALDotNet examples in Unity
MIT License
57 stars 10 forks source link

Boolean operations #5

Open AlastairShipman1 opened 1 year ago

AlastairShipman1 commented 1 year ago

Hi there! I'm working with your CGAL wrapper (fantastic resource- thanks!), and I'm having some issues with the boolean operations. I think I might just be defining the issue wrong, but was hoping to ask your advice?

I'm trying to find the unique volumes of a set of gameobjects. In order to do this I take the union of all of them, then one by one I intersect the other gameobjects with each other, then finish by taking the difference between the union and the intersected components.

However, for some reason I need to translate the intersections by a small amount to make the DIFFERENCE code work? I wonder if I'm doing something wrong, or there's an issue with the underlying algorithm?

Any help would be really appreciated!


public void PerformVolumetricBooleanOperations(GameObject[] inputGos)
    {
        // in this function we find the union of all the gameobject volumes.
        // we then find the volume that is unique to those volumes.

        var boolean = MeshProcessingBoolean<EEK>.Instance;

        // we also need to convert all the gameobjects to cgal polyhedra.
        var polyhedra = new Polyhedron3<EEK>[inputGos.Length];
        for (int i = 0; i < inputGos.Length; i++)
        {
            polyhedra[i] = ConvertGoToPolyhedron(inputGos[i]);
        }

        // now, let's produce a union of all the polyhedra.
        var unionPoly = new Polyhedron3<EEK>();
        for (int i = 0; i < polyhedra.Length; i++)
        {
            if (!boolean.Op(POLYHEDRA_BOOLEAN.UNION, unionPoly, polyhedra[i], out unionPoly))
            {
                Debug.Log("BooleanOperation has failed");// this is probably because one mesh completely encompasses/equals another.
            }
        }

        // now we can produce the bits which are unique to each gameobject.
        // to do this, we take the union of all the overlaps between every pairwise combination of gameobjects.
        // once we have this, we can take the difference between this and the union object we calculated above.
        var intersectionsUnion = new Polyhedron3<EEK>();
        for (int i = 0; i < polyhedra.Length; i++)
        {
            var tempPoly = new Polyhedron3<EEK>();
            for (int ii = i + 1; ii < polyhedra.Length; ii++)
            {
                if (boolean.Op(POLYHEDRA_BOOLEAN.INTERSECT, polyhedra[i], polyhedra[ii], out tempPoly))
                {
                    boolean.Op(POLYHEDRA_BOOLEAN.UNION, intersectionsUnion, tempPoly, out intersectionsUnion);
                }
            }
        }
        // there is a bit of an issue with taking the difference between union and intersections. i think it might be because there's too perfect an overlap?. this seems to solve it, but i don't like it.
        intersectionsUnion.Translate(new Vector3d(0.0000001));

        // as a check, you can uncomment the below, and you should see gameobjects appear that are the union, and the union of intersections
        //unionPoly.ToUnityMesh("union of all gameobjects", new Material(Shader.Find("Diffuse")), false);
        //intersectionsUnion.ToUnityMesh("union of all intersections", new Material(Shader.Find("Diffuse")), false);

        var intersectionsUnionInversion = new Polyhedron3<EEK>();
        boolean.Op(POLYHEDRA_BOOLEAN.DIFFERENCE, unionPoly, intersectionsUnion, out intersectionsUnionInversion);
        intersectionsUnionInversion.ToUnityMesh("All unique volumes", new Material(Shader.Find("Diffuse")), false);
    }

    Polyhedron3<EEK> ConvertGoToPolyhedron(GameObject go)
    {
        // this takes a unity gameobject, and turns it into an EEK polyhedron (middle accuracy, middle speed).
        // to convert back, just call .toUnityMesh() on the polyhedron itself.
        Vector3[] unityMeshPoints = go.GetComponent<MeshFilter>().mesh.vertices;
        Point3d[] cgalMeshPoints = new Point3d[unityMeshPoints.Length];
        for (int i = 0; i < unityMeshPoints.Length; i++)
        {
            cgalMeshPoints[i] = unityMeshPoints[i].ToCGALPoint3d();
        }
        var polyhedron = new Polyhedron3<EEK>(cgalMeshPoints, go.GetComponent<MeshFilter>().mesh.triangles);
        polyhedron.Translate(new Point3d(go.transform.position.x, go.transform.position.y, go.transform.position.z));

        return polyhedron;
    }
ankofl commented 1 week ago

Project is dead