// 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); } } }
// 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); }