void InitCSGTree() { csgTree = CSGUtility.LoadTree("import.xml", out instanceNodes); if (csgTree == null) { MessageBox.Show("Failed to load file"); return; } instanceNodeTranslations = new List <Vector3>(); if (instanceNodes != null && instanceNodes.Count > 0) { foreach (var node in instanceNodes) { instanceNodeTranslations.Add(node.LocalTranslation); } subInstanceBrushes = new HashSet <CSGNode>(); foreach (var node in instanceNodes) { foreach (var brush in CSGUtility.FindChildBrushes(node)) { subInstanceBrushes.Add(brush); } } allBrushes = (from node in CSGUtility.FindChildBrushes(csgTree) where !subInstanceBrushes.Contains(node) select node).ToList(); } else { allBrushes = CSGUtility.FindChildBrushes(csgTree).ToList(); } var updateNodes = new List <CSGNode>(); updateNodes.AddRange(allBrushes); updateNodes.AddRange(instanceNodes); UpdateMeshes(csgTree, updateNodes); }
void AnimateInstanceNodes(double time) { if (instanceNodes == null || instanceNodes.Count == 0) { return; } var revolutionsPerSecond = 0.75f; var t = ((time * revolutionsPerSecond) * Math.PI); var radiusX = 15.0f; var radiusY = 15.0f; var translation = new Vector3((float)(Math.Cos(t) * radiusX), (float)(Math.Sin(t) * radiusY), 0); var foundNodes = new HashSet <CSGNode>(); for (int i = 0; i < instanceNodes.Count; ++i) { var node = instanceNodes[i]; var nodeBounds = node.Bounds; var nodeTrans = node.Translation; for (int j = 0; j < allBrushes.Count; ++j) { var otherBrush = allBrushes[j]; if (foundNodes.Contains(otherBrush)) { continue; } var otherBrushBounds = otherBrush.Bounds; var otherBrushTrans = otherBrush.Translation; var relativeTrans = Vector3.Subtract(nodeTrans, otherBrushTrans); if (!AABB.IsOutside(nodeBounds, relativeTrans, otherBrushBounds)) { foundNodes.Add(otherBrush); } } } for (int i = 0; i < instanceNodes.Count; ++i) { var node = instanceNodes[i]; node.LocalTranslation = Vector3.Add(instanceNodeTranslations[i], translation); if (node.Parent != null) { node.Translation = node.LocalTranslation + node.Parent.Translation; } else { node.Translation = node.LocalTranslation; } CSGUtility.UpdateChildTransformations(node); foundNodes.Add(node); } for (int i = 0; i < instanceNodes.Count; ++i) { var node = instanceNodes[i]; var nodeBounds = node.Bounds; var nodeTrans = node.Translation; for (int j = 0; j < allBrushes.Count; ++j) { var otherBrush = allBrushes[j]; if (foundNodes.Contains(otherBrush)) { continue; } var otherBrushBounds = otherBrush.Bounds; var otherBrushTrans = otherBrush.Translation; var relativeTrans = Vector3.Subtract(nodeTrans, otherBrushTrans); if (!AABB.IsOutside(node.Bounds, relativeTrans, otherBrush.Bounds)) { foundNodes.Add(otherBrush); } } } UpdateMeshes(csgTree, foundNodes); }
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 (!cachedBaseMeshes.TryGetValue(node, out mesh)) { // 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); var brushMeshes = ProcessCSGNodes(node, childNodes); mesh = CSGMesh.Combine(node.Translation, brushMeshes); } else { mesh = CSGMesh.CreateFromPlanes(node.Planes); } // Cache the mesh cachedBaseMeshes[node] = mesh; } // 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); * /*/ Parallel.ForEach(nodes, buildMesh); CSGUtility.UpdateBounds(root); Parallel.ForEach(meshes, updateDelegate); //*/ return(meshes); }