Exemplo n.º 1
0
 public CSGNode(CSGNodeType branchOperator)
 {
     this.NodeType = branchOperator;
     this.Left = null; this.Right = null;
     this.Translation = new Vector3(0, 0, 0);
     this.LocalTranslation = new Vector3(0, 0, 0);
 }
Exemplo n.º 2
0
 public static void UpdateChildTransformations(CSGNode node)
 {
     if (node.NodeType == CSGNodeType.Brush)
         return;
     UpdateChildTransformations(node.Left, node.Translation);
     UpdateChildTransformations(node.Right, node.Translation);
 }
Exemplo n.º 3
0
 public static void UpdateChildTransformations(CSGNode node, Vector3 parentTranslation)
 {
     node.Translation = Vector3.Add(parentTranslation, node.LocalTranslation);
     if (node.NodeType == CSGNodeType.Brush)
         return;
     UpdateChildTransformations(node.Left, node.Translation);
     UpdateChildTransformations(node.Right, node.Translation);
 }
Exemplo n.º 4
0
 public static void UpdateChildTransformations(CSGNode node)
 {
     if (node.NodeType == CSGNodeType.Brush)
     {
         return;
     }
     UpdateChildTransformations(node.Left, node.Translation);
     UpdateChildTransformations(node.Right, node.Translation);
 }
Exemplo n.º 5
0
 public static void UpdateChildTransformations(CSGNode node, Vector3 parentTranslation)
 {
     node.Translation = Vector3.Add(parentTranslation, node.LocalTranslation);
     if (node.NodeType == CSGNodeType.Brush)
     {
         return;
     }
     UpdateChildTransformations(node.Left, node.Translation);
     UpdateChildTransformations(node.Right, node.Translation);
 }
Exemplo n.º 6
0
 public CSGNode(CSGNodeType branchOperator, CSGNode left, CSGNode right)
 {
     this.NodeType         = branchOperator;
     this.Left             = left;
     this.Right            = right;
     this.Translation      = new Vector3(0, 0, 0);
     this.LocalTranslation = new Vector3(0, 0, 0);
     left.Parent           = this;
     right.Parent          = this;
 }
Exemplo n.º 7
0
 public CSGNode(CSGNodeType branchOperator, CSGNode left, CSGNode right)
 {
     this.NodeType = branchOperator;
     this.Left = left;
     this.Right = right;
     this.Translation = new Vector3(0, 0, 0);
     this.LocalTranslation = new Vector3(0, 0, 0);
     left.Parent = this;
     right.Parent = this;
 }
Exemplo n.º 8
0
 public static IEnumerable<CSGNode> FindChildNodes(CSGNode node)
 {
     yield return node;
     if (node.NodeType != CSGNodeType.Brush)
     {
         foreach (var child in FindChildNodes(node.Left))
             yield return child;
         foreach (var child in FindChildNodes(node.Right))
             yield return child;
     }
 }
Exemplo n.º 9
0
 public static IEnumerable<CSGNode> FindChildBrushes(CSGNode node)
 {
     if (node.NodeType != CSGNodeType.Brush)
     {
         foreach (var brush in FindChildBrushes(node.Left))
             yield return brush;
         foreach (var brush in FindChildBrushes(node.Right))
             yield return brush;
         yield break;
     }
     else
         yield return node;
 }
Exemplo n.º 10
0
        private static void UpdateMesh(CSGNode node, CSGNode root)
        {
            //if (node.Left != null) UpdateMesh(node.Left, node);
            //if (node.Right != null) UpdateMesh(node.Right, node);

            var processedNode = node;
            var processedMesh = node.cachedMesh;

            var inputPolygons    = processedMesh.Polygons;
            var insidePolygons   = new List <Polygon>(inputPolygons.Count);
            var outsidePolygons  = new List <Polygon>(inputPolygons.Count);
            var alignedPolygons  = new List <Polygon>(inputPolygons.Count);
            var reversedPolygons = new List <Polygon>(inputPolygons.Count);

            CSGCategorization.Categorize(processedNode,
                                         processedMesh,

                                         root,

                                         inputPolygons, // these are the polygons that are categorized

                                         insidePolygons,
                                         alignedPolygons,
                                         reversedPolygons,
                                         outsidePolygons
                                         );

            // Flag all non aligned polygons as being invisible, and store their categorizations
            // so we can use it if we instance this mesh.
            foreach (var polygon in insidePolygons)
            {
                polygon.Category = PolygonCategory.Inside;
                polygon.Visible  = false;
            }

            foreach (var polygon in outsidePolygons)
            {
                polygon.Category = PolygonCategory.Outside;
                polygon.Visible  = false;
            }

            foreach (var polygon in alignedPolygons)
            {
                polygon.Category = PolygonCategory.Aligned;
            }

            foreach (var polygon in reversedPolygons)
            {
                polygon.Category = PolygonCategory.ReverseAligned;
            }
        }
Exemplo n.º 11
0
        public static void UpdateBounds(CSGNode node)
        {
            if (node.NodeType != CSGNodeType.Brush)
            {
                var leftNode  = node.Left;
                var rightNode = node.Right;
                UpdateBounds(leftNode);
                UpdateBounds(rightNode);

                node.Bounds.Clear();
                node.Bounds.Add(leftNode.Bounds.Translated(Vector3.Subtract(leftNode.Translation, node.Translation)));
                node.Bounds.Add(rightNode.Bounds.Translated(Vector3.Subtract(rightNode.Translation, node.Translation)));
            }
        }
Exemplo n.º 12
0
        public static void UpdateBounds(CSGNode node)
        {
            if (node.NodeType != CSGNodeType.Brush)
            {
                var leftNode = node.Left;
                var rightNode = node.Right;
                UpdateBounds(leftNode);
                UpdateBounds(rightNode);

                node.Bounds.Clear();
                node.Bounds.Add(leftNode.Bounds.Translated(Vector3.Subtract(leftNode.Translation, node.Translation)));
                node.Bounds.Add(rightNode.Bounds.Translated(Vector3.Subtract(rightNode.Translation, node.Translation)));
            }
        }
Exemplo n.º 13
0
        public static IEnumerable<CSGNode> FindChildBrushes(CSGNode node, Microsoft.Xna.Framework.Matrix transformation)
        {
            node.WorldTransformation = node.Transformation.Transform * transformation;

            if (node.NodeType != CSGNodeType.Brush)
            {
                foreach (var brush in FindChildBrushes(node.Left, node.WorldTransformation))
                    yield return brush;
                foreach (var brush in FindChildBrushes(node.Right, node.WorldTransformation))
                    yield return brush;
                yield break;
            }
            else
                yield return node;
        }
Exemplo n.º 14
0
        public static IEnumerable <CSGNode> FindChildNodes(CSGNode node)
        {
            yield return(node);

            if (node.NodeType != CSGNodeType.Brush)
            {
                foreach (var child in FindChildNodes(node.Left))
                {
                    yield return(child);
                }
                foreach (var child in FindChildNodes(node.Right))
                {
                    yield return(child);
                }
            }
        }
Exemplo n.º 15
0
 public static IEnumerable <CSGNode> FindChildBrushes(CSGNode node)
 {
     if (node.NodeType != CSGNodeType.Brush)
     {
         foreach (var brush in FindChildBrushes(node.Left))
         {
             yield return(brush);
         }
         foreach (var brush in FindChildBrushes(node.Right))
         {
             yield return(brush);
         }
         yield break;
     }
     else
     {
         yield return(node);
     }
 }
Exemplo n.º 16
0
        //public static IEnumerable<CSGNode> FindChildNodes(CSGNode node)
        //{
        //    yield return node;
        //    if (node.NodeType != CSGNodeType.Brush)
        //    {
        //        foreach (var child in FindChildNodes(node.Left))
        //            yield return child;
        //        foreach (var child in FindChildNodes(node.Right))
        //            yield return child;
        //    }
        //}
        #endregion

        #region FindChildBrushes
        public static IEnumerable <CSGNode> FindChildBrushes(CSGNode node, Microsoft.Xna.Framework.Matrix transformation)
        {
            node.WorldTransformation = node.Transformation.Transform * transformation;

            if (node.NodeType != CSGNodeType.Brush)
            {
                foreach (var brush in FindChildBrushes(node.Left, node.WorldTransformation))
                {
                    yield return(brush);
                }
                foreach (var brush in FindChildBrushes(node.Right, node.WorldTransformation))
                {
                    yield return(brush);
                }
                yield break;
            }
            else
            {
                yield return(node);
            }
        }
Exemplo n.º 17
0
        // Create meshes for a given number of nodes and perform CSG on these.
        #region ProcessCSGNodes

        private static void ProcessNode(CSGNode node, CSGNode root)
        {
            if (node.cachedMesh == null)
            {
                if (node.NodeType != CSGNodeType.Brush)
                {
                    ProcessNode(node.Left, node);
                    ProcessNode(node.Right, node);
                    node.cachedMesh = CSGMesh.Combine(node.Translation, node.Left, node.Right);

                    node.Bounds.Clear();
                    node.Bounds.Add(node.Left.Bounds.Translated(Vector3.Subtract(node.Left.Translation, node.Translation)));
                    node.Bounds.Add(node.Right.Bounds.Translated(Vector3.Subtract(node.Right.Translation, node.Translation)));

                    UpdateMesh(node, root);
                }
                else
                {
                    node.cachedMesh = CSGMesh.CreateFromPlanes(node.Generator.GetPlanes(node.WorldTransformation));

                    node.Bounds.Set(node.cachedMesh.Bounds);
                }
            }
        }
        static void FindParentNode(Transform opTransform, out CSGNode parentNode, out Transform parentTransform)
        {
            var iterator = opTransform.parent;

            while (iterator)
            {
                var currentNodeObj = iterator.GetComponent(TypeConstants.CSGNodeType);
                if (currentNodeObj)
                {
                    var operationNode = currentNodeObj as CSGOperation;
                    if (!operationNode ||
                        !operationNode.PassThrough)
                    {
                        parentNode      = currentNodeObj as CSGNode;
                        parentTransform = iterator;
                        return;
                    }
                }

                iterator = iterator.parent;
            }
            parentTransform = null;
            parentNode      = null;
        }
Exemplo n.º 19
0
 public void Init(CSGNode node, Int32 nodeID)
 {
     Transform   = node.transform;
     TransformID = node.transform.GetInstanceID();
     NodeID      = nodeID;
 }
Exemplo n.º 20
0
 public CSGNode(string id, CSGNodeType branchOperator, CSGNode left, CSGNode right)
 {
     this.NodeType = branchOperator; this.Left = left; this.Right = right;
 }
Exemplo n.º 21
0
        void CreateVisualObjects()
        {
            CleanUp();

            //Debug.Log("CreateVisualObjects");
            //prevForceGrid = Grid.ForceGrid;
            prevForcedGridCenter   = Grid.ForcedGridCenter;
            prevForcedGridRotation = Grid.ForcedGridRotation;

            sourceSurfaceAlignment      = PrefabSourceAlignment.AlignedFront;
            destinationSurfaceAlignment = PrefabDestinationAlignment.AlignToSurface;


            visualDragGameObject = new List <GameObject>();

            foreach (var obj in dragGameObjects)
            {
                CSGNode node = obj.GetComponent <CSGNode>();
                if (!node)
                {
                    continue;
                }
                sourceSurfaceAlignment      = node.PrefabSourceAlignment;
                destinationSurfaceAlignment = node.PrefabDestinationAlignment;

                GameObject copy;
                if (node && node.PrefabBehaviour == PrefabInstantiateBehaviour.Copy)
                {
                    copy = GameObject.Instantiate <GameObject>(obj);
                }
                else
                {
                    copy = PrefabUtility.InstantiatePrefab(obj) as GameObject;
                }
                if (!copy)
                {
                    continue;
                }

                copy.name = obj.name;
                visualDragGameObject.Add(copy);
            }

            var model = SelectionUtility.LastUsedModel;

            if (model)
            {
                var parent  = model.transform;
                int counter = 0;
                foreach (var obj in visualDragGameObject)
                {
                    if (!obj)
                    {
                        continue;
                    }
                    if (obj.activeSelf)
                    {
                        obj.transform.SetParent(parent, false);
                        obj.transform.SetSiblingIndex(hoverSiblingIndex + counter);
                        counter++;
                    }
                }
            }
        }
Exemplo n.º 22
0
 public static void Init(this HierarchyItem self, CSGNode node, Int32 nodeID)
 {
     self.Transform   = node.transform;
     self.TransformID = node.transform.GetInstanceID();
     self.NodeID      = nodeID;
 }
Exemplo n.º 23
0
        // Categorize the given inputPolygons as being inside/outside or (reverse-)aligned
        // with the shape that is defined by the current brush or csg-branch.
        // When an inputPolygon crosses the node, it is split into pieces and every individual
        // piece is then categorized.
        #region Categorize
        public static void Categorize(CSGNode processedNode,
                                      CSGMesh processedMesh,

                                      CSGNode categorizationNode,

                                      List <Polygon> inputPolygons,

                                      List <Polygon> inside,
                                      List <Polygon> aligned,
                                      List <Polygon> revAligned,
                                      List <Polygon> outside)
        {
            // When you go deep enough in the tree it's possible that all categories point to the same
            // destination. So we detect that and potentially avoid a lot of wasted work.
            if (inside == revAligned &&
                inside == aligned &&
                inside == outside)
            {
                inside.AddRange(inputPolygons);
                return;
            }

Restart:
            if (processedNode == categorizationNode)
            {
                // When the currently processed node is the same node as we categorize against, then
                // we know that all our polygons are visible and we set their default category
                // (usually aligned, unless it's an instancing node in which case it's precalculated)
                foreach (var polygon in inputPolygons)
                {
                    switch (polygon.Category)
                    {
                    case PolygonCategory.Aligned:                   aligned.Add(polygon); break;

                    case PolygonCategory.ReverseAligned:    revAligned.Add(polygon); break;

                    case PolygonCategory.Inside:                    inside.Add(polygon); break;

                    case PolygonCategory.Outside:                   outside.Add(polygon); break;
                    }

                    // When brushes overlap and they share the same surface area we only want to keep
                    // the polygons of the last brush in the tree, and skip all others.
                    // At this point in the tree we know that this polygon belongs to this brush, so
                    // we set it to visible. If the polygon is found to share the surface area with another
                    // brush further on in the tree it'll be set to invisible again in mesh.Intersect.
                    polygon.Visible = true;
                }
                return;
            }

            var leftNode  = categorizationNode.Left;
            var rightNode = categorizationNode.Right;

            switch (categorizationNode.NodeType)
            {
            case CSGNodeType.Brush:
            {
                processedMesh.Intersect(categorizationNode.Bounds,
                                        categorizationNode.Generator.GetPlanes(categorizationNode.WorldTransformation),
                                        categorizationNode.Translation,
                                        processedNode.Translation,

                                        inputPolygons,

                                        inside, aligned, revAligned, outside);
                break;
            }

            case CSGNodeType.Addition:
            {
                //  ( A ||  B)
                var relativeLeftTrans  = Vector3.Subtract(processedNode.Translation, leftNode.Translation);
                var relativeRightTrans = Vector3.Subtract(processedNode.Translation, rightNode.Translation);
                if (AABB.IsOutside(processedNode.Bounds, relativeLeftTrans, leftNode.Bounds))
                {
                    if (AABB.IsOutside(processedNode.Bounds, relativeRightTrans, rightNode.Bounds))
                    {
                        // When our polygons lie outside the bounds of both the left and the right node, then
                        // all the polygons can be categorized as being 'outside'
                        outside.AddRange(inputPolygons);
                    }
                    else
                    {
                        //Categorize(processedNode, mesh, right,
                        //           inputPolygons,
                        //           inside, aligned, revAligned, outside);
                        categorizationNode = rightNode;
                        goto Restart;
                    }
                }
                else
                if (AABB.IsOutside(processedNode.Bounds, relativeRightTrans, rightNode.Bounds))
                {
                    //Categorize(processedNode, left, mesh,
                    //           inputPolygons,
                    //           inside, aligned, revAligned, outside);
                    categorizationNode = leftNode;
                    goto Restart;
                }
                else
                {
                    LogicalOr(processedNode, processedMesh, categorizationNode,
                              inputPolygons,
                              inside, aligned, revAligned, outside,
                              false, false);
                }
                break;
            }

            case CSGNodeType.Common:
            {
                // !(!A || !B)
                var relativeLeftTrans  = Vector3.Subtract(processedNode.Translation, leftNode.Translation);
                var relativeRightTrans = Vector3.Subtract(processedNode.Translation, rightNode.Translation);
                if (AABB.IsOutside(processedNode.Bounds, relativeLeftTrans, leftNode.Bounds) ||
                    AABB.IsOutside(processedNode.Bounds, relativeRightTrans, rightNode.Bounds))
                {
                    // When our polygons lie outside the bounds of both the left and the right node, then
                    // all the polygons can be categorized as being 'outside'
                    outside.AddRange(inputPolygons);
                }
                else
                {
                    LogicalOr(processedNode, processedMesh, categorizationNode,
                              inputPolygons,
                              outside, revAligned, aligned, inside,
                              true, true);
                }
                break;
            }

            case CSGNodeType.Subtraction:
            {
                // !(!A ||  B)
                var relativeLeftTrans  = Vector3.Subtract(processedNode.Translation, leftNode.Translation);
                var relativeRightTrans = Vector3.Subtract(processedNode.Translation, rightNode.Translation);
                if (AABB.IsOutside(processedNode.Bounds, relativeLeftTrans, leftNode.Bounds))
                {
                    // When our polygons lie outside the bounds of both the left node, then
                    // all the polygons can be categorized as being 'outside'
                    outside.AddRange(inputPolygons);
                }
                else
                if (AABB.IsOutside(processedNode.Bounds, relativeRightTrans, rightNode.Bounds))
                {
                    categorizationNode = leftNode;
                    goto Restart;
                }
                else
                {
                    LogicalOr(processedNode, processedMesh, categorizationNode,
                              inputPolygons,
                              outside, revAligned, aligned, inside,
                              true, false);
                }
                break;
            }
            }
        }
Exemplo n.º 24
0
        // We cache our base meshes here
        public static ConcurrentDictionary <CSGNode, CSGMesh> ProcessCSGNodes(CSGNode root, IEnumerable <CSGNode> nodes)
        {
            var meshes    = new ConcurrentDictionary <CSGNode, CSGMesh>();
            var buildMesh =
                (Action <CSGNode>)
                delegate(CSGNode node)
            {
                CSGMesh mesh;

                if (node.cachedMesh == null)
                {
                    // If the node we're performing csg on is a brush, we simply create the geometry from the planes
                    // If the node is a more complicated node, we perform csg on it's child nodes and combine the
                    // meshes that are created.
                    // Note that right now we cache brushes per node, but we can improve on this by caching on
                    // node type instead. Since lots of nodes will have the same geometry in real life and only
                    // need to be created once. It won't help much in runtime performance considering they're
                    // cached anyway, but it'll save on memory usage.
                    if (node.NodeType != CSGNodeType.Brush)
                    {
                        var childNodes  = CSGUtility.FindChildBrushes(node, root.Transformation.Transform);
                        var brushMeshes = ProcessCSGNodes(node, childNodes);
                        mesh = CSGMesh.Combine(node.Translation, brushMeshes);
                    }
                    else
                    {
                        mesh = CSGMesh.CreateFromPlanes(node.Generator.GetPlanes(node.WorldTransformation));
                    }

                    // Cache the mesh
                    node.cachedMesh = mesh;
                }
                else
                {
                    mesh = node.cachedMesh;
                }

                // Clone the cached mesh so we can perform CSG on it.
                var clonedMesh = mesh;                                //.Clone();
                node.Bounds.Set(clonedMesh.Bounds);
                meshes[node] = clonedMesh;
            };

            var updateDelegate =
                (Action <KeyValuePair <CSGNode, CSGMesh> >)
                delegate(KeyValuePair <CSGNode, CSGMesh> item)
            {
                var processedNode = item.Key;
                var processedMesh = item.Value;

                var inputPolygons    = processedMesh.Polygons;
                var insidePolygons   = new List <Polygon>(inputPolygons.Count);
                var outsidePolygons  = new List <Polygon>(inputPolygons.Count);
                var alignedPolygons  = new List <Polygon>(inputPolygons.Count);
                var reversedPolygons = new List <Polygon>(inputPolygons.Count);

                CSGCategorization.Categorize(processedNode,
                                             processedMesh,

                                             root,

                                             inputPolygons,                                                             // these are the polygons that are categorized

                                             insidePolygons,
                                             alignedPolygons,
                                             reversedPolygons,
                                             outsidePolygons
                                             );

                // Flag all non aligned polygons as being invisible, and store their categorizations
                // so we can use it if we instance this mesh.
                foreach (var polygon in insidePolygons)
                {
                    polygon.Category = PolygonCategory.Inside;
                    polygon.Visible  = false;
                }

                foreach (var polygon in outsidePolygons)
                {
                    polygon.Category = PolygonCategory.Outside;
                    polygon.Visible  = false;
                }

                foreach (var polygon in alignedPolygons)
                {
                    polygon.Category = PolygonCategory.Aligned;
                }

                foreach (var polygon in reversedPolygons)
                {
                    polygon.Category = PolygonCategory.ReverseAligned;
                }
            };


            //
            // Here we run build the meshes and perform csg on them either in serial or parallel
            //


            foreach (var node in nodes)
            {
                buildMesh(node);
            }
            CSGUtility.UpdateBounds(root);
            foreach (var item in meshes)
            {
                updateDelegate(item);
            }

            //ProcessNode(root, root);
            //Parallel.ForEach(nodes, ProcessNode);

            //CSGUtility.UpdateBounds(root);
            //UpdateMesh(root, root);

            //Parallel.ForEach(meshes, updateDelegate);

            //*/
            return(meshes);
        }
Exemplo n.º 25
0
        private static void UpdateMesh(CSGNode node, CSGNode root)
        {
            //if (node.Left != null) UpdateMesh(node.Left, node);
            //if (node.Right != null) UpdateMesh(node.Right, node);

            var processedNode = node;
            var processedMesh = node.cachedMesh;

            var inputPolygons = processedMesh.Polygons;
            var insidePolygons = new List<Polygon>(inputPolygons.Count);
            var outsidePolygons = new List<Polygon>(inputPolygons.Count);
            var alignedPolygons = new List<Polygon>(inputPolygons.Count);
            var reversedPolygons = new List<Polygon>(inputPolygons.Count);

            CSGCategorization.Categorize(processedNode,
                                         processedMesh,

                                         root,

                                         inputPolygons,	// these are the polygons that are categorized

                                         insidePolygons,
                                         alignedPolygons,
                                         reversedPolygons,
                                         outsidePolygons
                                        );

            // Flag all non aligned polygons as being invisible, and store their categorizations
            // so we can use it if we instance this mesh.
            foreach (var polygon in insidePolygons)
            {
                polygon.Category = PolygonCategory.Inside;
                polygon.Visible = false;
            }

            foreach (var polygon in outsidePolygons)
            {
                polygon.Category = PolygonCategory.Outside;
                polygon.Visible = false;
            }

            foreach (var polygon in alignedPolygons)
                polygon.Category = PolygonCategory.Aligned;

            foreach (var polygon in reversedPolygons)
                polygon.Category = PolygonCategory.ReverseAligned;
        }
Exemplo n.º 26
0
        private static void ProcessNode(CSGNode node, CSGNode root)
        {
            if (node.cachedMesh == null)
            {
                if (node.NodeType != CSGNodeType.Brush)
                {
                    ProcessNode(node.Left, node);
                    ProcessNode(node.Right, node);
                    node.cachedMesh = CSGMesh.Combine(node.Translation, node.Left, node.Right);

                    node.Bounds.Clear();
                    node.Bounds.Add(node.Left.Bounds.Translated(Vector3.Subtract(node.Left.Translation, node.Translation)));
                    node.Bounds.Add(node.Right.Bounds.Translated(Vector3.Subtract(node.Right.Translation, node.Translation)));

                    UpdateMesh(node, root);
                }
                else
                {
                    node.cachedMesh = CSGMesh.CreateFromPlanes(node.Generator.GetPlanes(node.WorldTransformation));

                    node.Bounds.Set(node.cachedMesh.Bounds);
                }

            }
        }
Exemplo n.º 27
0
        // We cache our base meshes here
        public static ConcurrentDictionary<CSGNode, CSGMesh> ProcessCSGNodes(CSGNode root, IEnumerable<CSGNode> nodes)
        {
            var meshes = new ConcurrentDictionary<CSGNode, CSGMesh>();
            var buildMesh =
                (Action<CSGNode>)
                    delegate(CSGNode node)
                    {
                        CSGMesh mesh;

                        if (node.cachedMesh == null)
                        {
                            // If the node we're performing csg on is a brush, we simply create the geometry from the planes
                            // If the node is a more complicated node, we perform csg on it's child nodes and combine the
                            // meshes that are created.
                            // Note that right now we cache brushes per node, but we can improve on this by caching on
                            // node type instead. Since lots of nodes will have the same geometry in real life and only
                            // need to be created once. It won't help much in runtime performance considering they're
                            // cached anyway, but it'll save on memory usage.
                            if (node.NodeType != CSGNodeType.Brush)
                            {
                                var childNodes = CSGUtility.FindChildBrushes(node, root.Transformation.Transform);
                                var brushMeshes = ProcessCSGNodes(node, childNodes);
                                mesh = CSGMesh.Combine(node.Translation, brushMeshes);
                            }
                            else
                                mesh = CSGMesh.CreateFromPlanes(node.Generator.GetPlanes(node.WorldTransformation));

                            // Cache the mesh
                            node.cachedMesh = mesh;
                        }
                        else
                            mesh = node.cachedMesh;

                        // Clone the cached mesh so we can perform CSG on it.
                        var clonedMesh = mesh;//.Clone();
                        node.Bounds.Set(clonedMesh.Bounds);
                        meshes[node] = clonedMesh;
                    };

            var updateDelegate =
                (Action<KeyValuePair<CSGNode, CSGMesh>>)
                    delegate(KeyValuePair<CSGNode, CSGMesh> item)
                    {
                        var processedNode		= item.Key;
                        var processedMesh		= item.Value;

                        var inputPolygons		= processedMesh.Polygons;
                        var insidePolygons		= new List<Polygon>(inputPolygons.Count);
                        var outsidePolygons		= new List<Polygon>(inputPolygons.Count);
                        var alignedPolygons		= new List<Polygon>(inputPolygons.Count);
                        var reversedPolygons	= new List<Polygon>(inputPolygons.Count);

                        CSGCategorization.Categorize(processedNode,
                                                     processedMesh,

                                                     root,

                                                     inputPolygons,	// these are the polygons that are categorized

                                                     insidePolygons,
                                                     alignedPolygons,
                                                     reversedPolygons,
                                                     outsidePolygons
                                                    );

                        // Flag all non aligned polygons as being invisible, and store their categorizations
                        // so we can use it if we instance this mesh.
                        foreach (var polygon in insidePolygons)
                        {
                            polygon.Category = PolygonCategory.Inside;
                            polygon.Visible = false;
                        }

                        foreach (var polygon in outsidePolygons)
                        {
                            polygon.Category = PolygonCategory.Outside;
                            polygon.Visible = false;
                        }

                        foreach (var polygon in alignedPolygons)
                            polygon.Category = PolygonCategory.Aligned;

                        foreach (var polygon in reversedPolygons)
                            polygon.Category = PolygonCategory.ReverseAligned;
                    };

            //
            // Here we run build the meshes and perform csg on them either in serial or parallel
            //

            foreach (var node in nodes)
                buildMesh(node);
            CSGUtility.UpdateBounds(root);
            foreach (var item in meshes)
                updateDelegate(item);

            //ProcessNode(root, root);
            //Parallel.ForEach(nodes, ProcessNode);

            //CSGUtility.UpdateBounds(root);
            //UpdateMesh(root, root);

            //Parallel.ForEach(meshes, updateDelegate);

            //*/
            return meshes;
        }
Exemplo n.º 28
0
        public static void Categorize(CSGNode			processedNode,
									  CSGMesh			processedMesh,
								 	  
									  CSGNode			categorizationNode,

									  List<Polygon>		inputPolygons,

									  List<Polygon>		inside,
									  List<Polygon>		aligned,
									  List<Polygon>		revAligned,
									  List<Polygon>		outside)
        {
            // When you go deep enough in the tree it's possible that all categories point to the same
            // destination. So we detect that and potentially avoid a lot of wasted work.
            if (inside == revAligned &&
                inside == aligned &&
                inside == outside)
            {
                inside.AddRange(inputPolygons);
                return;
            }

            Restart:
            if (processedNode == categorizationNode)
            {
                // When the currently processed node is the same node as we categorize against, then
                // we know that all our polygons are visible and we set their default category
                // (usually aligned, unless it's an instancing node in which case it's precalculated)
                foreach (var polygon in inputPolygons)
                {
                    switch (polygon.Category)
                    {
                        case PolygonCategory.Aligned:			aligned.Add(polygon); break;
                        case PolygonCategory.ReverseAligned:	revAligned.Add(polygon); break;
                        case PolygonCategory.Inside:			inside.Add(polygon); break;
                        case PolygonCategory.Outside:			outside.Add(polygon); break;
                    }

                    // When brushes overlap and they share the same surface area we only want to keep
                    // the polygons of the last brush in the tree, and skip all others.
                    // At this point in the tree we know that this polygon belongs to this brush, so
                    // we set it to visible. If the polygon is found to share the surface area with another
                    // brush further on in the tree it'll be set to invisible again in mesh.Intersect.
                    polygon.Visible = true;
                }
                return;
            }

            var leftNode	= categorizationNode.Left;
            var rightNode	= categorizationNode.Right;

            switch (categorizationNode.NodeType)
            {
                case CSGNodeType.Brush:
                {
                    processedMesh.Intersect( categorizationNode.Bounds,
                                             categorizationNode.Generator.GetPlanes(categorizationNode.WorldTransformation),
                                             categorizationNode.Translation,
                                             processedNode.Translation,

                                             inputPolygons,

                                             inside, aligned, revAligned, outside);
                    break;
                }

                case CSGNodeType.Addition:
                {
                    //  ( A ||  B)
                    var relativeLeftTrans	= Vector3.Subtract(processedNode.Translation, leftNode.Translation);
                    var relativeRightTrans	= Vector3.Subtract(processedNode.Translation, rightNode.Translation);
                    if (AABB.IsOutside(processedNode.Bounds, relativeLeftTrans, leftNode.Bounds))
                    {
                        if (AABB.IsOutside(processedNode.Bounds, relativeRightTrans, rightNode.Bounds))
                        {
                            // When our polygons lie outside the bounds of both the left and the right node, then
                            // all the polygons can be categorized as being 'outside'
                            outside.AddRange(inputPolygons);
                        } else
                        {
                            //Categorize(processedNode, mesh, right,
                            //           inputPolygons,
                            //           inside, aligned, revAligned, outside);
                            categorizationNode = rightNode;
                            goto Restart;
                        }
                    } else
                    if (AABB.IsOutside(processedNode.Bounds, relativeRightTrans, rightNode.Bounds))
                    {
                        //Categorize(processedNode, left, mesh,
                        //           inputPolygons,
                        //           inside, aligned, revAligned, outside);
                        categorizationNode = leftNode;
                        goto Restart;
                    } else
                    {
                        LogicalOr(processedNode, processedMesh, categorizationNode,
                                    inputPolygons,
                                    inside, aligned, revAligned, outside,
                                    false, false);
                    }
                    break;
                }

                case CSGNodeType.Common:
                {
                    // !(!A || !B)
                    var relativeLeftTrans	= Vector3.Subtract(processedNode.Translation, leftNode.Translation);
                    var relativeRightTrans	= Vector3.Subtract(processedNode.Translation, rightNode.Translation);
                    if (AABB.IsOutside(processedNode.Bounds, relativeLeftTrans, leftNode.Bounds) ||
                        AABB.IsOutside(processedNode.Bounds, relativeRightTrans, rightNode.Bounds))
                    {
                        // When our polygons lie outside the bounds of both the left and the right node, then
                        // all the polygons can be categorized as being 'outside'
                        outside.AddRange(inputPolygons);
                    } else
                    {
                        LogicalOr(processedNode, processedMesh, categorizationNode,
                                    inputPolygons,
                                    outside, revAligned, aligned, inside,
                                    true, true);
                    }
                    break;
                }

                case CSGNodeType.Subtraction:
                {
                    // !(!A ||  B)
                    var relativeLeftTrans	= Vector3.Subtract(processedNode.Translation, leftNode.Translation);
                    var relativeRightTrans	= Vector3.Subtract(processedNode.Translation, rightNode.Translation);
                    if (AABB.IsOutside(processedNode.Bounds, relativeLeftTrans, leftNode.Bounds))
                    {
                        // When our polygons lie outside the bounds of both the left node, then
                        // all the polygons can be categorized as being 'outside'
                        outside.AddRange(inputPolygons);
                    } else
                    if (AABB.IsOutside(processedNode.Bounds, relativeRightTrans, rightNode.Bounds))
                    {
                        categorizationNode = leftNode;
                        goto Restart;
                    } else
                    {
                        LogicalOr(processedNode, processedMesh, categorizationNode,
                                    inputPolygons,
                                    outside, revAligned, aligned, inside,
                                    true, false);
                    }
                    break;
                }
            }
        }
Exemplo n.º 29
0
        void CreateVisualObjects(bool inSceneView = false)
        {
            CleanUp();

            prevForcedGridCenter   = RealtimeCSG.CSGGrid.ForcedGridCenter;
            prevForcedGridRotation = RealtimeCSG.CSGGrid.ForcedGridRotation;

            sourceSurfaceAlignment      = PrefabSourceAlignment.AlignedFront;
            destinationSurfaceAlignment = PrefabDestinationAlignment.AlignToSurface;


            visualDragGameObject = new List <GameObject>();

            var foundTransforms = new List <Transform>();

            foreach (var obj in dragGameObjects)
            {
                foundTransforms.AddRange(obj.GetComponentsInChildren <Transform>());
                CSGNode node = obj.GetComponent <CSGNode>();
                if (!node)
                {
                    continue;
                }
                sourceSurfaceAlignment      = node.PrefabSourceAlignment;
                destinationSurfaceAlignment = node.PrefabDestinationAlignment;

                bool createCopyInsteadOfInstance = node && node.PrefabBehaviour == PrefabInstantiateBehaviour.Copy;

                GameObject copy = CSGPrefabUtility.Instantiate(obj, createCopyInsteadOfInstance);
                if (!copy)
                {
                    continue;
                }


                copy.name = obj.name;
                visualDragGameObject.Add(copy);
            }

            ignoreTransforms = new HashSet <Transform>(foundTransforms);

            if (inSceneView)
            {
                var model = SelectionUtility.LastUsedModel;
                if (model && !containsModel)
                {
                    var parent  = model.transform;
                    int counter = 0;
                    foreach (var obj in visualDragGameObject)
                    {
                        if (!obj)
                        {
                            continue;
                        }
                        if (obj.activeSelf)
                        {
                            obj.transform.SetParent(parent, false);
                            obj.transform.SetSiblingIndex(hoverSiblingIndex + counter);
                            counter++;
                        }
                    }
                }
            }
            else
            {
                var parent  = hoverParent;
                int counter = 0;
                foreach (var obj in visualDragGameObject)
                {
                    if (!obj)
                    {
                        continue;
                    }
                    if (obj.activeSelf)
                    {
                        obj.transform.SetParent(parent, false);
                        obj.transform.SetSiblingIndex(hoverSiblingIndex + counter);
                        counter++;
                    }
                }
            }
        }
Exemplo n.º 30
0
 public CSGNode(string id, CSGNodeType branchOperator, CSGNode left, CSGNode right)
 {
     this.NodeType = branchOperator; this.Left = left; this.Right = right;
 }
Exemplo n.º 31
0
        // Logical OR set operation on polygons
        //
        // Table showing final output from combination of categorization of left and right node
        //
        //                  | right node
        //                  | inside    aligned     r-aligned   outside
        // -----------------+------------------------------------------
        // left  inside     | I         I           I           I
        // node  aligned    | I         A           I           A
        //       r-aligned  | I         I           R           R
        //       outside    | I         A           R           O
        //
        // I = inside   A = aligned
        // O = outside  R = reverse aligned
        //
        #region LogicalOr
        static void LogicalOr(CSGNode processedNode,
                              CSGMesh processedMesh,

                              CSGNode categorizationNode,

                              List <Polygon> inputPolygons,

                              List <Polygon> inside,
                              List <Polygon> aligned,
                              List <Polygon> revAligned,
                              List <Polygon> outside,

                              bool inverseLeft,
                              bool inverseRight)
        {
            var leftNode        = categorizationNode.Left;
            var rightNode       = categorizationNode.Right;
            var defaultCapacity = inputPolygons.Count / 2;

            // ... Allocations are ridiculously cheap in .NET, there is a garbage collection penalty however.
            // CSG can be performed without temporary buffers and recursion by using flags,
            // which would increase performance and scalability (garbage collection interfers with parallelization).
            // It makes the code a lot harder to read however.
            var leftAligned    = new List <Polygon>(defaultCapacity);
            var leftRevAligned = new List <Polygon>(defaultCapacity);
            var leftOutside    = new List <Polygon>(defaultCapacity);

            //var leftInside	= new List<Polygon>(defaultCapacity); // everything that's inside the left node
            // is always part of the inside category

            // First categorize polygons in left path ...
            if (inverseLeft)
            {
                Categorize(processedNode, processedMesh, leftNode,
                           inputPolygons,
                           leftOutside, leftRevAligned, leftAligned, inside);
            }
            else
            {
                Categorize(processedNode, processedMesh, leftNode,
                           inputPolygons,
                           inside, leftAligned, leftRevAligned, leftOutside);
            }

            // ... Then categorize the polygons in the right path
            // Note that no single polygon will go into more than one of the Categorize methods below
            if (inverseRight)
            {
                if (leftAligned.Count > 0)
                {
                    if (inside == aligned)
                    {
                        inside.AddRange(leftAligned);
                    }
                    else
                    {
                        Categorize(processedNode, processedMesh, rightNode,
                                   leftAligned,
                                   aligned, inside, aligned, inside);
                    }
                }

                if (leftRevAligned.Count > 0)
                {
                    if (inside == revAligned)
                    {
                        inside.AddRange(leftRevAligned);
                    }
                    else
                    {
                        Categorize(processedNode, processedMesh, rightNode,
                                   leftRevAligned,
                                   revAligned, revAligned, inside, inside);
                    }
                }

                if (leftOutside.Count > 0)
                {
                    Categorize(processedNode, processedMesh, rightNode,
                               leftOutside,
                               outside, revAligned, aligned, inside);
                }
            }
            else
            {
                if (leftAligned.Count > 0)
                {
                    if (inside == aligned)
                    {
                        inside.AddRange(leftAligned);
                    }
                    else
                    {
                        Categorize(processedNode, processedMesh, rightNode,
                                   leftAligned,
                                   inside, aligned, inside, aligned);
                    }
                }

                if (leftRevAligned.Count > 0)
                {
                    if (inside == revAligned)
                    {
                        inside.AddRange(leftRevAligned);
                    }
                    else
                    {
                        Categorize(processedNode, processedMesh, rightNode,
                                   leftRevAligned,
                                   inside, inside, revAligned, revAligned);
                    }
                }

                if (leftOutside.Count > 0)
                {
                    Categorize(processedNode, processedMesh, rightNode,
                               leftOutside,
                               inside, aligned, revAligned, outside);
                }
            }
        }
Exemplo n.º 32
0
        static void LogicalOr(	CSGNode			processedNode,
								CSGMesh			processedMesh,
								
								CSGNode			categorizationNode,

								List<Polygon>	inputPolygons,

								List<Polygon>	inside,
								List<Polygon>	aligned,
								List<Polygon>	revAligned,
								List<Polygon>	outside,

								bool			inverseLeft,
								bool			inverseRight)
        {
            var leftNode		= categorizationNode.Left;
            var rightNode		= categorizationNode.Right;
            var defaultCapacity	= inputPolygons.Count / 2;

            // ... Allocations are ridiculously cheap in .NET, there is a garbage collection penalty however.
            // CSG can be performed without temporary buffers and recursion by using flags,
            // which would increase performance and scalability (garbage collection interfers with parallelization).
            // It makes the code a lot harder to read however.
            var leftAligned		= new List<Polygon>(defaultCapacity);
            var leftRevAligned	= new List<Polygon>(defaultCapacity);
            var leftOutside		= new List<Polygon>(defaultCapacity);
            //var leftInside	= new List<Polygon>(defaultCapacity); // everything that's inside the left node
                                                                          // is always part of the inside category

            // First categorize polygons in left path ...
            if (inverseLeft)
                Categorize(processedNode, processedMesh, leftNode,
                            inputPolygons,
                            leftOutside, leftRevAligned, leftAligned, inside);
            else
                Categorize(processedNode, processedMesh, leftNode,
                            inputPolygons,
                            inside, leftAligned, leftRevAligned, leftOutside);

            // ... Then categorize the polygons in the right path
            // Note that no single polygon will go into more than one of the Categorize methods below
            if (inverseRight)
            {
                if (leftAligned.Count > 0)
                {
                    if (inside == aligned)
                    {
                        inside.AddRange(leftAligned);
                    } else
                        Categorize(processedNode, processedMesh, rightNode,
                                    leftAligned,
                                    aligned, inside, aligned, inside);
                }

                if (leftRevAligned.Count > 0)
                {
                    if (inside == revAligned)
                    {
                        inside.AddRange(leftRevAligned);
                    } else
                        Categorize(processedNode, processedMesh, rightNode,
                                    leftRevAligned,
                                    revAligned, revAligned, inside, inside);
                }

                if (leftOutside.Count > 0)
                {
                    Categorize(processedNode, processedMesh, rightNode,
                                leftOutside,
                                outside, revAligned, aligned, inside);
                }
            } else
            {
                if (leftAligned.Count > 0)
                {
                    if (inside == aligned)
                    {
                        inside.AddRange(leftAligned);
                    } else
                        Categorize(processedNode, processedMesh, rightNode,
                                    leftAligned,
                                    inside, aligned, inside, aligned);
                }

                if (leftRevAligned.Count > 0)
                {
                    if (inside == revAligned)
                    {
                        inside.AddRange(leftRevAligned);
                    } else
                        Categorize(processedNode, processedMesh, rightNode,
                                    leftRevAligned,
                                    inside, inside, revAligned, revAligned);
                }

                if (leftOutside.Count > 0)
                {
                    Categorize(processedNode, processedMesh, rightNode,
                                leftOutside,
                                inside, aligned, revAligned, outside);
                }
            }
        }
Exemplo n.º 33
0
 public CSGNode(string id, CSGNodeType branchOperator)
 {
     this.NodeType = branchOperator; this.Left = null; this.Right = null;
 }