コード例 #1
0
        public static BspNode AddNode(BspNode inParent, BspNode.EBspLocation inLocation, Face inFace, int inFlags)
        {
            BspNode newNode = new BspNode();

            newNode.plane = inFace.GetPlane();
            newNode.face  = inFace;
            newNode.front = newNode.back = newNode.planar = null;
            newNode.flags = inFlags;

            if (inLocation == BspNode.EBspLocation.BspLocation_Front)
            {
                // check that front node is null
                inParent.front = newNode;
            }
            else if (inLocation == BspNode.EBspLocation.BspLocation_Back)
            {
                // TODO: check that back node is null
                inParent.back = newNode;
            }
            else if (inLocation == BspNode.EBspLocation.BspLocation_Planar)
            {
                // go to the last planar node
                BspNode lastPlanar = inParent;

                while (lastPlanar.planar != null)
                {
                    lastPlanar = lastPlanar.planar;
                }

                // add planar node
                lastPlanar.planar = newNode;
            }

            return(newNode);
        }
コード例 #2
0
        //
        public static void GetFaces(BspNode inNode, List <Face> outFaces)
        {
            while (inNode != null)
            {
                // if we are not destroyed
                if ((inNode.flags & BspNode.BspFlags_IsDestroyed) == 0)
                {
                    // add to array list
                    outFaces.Add(inNode.face);
                }


                if (inNode.front != null)
                {
                    GetFaces(inNode.front, outFaces);
                }

                if (inNode.back != null)
                {
                    GetFaces(inNode.back, outFaces);
                }

                // get to the next planar node
                inNode = inNode.planar;
            }
        }
コード例 #3
0
        public static void DumpTree(BspNode inNode)
        {
            Debug.Log("Node...");

            Debug.Log("Planar Nodes");
            BspNode planar = inNode.planar;

            while (planar != null)
            {
                Debug.Log("Planar Node");
                planar = planar.planar;
            }

            if (inNode.front != null)
            {
                Debug.Log("FrontSide");
                DumpTree(inNode.front);
            }

            if (inNode.back != null)
            {
                Debug.Log("BackSide");
                DumpTree(inNode.back);
            }
        }
コード例 #4
0
        //
        private void PerformFaces(BspNode inRoot, List <Face> inFaces)
        {
            for (int i = 0; i < inFaces.Count; ++i)
            {
                OperationInfo info;
                InitializeOper(out info);

                PerformNode(inRoot, inFaces[i] as Face, SIDE_Outside, info);
            }
        }
コード例 #5
0
 void RouteOper(BspNode inNode, Face inFace, EPolySide inSide, OperationInfo info)
 {
     if (processState == EProcessState.Process_Master)
     {
         csgVisitor.ProcessMaster(this, inFace, inSide, info);
     }
     else
     {
         csgVisitor.ProcessSlave(this, inFace, inSide, info);
     }
 }
コード例 #6
0
        private void PerformTree(BspNode inNode, BspNode inOtherRoot)
        {
            while (inNode != null)
            {
                // if we are new, stop processing our node...
                if ((inNode.flags & BspNode.BspFlags_IsNew) != 0)
                {
                    return;
                }

                // if we are not destroyed
                if ((inNode.flags & BspNode.BspFlags_IsDestroyed) == 0)
                {
                    OperationInfo info;
                    InitializeOper(out info);

                    // save current node
                    currentNode = inNode;

                    // find last coplanar node
                    BspNode lastPlanar = inNode;
                    while (lastPlanar.planar != null)
                    {
                        lastPlanar = lastPlanar.planar;
                    }

                    // perform nodes face with other tree
                    PerformNode(inOtherRoot, inNode.face, SIDE_Outside, info);

                    // nobody removed us
                    if ((inNode.flags & BspNode.BspFlags_IsDestroyed) == 0)
                    {
                        // remove all planar nodes added (if any)
                        lastPlanar.planar = null;
                    }
                }


                // process front node
                if (inNode.front != null)
                {
                    PerformTree(inNode.front, inOtherRoot);
                }

                // process back node
                if (inNode.back != null)
                {
                    PerformTree(inNode.back, inOtherRoot);
                }

                // process next planar node
                inNode = inNode.planar;
            }
        }
コード例 #7
0
        //
        public void Perform(ECsgOperation inOper, CSGObject inMaster, CSGObject inSlave)
        {
            // we are processing our slave faces
            processState = EProcessState.Process_Slave;

            // process faces against master tree
            PerformFaces(inMaster.rootNode, inSlave.faces);

            // process face from master tree
            processState = EProcessState.Process_Master;

            // perform master faces on slave bsp tree
            PerformTree(inMaster.rootNode, inSlave.rootNode);

            // check if how do we need to process generated faces
            if (inOper == ECsgOperation.CsgOper_Additive || inOper == ECsgOperation.CsgOper_Subtractive)
            {
                // add deferred faces to master tree...
                for (int i = 0; i < deferredFaces.Count; i++)
                {
                    Face    defFace   = ((DeferredFace)deferredFaces[i]).face;
                    BspNode startNode = ((DeferredFace)deferredFaces[i]).node;

                    // testing
                    startNode = inMaster.rootNode;
                    // add node to master tree
                    BspGen.AddNodeRecursive(startNode, defFace, BspNode.BspFlags_IsNew);
                }
            }
            else
            {
                // clear old faces list
                inMaster.faces.Clear();

                // copy created faces
                for (int i = 0; i < deferredFaces.Count; i++)
                {
                    inMaster.faces.Add(deferredFaces[i].face);
                }
            }

            // clear deferred faces
            deferredFaces.Clear();
        }
コード例 #8
0
        public static void FacesFromNodes(BspNode inNode, List <Face> outFaces)
        {
            while (inNode != null)
            {
                if ((inNode.flags & BspNode.BspFlags_IsDestroyed) == 0)
                {
                    outFaces.Add(inNode.face);
                }

                if (inNode.front != null)
                {
                    FacesFromNodes(inNode.front, outFaces);
                }

                if (inNode.back != null)
                {
                    FacesFromNodes(inNode.back, outFaces);
                }

                //
                inNode = inNode.planar;
            }
        }
コード例 #9
0
        //
        public BspNode GenerateBspTree(List <Face> inFaces)
        {
            if (inFaces == null)
            {
                Debug.Log("Not able to create Tree with no Faces");
                return(null);
            }

            Debug.Log("Building Bsp Tree for " + inFaces.Count + " Faces");

            // create root node
            BspNode root = new BspNode();

            // partition all faces
            Partition(root, inFaces);

            // copy bsp faces back to array list (resulting faces...)
            GetFaces(root, inFaces);

            Debug.Log("Resulting in " + inFaces.Count + " Faces");

            // result
            return(root);
        }
コード例 #10
0
        private void PerformNode(BspNode inNode, Face inFace, int nodeSide, OperationInfo info)
        {
            while (inNode != null)
            {
                Face.EPlaneSide side = inFace.Side(inNode.plane);

                switch (side)
                {
                case Face.EPlaneSide.Side_Front:

                    //
                    nodeSide = nodeSide | (inNode.IsCsg() ? 1 : 0);

                    // leaf node
                    if (inNode.front == null)
                    {
                        // set operation infos
                        info.leafNode     = inNode;
                        info.leafLocation = BspNode.EBspLocation.BspLocation_Front;

                        // we are done, process face
                        ProcessFace(inFace, SIDE_Outside, info);
                    }

                    // get to next front node (if any)
                    inNode = inNode.front;

                    break;

                case Face.EPlaneSide.Side_Back:

                    int backSide = inNode.IsCsg() ? 0 : 1;
                    //
                    nodeSide = nodeSide & backSide;

                    // leaf node
                    if (inNode.back == null)
                    {
                        // set leaf infos
                        info.leafNode     = inNode;
                        info.leafLocation = BspNode.EBspLocation.BspLocation_Back;

                        // we are done, process face
                        ProcessFace(inFace, SIDE_Inside, info);
                    }

                    // get to next front node (if any)
                    inNode = inNode.back;
                    break;

                case Face.EPlaneSide.Side_Split:

                    // split face and process front and back
                    Face frontFace, backFace;

                    //
                    inFace.Split(inNode.plane, out frontFace, out backFace);

                    // TODO: set polygon cutted flags
                    frontFace.flags |= Face.FaceFlags_WasCutted;
                    backFace.flags  |= Face.FaceFlags_WasCutted;


                    // front node is a leaf node
                    if (inNode.front == null)
                    {
                        //
                        info.leafNode     = inNode;
                        info.leafLocation = BspNode.EBspLocation.BspLocation_Front;


                        ProcessFace(frontFace, SIDE_Outside, info);
                    }
                    else
                    {
                        PerformNode(inNode.front, frontFace, nodeSide, info);
                    }

                    // Prcess back node with back face
                    if (inNode.back == null)
                    {
                        //
                        info.leafNode     = inNode;
                        info.leafLocation = BspNode.EBspLocation.BspLocation_Back;


                        ProcessFace(backFace, SIDE_Inside, info);
                    }
                    else
                    {
                        // process back node with new face
                        PerformNode(inNode.back, backFace, nodeSide, info);
                    }

                    // stop loop
                    inNode = null;
                    break;

                case Face.EPlaneSide.Side_Planar:

                    BspNode front, back;

                    if (info.wasPlanar == true)
                    {
                        Debug.Log("Reentering Planar Nodes!");
                    }


                    // set operation infos
                    info.wasPlanar      = true;
                    info.backNode       = null;
                    info.processingBack = false;

                    if (Vector3.Dot(inFace.GetPlane().normal, inNode.plane.normal) >= 0.0f)
                    {
                        // same order as we face in the same order
                        front = inNode.front;
                        back  = inNode.back;

                        // we are for now outside (as we are looking outside)
                        info.planarSide = SIDE_Outside;
                    }
                    else
                    {
                        // reverse order as we are facing in the opposite direction
                        front = inNode.back;
                        back  = inNode.front;

                        // we are now inside as we are looking to the inside
                        info.planarSide = SIDE_Inside;
                    }

                    // we are leaf node (coplanar face)
                    if (front == null && back == null)
                    {
                        // set leaf stuff
                        info.leafNode     = inNode;
                        info.leafLocation = BspNode.EBspLocation.BspLocation_Planar;

                        // process node
                        info.processingBack = true;

                        // process face
                        ProcessFace(inFace, InverseSide(info.planarSide), info);

                        // stop loop
                        inNode = null;
                    }
                    else if (front == null && back != null)
                    {
                        // only back nodes
                        info.processingBack = true;

                        // process back
                        inNode = back;
                    }
                    else
                    {
                        // tread like we were on front side (maybe we do have a back node)
                        info.processingBack = false;

                        // remember back node
                        info.backNode = back;

                        // process front
                        inNode = front;
                    }

                    break;
                }
            }
        }
コード例 #11
0
        //
        void Partition(BspNode inNode, List <Face> inFaces)
        {
            List <Face> frontFaces = new List <Face>();
            List <Face> backFaces  = new List <Face>();
            Face        nodeFace;

            // find best splitter plane for this
            bool ret = FindSplitter(inFaces, out nodeFace);

            // return has to be true!!!
            if (ret == false)
            {
                Debug.DebugBreak();
                Debug.Log("Error processing Mesh!");
                return;
            }

            // setup node
            inNode.front  = null;
            inNode.back   = null;
            inNode.planar = null;
            inNode.face   = nodeFace;
            inNode.plane  = nodeFace.GetPlane();


            // split remaining faces into lists
            for (int i = 0; i < inFaces.Count; ++i)
            {
                // get face
                Face face = inFaces[i] as Face;

                // do not process our self
                if (face == nodeFace)
                {
                    continue;
                }


                Face.EPlaneSide side = face.Side(inNode.plane);

                switch (side)
                {
                case Face.EPlaneSide.Side_Front:
                    frontFaces.Add(face);
                    break;

                case Face.EPlaneSide.Side_Back:
                    backFaces.Add(face);
                    break;

                case Face.EPlaneSide.Side_Planar:
                    // get last planar node
                    BspNode lastPlanar = inNode;
                    while (lastPlanar.planar != null)
                    {
                        lastPlanar = lastPlanar.planar;
                    }

                    // create new planar node
                    BspNode planar = lastPlanar.planar = new BspNode();

                    // setup planar node
                    planar.front  = null;
                    planar.back   = null;
                    planar.planar = null;
                    planar.face   = face;
                    planar.plane  = face.GetPlane();

                    break;

                case Face.EPlaneSide.Side_Split:
                    // TODO...
                    Face front, back;
                    // split face into two parts...
                    ret = face.Split(inNode.plane, out front, out back);

                    if (ret == false)
                    {
                        Debug.DebugBreak();
                    }

                    // add to front and back
                    frontFaces.Add(front);
                    backFaces.Add(back);
                    break;
                }
            }

            // optimizing a bit, clear in array list as we do not need it any more
            inFaces.Clear();

            // process front faces
            if (frontFaces.Count > 0)
            {
                inNode.front = new BspNode();
                // partition front faces
                Partition(inNode.front, frontFaces);
            }


            // process back faces
            if (backFaces.Count > 0)
            {
                inNode.back = new BspNode();
                // partition back faces
                Partition(inNode.back, backFaces);
            }
        }
コード例 #12
0
        public static BspNode AddNodeRecursive(BspNode inNode, Face inFace, int inFlags)
        {
            while (inNode != null)
            {
                Face.EPlaneSide planeSide = inFace.Side(inNode.plane);

                switch (planeSide)
                {
                case Face.EPlaneSide.Side_Front:

                    if (inNode.front == null)
                    {
                        return(AddNode(inNode, BspNode.EBspLocation.BspLocation_Front, inFace, inFlags));
                    }

                    inNode = inNode.front;
                    break;

                case Face.EPlaneSide.Side_Back:

                    if (inNode.back == null)
                    {
                        return(AddNode(inNode, BspNode.EBspLocation.BspLocation_Back, inFace, inFlags));
                    }

                    inNode = inNode.back;
                    break;

                case Face.EPlaneSide.Side_Planar:
                    return(AddNode(inNode, BspNode.EBspLocation.BspLocation_Planar, inFace, inFlags));

                case Face.EPlaneSide.Side_Split:

                    Face frontFace, backFace;

                    inFace.Split(inNode.plane, out frontFace, out backFace);

                    if (inNode.front == null)
                    {
                        AddNode(inNode, BspNode.EBspLocation.BspLocation_Front, frontFace, inFlags);
                    }
                    else
                    {
                        AddNodeRecursive(inNode.front, frontFace, inFlags);
                    }

                    if (inNode.back == null)
                    {
                        AddNode(inNode, BspNode.EBspLocation.BspLocation_Back, inFace, inFlags);
                    }
                    else
                    {
                        AddNodeRecursive(inNode.back, backFace, inFlags);
                    }

                    inNode = null;
                    break;
                }
            }

            // happens when face get splitted...
            return(null);
        }
コード例 #13
0
        public static void MergeCoplanars(BspNode inNode)
        {
            // proceed front nodes
            if (inNode.front != null)
            {
                MergeCoplanars(inNode.front);
            }

            // proceed back nodes
            if (inNode.back != null)
            {
                MergeCoplanars(inNode.back);
            }

            // first try to merge other co planar nodes
            if (inNode.planar != null)
            {
                MergeCoplanars(inNode.planar);
            }

            //
            bool tryToMerge = (inNode.flags & BspNode.BspFlags_IsDestroyed) == 0;

            while (tryToMerge)
            {
                // get planar node
                BspNode planarNode = inNode.planar;

                // assume we are done
                tryToMerge = false;

                // get through all planar nodes
                while (planarNode != null)
                {
                    // if we are destroyed, proceed to next
                    if ((planarNode.flags & BspNode.BspFlags_IsDestroyed) != 0)
                    {
                        // proceed to next
                        planarNode = planarNode.planar;
                        continue;
                    }


                    Face thisFace  = inNode.face;
                    Face otherFace = planarNode.face;

                    // are we facing the same direction
                    if (Vector3.Dot(thisFace.GetPlane().normal, otherFace.GetPlane().normal) > 0.995f)
                    {
                        // result
                        Face merged;

                        //
                        if (thisFace.Merge(otherFace, out merged))
                        {
                            // replace this face with merged
                            thisFace = merged;

                            // set other node as destroyed
                            planarNode.flags |= BspNode.BspFlags_IsDestroyed;

                            // retry to merge
                            tryToMerge = true;
                        }
                    }

                    // proceed to next
                    planarNode = planarNode.planar;
                }
            }
        }
コード例 #14
0
        /// <summary>
        /// Performs CSG Operation on this Object (Master) with given Slaves.
        /// </summary>
        /// <param name='inOper'>
        /// In oper.
        /// </param>
        /// <param name='inSlaves'>
        /// In slaves.
        /// </param>
        public void PerformCSG(CsgOperation.ECsgOperation inOper, CSGObject[] inSlaves)
        {
            //
            CreateFromMesh();

            // create bsp generator
            BspGen gen = new BspGen(BooleanSettings.BspOptimization);

            rootNode = gen.GenerateBspTree(faces);

            List <Face> savedFaces = new List <Face>();

            //
            foreach (var slave in inSlaves)
            {
                // if we have a csg object and we are not our self
                // and intersecting
                if (slave && slave.gameObject != gameObject && intersect(slave))
                {
                    Debug.Log(slave.gameObject.name);

                    //
                    slave.CreateFromMesh();

                    // ....
                    BspGen genSlave = new BspGen(BooleanSettings.BspOptimization);
                    slave.rootNode = genSlave.GenerateBspTree(slave.faces);

                    CsgVisitor visitor = null;

                    switch (inOper)
                    {
                    case CsgOperation.ECsgOperation.CsgOper_Additive:
                        visitor = new UnionVisitor();
                        break;

                    case CsgOperation.ECsgOperation.CsgOper_Subtractive:
                        visitor = new SubtractiveVisitor();
                        break;

                    case CsgOperation.ECsgOperation.CsgOper_Intersect:
                        visitor = new IntersectVisitor();
                        break;

                    case CsgOperation.ECsgOperation.CsgOper_DeIntersect:
                        visitor = new DeIntersectVisitor();
                        break;

                    default:
                        visitor = null;
                        break;
                    }


                    CsgOperation oper = new CsgOperation(visitor);

                    oper.Perform(inOper, this, slave);

                    // save faces
                    savedFaces.AddRange(faces);
                }
            }


            // If we want to merge Coplanars after every Operation
            if (BooleanSettings.MergeCoplanars)
            {
                MergeFaces();
            }

            // for additive or subtracte operation, built faces list from bsp tree
            // for others, use faces directly
            if (inOper == CsgOperation.ECsgOperation.CsgOper_Additive ||
                inOper == CsgOperation.ECsgOperation.CsgOper_Subtractive)
            {
                // create new face list
                List <Face> newFaces = new List <Face>();
                // create faces from bsp nodes
                BspHelper.FacesFromNodes(rootNode, newFaces);
                // copy to face list
                faces = newFaces;
            }
            else
            {
                // copy saved faces
                faces = savedFaces;
            }

            // copy to unity structure
            TransferFacesToMesh();
        }