public void testBSPTree() { Mesh mesh = (meshFilter.mesh.vertexCount > 0) ? meshFilter.mesh : meshFilter.sharedMesh; PrintMesh(mesh); var materials = new List <Material>(); meshRenderer.GetSharedMaterials(materials); var start = System.DateTime.Now; tree = CSG.BSPTreeCreator.Construct(mesh, materials, maxTrianglesInLeaves, nbCandidates, precision); Debug.Log("BSPTree created in: " + (System.DateTime.Now - start).TotalMilliseconds + " ms"); Debug.Log(tree.PrintString()); Mesh computedMesh = tree.ComputeMesh(); PrintMesh(computedMesh); GameObject go = new GameObject(); go.AddComponent <MeshFilter>().sharedMesh = computedMesh; go.AddComponent <MeshRenderer>().sharedMaterials = tree.Materials.ToArray(); go.transform.localPosition = transform.localPosition; go.transform.localRotation = transform.localRotation; go.transform.localScale = transform.localScale; go.transform.Translate(1.5f, 0, 0); }
// -- UTILS' METHODS FOR THE GENERATION OF A BSPTREE private static bool ConstructInternal(this BSPNode node, int maxTrianglesInLeaves, int nbCandidates, float precision) { if (node == null || node.TrianglesCount <= maxTrianglesInLeaves) { return(true); // return without splitting, it's a leaf } // Compute split Plane plane = node.ChooseSplittingPlane(nbCandidates, precision); if (plane.normal == Vector3.zero) { Debug.Log("Impossible to compute a plane at depth " + node.DepthFromRoot + ". Try to increase precision or number of candidates."); return(false); } Split(node.SubMeshIndices, plane, node.MeshData.vertices, precision, out var zeros, out var plus, out var minus, out var newVertices); // Apply split node.Plane = plane; node.Plus = new BSPNode(node, node.MeshData, plus); node.Minus = new BSPNode(node, node.MeshData, minus); node.SubMeshIndices = zeros; node.MeshData.AddData(newVertices); // recurse bool result = true; result &= node.Plus.ConstructInternal(maxTrianglesInLeaves, nbCandidates, precision); result &= node.Minus.ConstructInternal(maxTrianglesInLeaves, nbCandidates, precision); return(result); }
public static GeneratedShape Intersect(Shape lhs, Shape rhs) { var a = new BSPNode(lhs.CreatePolygons()); var b = new BSPNode(rhs.CreatePolygons()); var polygons = BSPNode.Intersect(a, b).AllPolygons(); return(new GeneratedShape(polygons)); }
public static BSPNode Construct(Mesh inMesh, List <Material> inMaterials, int maxTrianglesInLeaves = 1, int nbCandidates = 5, float precision = 1E-06f) { // retrieve indices by submesh index IndicesList subMeshIndices = new IndicesList(inMesh.subMeshCount); for (int i = 0; i < inMesh.subMeshCount; i++) { Debug.Assert(inMesh.GetTopology(i) == MeshTopology.Triangles, "Only triangle topology is supported by the BSP tree currently."); subMeshIndices.Add(inMesh.GetTriangles(i).ToList()); } var rootNode = new BSPNode(null, new MeshData(inMesh, inMaterials), subMeshIndices); rootNode.ConstructInternal(maxTrianglesInLeaves, nbCandidates, precision); return(rootNode); }
private static Plane ComputeSplittingPlane(this BSPNode node, int triangle) { int subMeshIndex = 0; int firstIndexInSubMesh = triangle * 3; Debug.Assert(firstIndexInSubMesh < node.IndicesCount); while (subMeshIndex < node.SubMeshCount && firstIndexInSubMesh > node[subMeshIndex].Count) { firstIndexInSubMesh -= node[subMeshIndex].Count; subMeshIndex++; } var subMesh = node[subMeshIndex]; var v0 = node.MeshData.vertices[subMesh[firstIndexInSubMesh]]; var v1 = node.MeshData.vertices[subMesh[firstIndexInSubMesh + 1]]; var v2 = node.MeshData.vertices[subMesh[firstIndexInSubMesh + 2]]; Plane plane = new Plane(); plane.Set3Points(v0, v1, v2); return(plane); }
private static Plane ChooseSplittingPlane(this BSPNode node, int nbCandidates, float precision) { Plane bestCandidate = new Plane(); int bestResult = int.MaxValue; for (int i = 0; i < nbCandidates && bestResult > 0; i++) { Plane candidate = node.ComputeSplittingPlane(Random.Range(0, node.TrianglesCount)); if (candidate.normal != Vector3.zero) { int result = SplitCost(node.SubMeshIndices, candidate, node.MeshData.vertices, precision); if (result < bestResult) { bestCandidate = candidate; bestResult = result; } } } return(bestCandidate); }