private void UpdataAABB(double elapsed) { AABB.Clear(); for (int i = 0; i < Count; i++) { float x = PointMassList[i].Position.X; float y = PointMassList[i].Position.Y; AABB.Add(x, y); x += (float)(PointMassList[i].Velocity.X * elapsed); y += (float)(PointMassList[i].Velocity.Y * elapsed); AABB.Add(x, y); } }
/// <summary> Add a primitive to the spatial bin and clip it </summary> /// <param name="primitive">The primitive to add to the bin</param> public void ClipAndAdd(Primitive primitive) { PrimitiveFragment?fragment = primitive.Clip(SplitPlaneLeft)?.Clip(SplitPlaneRight); if (fragment == null) { return; } Fragments.Add(fragment); AABB.Add(fragment); }
//---------------------------------------------------------------------------------------- // //---------------------------------------------------------------------------------------- public void Build(VOXLoader.VoxelData[] data, int max_primitive = 64, int max_depth = 32) { var Stopwatch = new Stopwatch(); Stopwatch.Start(); m_VoxelArray = data; m_MaxPrimitivesPerLeaf = max_primitive; m_NumNodes = 0; m_NumLeaves = 0; m_NumPrimitives = 0; AABB RootAABB = new AABB(data[0].Pos, new Vector3(0.5f, 0.5f, 0.5f)); for (int i = 1; i < data.Length; i++) { RootAABB.Add(new AABB(data[i].Pos, new Vector3(0.5f, 0.5f, 0.5f))); } m_RootNode = new TreeNode(); m_NumNodes++; m_RootNode.m_AABB = new AABB(Vector3.zero, Vector3.zero); m_RootNode.m_AABB.Min = RootAABB.Min; m_RootNode.m_AABB.Max = RootAABB.Max; m_ProcessedVoxelArray = new bool[m_VoxelArray.Length]; for (int i = 0; i < m_ProcessedVoxelArray.Length; i++) { m_ProcessedVoxelArray[i] = false; } SplitNode(m_RootNode); ComputeTreeDepth(); Serialize(); Stopwatch.Stop(); m_BuidTime = Stopwatch.ElapsedMilliseconds; }
// Combines multiple meshes into one #region Combine public static CSGMesh Combine(Vector3 offset, IDictionary <CSGNode, CSGMesh> brushMeshes) { var planeLookup = new Dictionary <Plane, short>(); var vertexLookup = new Dictionary <Vector3, short>(); var planes = new List <Plane>(); var polygons = new List <Polygon>(); var edges = new List <HalfEdge>(); var vertices = new List <Vector3>(); var bounds = new AABB(); bounds.Clear(); int edgeIndex = 0; int polygonIndex = 0; foreach (var item in brushMeshes) { var node = item.Key; var translation = Vector3.Subtract(node.Translation, offset); var mesh = item.Value; foreach (var edge in mesh.Edges) { short vertexIndex; var vertex = Vector3.Add(mesh.Vertices[edge.VertexIndex], translation); if (!vertexLookup.TryGetValue(vertex, out vertexIndex)) { vertexIndex = (short)vertices.Count; vertices.Add(vertex); vertexLookup.Add(vertex, vertexIndex); } var newEdge = new HalfEdge(); newEdge.VertexIndex = vertexIndex; newEdge.NextIndex = (short)(edge.NextIndex + edgeIndex); newEdge.TwinIndex = (short)(edge.TwinIndex + edgeIndex); newEdge.PolygonIndex = (short)(edge.PolygonIndex + polygonIndex); edges.Add(newEdge); } foreach (var polygon in mesh.Polygons) { if (polygon.FirstIndex == -1) { continue; } short planeIndex; var plane = mesh.Planes[polygon.PlaneIndex]; if (!planeLookup.TryGetValue(plane, out planeIndex)) { planeIndex = (short)planes.Count; planes.Add(plane); planeLookup.Add(plane, planeIndex); } var newPolygon = new Polygon(); newPolygon.PlaneIndex = planeIndex; newPolygon.FirstIndex = (short)(polygon.FirstIndex + edgeIndex); newPolygon.Category = polygon.Category; newPolygon.Visible = polygon.Visible; newPolygon.Bounds.Set(polygon.Bounds, translation); polygons.Add(newPolygon); if (newPolygon.Visible) { var first = edges[newPolygon.FirstIndex]; var iterator = first; do { bounds.Add(vertices[iterator.VertexIndex]); iterator = edges[iterator.NextIndex]; } while (iterator != first); } } edgeIndex = edges.Count; polygonIndex = polygons.Count; } return(new CSGMesh(planes.ToArray(), polygons, edges, vertices, bounds)); }
public static CSGMesh CreateFromPlanes(Plane[] brushPlanes) { var planes = new Plane[brushPlanes.Length]; for (int i = 0; i < brushPlanes.Length; i++) { var plane = brushPlanes[i]; planes[i] = new Plane(plane.A, plane.B, plane.C, plane.D); } var pointIntersections = new List <PointIntersection>(planes.Length * planes.Length); var intersectingPlanes = new List <short>(); var vertices = new List <Vector3>(); var edges = new List <HalfEdge>(); // Find all point intersections where 3 (or more planes) intersect for (short planeIndex1 = 0; planeIndex1 < planes.Length - 2; planeIndex1++) { var plane1 = planes[planeIndex1]; for (short planeIndex2 = (short)(planeIndex1 + 1); planeIndex2 < planes.Length - 1; planeIndex2++) { var plane2 = planes[planeIndex2]; for (short planeIndex3 = (short)(planeIndex2 + 1); planeIndex3 < planes.Length; planeIndex3++) { var plane3 = planes[planeIndex3]; // Calculate the intersection var vertex = Plane.Intersection(plane1, plane2, plane3); // Check if the intersection is valid if (float.IsNaN(vertex.X) || float.IsNaN(vertex.Y) || float.IsNaN(vertex.Z) || float.IsInfinity(vertex.X) || float.IsInfinity(vertex.Y) || float.IsInfinity(vertex.Z)) { continue; } intersectingPlanes.Clear(); intersectingPlanes.Add(planeIndex1); intersectingPlanes.Add(planeIndex2); intersectingPlanes.Add(planeIndex3); for (short planeIndex4 = 0; planeIndex4 < planes.Length; planeIndex4++) { if (planeIndex4 == planeIndex1 || planeIndex4 == planeIndex2 || planeIndex4 == planeIndex3) { continue; } var plane4 = planes[planeIndex4]; var side = plane4.OnSide(vertex); if (side == PlaneSideResult.Intersects) { if (planeIndex4 < planeIndex3) { // Already found this vertex goto SkipIntersection; } // We've found another plane which goes trough our found intersection point intersectingPlanes.Add(planeIndex4); } else if (side == PlaneSideResult.Outside) { // Intersection is outside of brush goto SkipIntersection; } } var vertexIndex = (short)vertices.Count; vertices.Add(vertex); // Add intersection point to our list pointIntersections.Add(new PointIntersection(vertexIndex, intersectingPlanes)); SkipIntersection: ; } } } var foundPlanes = new short[2]; // Find all our intersection edges which are formed by a pair of planes // (this could probably be done inside the previous loop) for (int i = 0; i < pointIntersections.Count; i++) { var pointIntersectionA = pointIntersections[i]; for (int j = i + 1; j < pointIntersections.Count; j++) { var pointIntersectionB = pointIntersections[j]; var planesIndicesA = pointIntersectionA.PlaneIndices; var planesIndicesB = pointIntersectionB.PlaneIndices; short foundPlaneIndex = 0; foreach (var currentPlaneIndex in planesIndicesA) { if (!planesIndicesB.Contains(currentPlaneIndex)) { continue; } foundPlanes[foundPlaneIndex] = currentPlaneIndex; foundPlaneIndex++; if (foundPlaneIndex == 2) { break; } } // If foundPlaneIndex is 0 or 1 then either this combination does not exist, // or only goes trough one point if (foundPlaneIndex < 2) { continue; } // Create our found intersection edge var halfEdgeA = new HalfEdge(); var halfEdgeAIndex = (short)edges.Count; edges.Add(halfEdgeA); var halfEdgeB = new HalfEdge(); var halfEdgeBIndex = (short)edges.Count; edges.Add(halfEdgeB); halfEdgeA.TwinIndex = halfEdgeBIndex; halfEdgeB.TwinIndex = halfEdgeAIndex; halfEdgeA.VertexIndex = pointIntersectionA.VertexIndex; halfEdgeB.VertexIndex = pointIntersectionB.VertexIndex; // Add it to our points pointIntersectionA.Edges.Add(new EdgeIntersection( halfEdgeA, foundPlanes[0], foundPlanes[1])); pointIntersectionB.Edges.Add(new EdgeIntersection( halfEdgeB, foundPlanes[0], foundPlanes[1])); } } var polygons = new List <Polygon>(); for (short i = 0; i < (short)planes.Length; i++) { var polygon = new Polygon(); polygon.PlaneIndex = i; polygons.Add(polygon); } var bounds = new AABB(); var direction = new Vector3(); for (int i = pointIntersections.Count - 1; i >= 0; i--) { var pointIntersection = pointIntersections[i]; var pointEdges = pointIntersection.Edges; // Make sure that we have at least 2 edges ... // This may happen when a plane only intersects at a single edge. if (pointEdges.Count <= 2) { pointIntersections.RemoveAt(i); continue; } var vertexIndex = pointIntersection.VertexIndex; var vertex = vertices[vertexIndex]; for (int j = 0; j < pointEdges.Count - 1; j++) { var edge1 = pointEdges[j]; for (int k = j + 1; k < pointEdges.Count; k++) { var edge2 = pointEdges[k]; int planeIndex1 = -1; int planeIndex2 = -1; // Determine if and which of our 2 planes are identical if (edge1.PlaneIndices[0] == edge2.PlaneIndices[0]) { planeIndex1 = 0; planeIndex2 = 0; } else if (edge1.PlaneIndices[0] == edge2.PlaneIndices[1]) { planeIndex1 = 0; planeIndex2 = 1; } else if (edge1.PlaneIndices[1] == edge2.PlaneIndices[0]) { planeIndex1 = 1; planeIndex2 = 0; } else if (edge1.PlaneIndices[1] == edge2.PlaneIndices[1]) { planeIndex1 = 1; planeIndex2 = 1; } else { continue; } HalfEdge ingoing; HalfEdge outgoing; short outgoingIndex; var shared_plane = planes[edge1.PlaneIndices[planeIndex1]]; var edge1_plane = planes[edge1.PlaneIndices[1 - planeIndex1]]; var edge2_plane = planes[edge2.PlaneIndices[1 - planeIndex2]]; direction = Vector3.Cross(shared_plane.Normal, edge1_plane.Normal); // Determine the orientation of our two edges to determine // which edge is in-going, and which one is out-going if (Vector3.Dot(direction, edge2_plane.Normal) < 0) { ingoing = edge2.Edge; outgoingIndex = edge1.Edge.TwinIndex; outgoing = edges[outgoingIndex]; } else { ingoing = edge1.Edge; outgoingIndex = edge2.Edge.TwinIndex; outgoing = edges[outgoingIndex]; } // Link the out-going half-edge to the in-going half-edge ingoing.NextIndex = outgoingIndex; // Add reference to polygon to half-edge, and make sure our // polygon has a reference to a half-edge // Since a half-edge, in this case, serves as a circular // linked list this just works. var polygonIndex = edge1.PlaneIndices[planeIndex1]; ingoing.PolygonIndex = polygonIndex; outgoing.PolygonIndex = polygonIndex; var polygon = polygons[polygonIndex]; polygon.FirstIndex = outgoingIndex; polygon.Bounds.Add(vertex); } } // Add the intersection point to the area of our bounding box bounds.Add(vertex); } return(new CSGMesh(planes, polygons, edges, vertices, bounds)); }
//---------------------------------------------------------------------------------------- // //---------------------------------------------------------------------------------------- void SplitNode(TreeNode node) { Axis SelectedAxis; Vector3 Size = node.m_AABB.Max - node.m_AABB.Min; if (Size.x >= Size.y && Size.x >= Size.z) { SelectedAxis = Axis.Axis_X; } else if (Size.y >= Size.x && Size.y >= Size.z) { SelectedAxis = Axis.Axis_Y; } else { SelectedAxis = Axis.Axis_Z; } AABB LAABB = new AABB(Vector3.zero, Vector3.zero); AABB RAABB = new AABB(Vector3.zero, Vector3.zero); float Len, LLen, RLen; switch (SelectedAxis) { case Axis.Axis_X: Len = (node.m_AABB.Max.x - node.m_AABB.Min.x); LLen = UnityEngine.Mathf.Ceil(Len * 0.5f); LAABB.Min = node.m_AABB.Min; LAABB.Max = new Vector3(LAABB.Min.x + LLen, node.m_AABB.Max.y, node.m_AABB.Max.z); RLen = Len - LLen; RAABB.Max = node.m_AABB.Max; RAABB.Min = new Vector3(RAABB.Max.x - RLen, node.m_AABB.Min.y, node.m_AABB.Min.z); break; case Axis.Axis_Y: Len = (node.m_AABB.Max.y - node.m_AABB.Min.y); LLen = UnityEngine.Mathf.Ceil(Len * 0.5f); LAABB.Min = node.m_AABB.Min; LAABB.Max = new Vector3(node.m_AABB.Max.x, LAABB.Min.y + LLen, node.m_AABB.Max.z); RLen = Len - LLen; RAABB.Max = node.m_AABB.Max; RAABB.Min = new Vector3(node.m_AABB.Min.x, RAABB.Max.y - RLen, node.m_AABB.Min.z); break; case Axis.Axis_Z: Len = (node.m_AABB.Max.z - node.m_AABB.Min.z); LLen = UnityEngine.Mathf.Ceil(Len * 0.5f); LAABB.Min = node.m_AABB.Min; LAABB.Max = new Vector3(node.m_AABB.Max.x, node.m_AABB.Max.y, LAABB.Min.z + LLen); RLen = Len - LLen; RAABB.Max = node.m_AABB.Max; RAABB.Min = new Vector3(node.m_AABB.Min.x, node.m_AABB.Min.y, RAABB.Max.z - RLen); break; } List <int> VoxelList = new List <int>(); AABB NodeAABB = new AABB(Vector3.zero, Vector3.zero); for (int v = 0; v < m_VoxelArray.Length; v++) { if (!m_ProcessedVoxelArray[v]) { if (m_VoxelArray[v].Pos.x >= LAABB.Min.x && m_VoxelArray[v].Pos.x <= LAABB.Max.x && m_VoxelArray[v].Pos.y >= LAABB.Min.y && m_VoxelArray[v].Pos.y <= LAABB.Max.y && m_VoxelArray[v].Pos.z >= LAABB.Min.z && m_VoxelArray[v].Pos.z <= LAABB.Max.z) { VoxelList.Add(v); if (VoxelList.Count == 1) { NodeAABB.Min = m_VoxelArray[v].Pos - new Vector3(0.5f, 0.5f, 0.5f); NodeAABB.Max = m_VoxelArray[v].Pos + new Vector3(0.5f, 0.5f, 0.5f); } else { NodeAABB.Add(new AABB(m_VoxelArray[v].Pos, new Vector3(0.5f, 0.5f, 0.5f))); } } } } if (VoxelList.Count <= m_MaxPrimitivesPerLeaf) //is leaf { node.m_LNode = new TreeNode(); node.m_LNode.m_AABB = new AABB(Vector3.zero, Vector3.zero); node.m_LNode.m_AABB.Min = NodeAABB.Min; node.m_LNode.m_AABB.Max = NodeAABB.Max; node.m_LNode.m_Leaf = new TreeLeaf(); m_NumLeaves++; node.m_LNode.m_Leaf.m_RimitiveList = new List <int>(); for (int v = 0; v < VoxelList.Count; v++) { node.m_LNode.m_Leaf.m_RimitiveList.Add(VoxelList[v]); m_ProcessedVoxelArray[VoxelList[v]] = true; } m_NumPrimitives += node.m_LNode.m_Leaf.m_RimitiveList.Count; } else { node.m_LNode = new TreeNode(); m_NumNodes++; node.m_LNode.m_AABB = new AABB(Vector3.zero, Vector3.zero); node.m_LNode.m_AABB.Min = NodeAABB.Min; node.m_LNode.m_AABB.Max = NodeAABB.Max; SplitNode(node.m_LNode); } VoxelList.Clear(); for (int v = 0; v < m_VoxelArray.Length; v++) { if (!m_ProcessedVoxelArray[v]) { if (m_VoxelArray[v].Pos.x >= RAABB.Min.x && m_VoxelArray[v].Pos.x <= RAABB.Max.x && m_VoxelArray[v].Pos.y >= RAABB.Min.y && m_VoxelArray[v].Pos.y <= RAABB.Max.y && m_VoxelArray[v].Pos.z >= RAABB.Min.z && m_VoxelArray[v].Pos.z <= RAABB.Max.z) { VoxelList.Add(v); if (VoxelList.Count == 1) { NodeAABB.Min = m_VoxelArray[v].Pos - new Vector3(0.5f, 0.5f, 0.5f); NodeAABB.Max = m_VoxelArray[v].Pos + new Vector3(0.5f, 0.5f, 0.5f); } else { NodeAABB.Add(new AABB(m_VoxelArray[v].Pos, new Vector3(0.5f, 0.5f, 0.5f))); } } } } if (VoxelList.Count <= m_MaxPrimitivesPerLeaf) //is leaf { node.m_RNode = new TreeNode(); node.m_RNode.m_AABB = new AABB(Vector3.zero, Vector3.zero); node.m_RNode.m_AABB.Min = NodeAABB.Min; node.m_RNode.m_AABB.Max = NodeAABB.Max; node.m_RNode.m_Leaf = new TreeLeaf(); m_NumLeaves++; node.m_RNode.m_Leaf.m_RimitiveList = new List <int>(); for (int v = 0; v < VoxelList.Count; v++) { node.m_RNode.m_Leaf.m_RimitiveList.Add(VoxelList[v]); m_ProcessedVoxelArray[VoxelList[v]] = true; } m_NumPrimitives += node.m_RNode.m_Leaf.m_RimitiveList.Count; } else { node.m_RNode = new TreeNode(); m_NumNodes++; node.m_RNode.m_AABB = new AABB(Vector3.zero, Vector3.zero); node.m_RNode.m_AABB.Min = NodeAABB.Min; node.m_RNode.m_AABB.Max = NodeAABB.Max; SplitNode(node.m_RNode); } }