private static unsafe void CollectAllVerticesFromSubTree(BoundingVolumeHierarchy.Node *nodes, int subTreeNodeIndex, NativeList <MeshConnectivityBuilder.Primitive> primitives, NativeList <float3> vertices) { int *nodesIndexStack = stackalloc int[BoundingVolumeHierarchy.Constants.UnaryStackSize]; int stackSize = 1; nodesIndexStack[0] = subTreeNodeIndex; do { BoundingVolumeHierarchy.Node node = nodes[nodesIndexStack[--stackSize]]; if (node.IsLeaf) { for (int i = 0; i < 4; i++) { if (node.IsChildValid(i)) { MeshConnectivityBuilder.Primitive p = primitives[node.Data[i]]; vertices.Add(p.Vertices[0]); vertices.Add(p.Vertices[1]); vertices.Add(p.Vertices[2]); if ((p.Flags & MeshConnectivityBuilder.PrimitiveFlags.DefaultTrianglePairFlags) != 0) { vertices.Add(p.Vertices[3]); } } } } else { for (int i = 0; i < 4; i++) { if (node.IsChildValid(i)) { nodesIndexStack[stackSize++] = node.Data[i]; } } } } while (stackSize > 0); }
private static unsafe NativeArray <int> ProducedPrimitivesCountPerSubTree(BoundingVolumeHierarchy.Node *nodes, int nodeCount) { var primitivesPerNode = new NativeArray <int>(nodeCount, Allocator.Temp); for (int nodeIndex = nodeCount - 1; nodeIndex >= 0; nodeIndex--) { BoundingVolumeHierarchy.Node node = nodes[nodeIndex]; if (node.IsLeaf) { primitivesPerNode[nodeIndex] = node.NumValidChildren(); } else { primitivesPerNode[nodeIndex] = primitivesPerNode[node.Data[0]] + primitivesPerNode[node.Data[1]] + primitivesPerNode[node.Data[2]] + primitivesPerNode[node.Data[3]]; } } return(primitivesPerNode); }
internal static unsafe TempSection BuildSections(BoundingVolumeHierarchy.Node *nodes, int nodeCount, NativeList <MeshConnectivityBuilder.Primitive> primitives) { var tempSections = new TempSection() { PrimitivesFlags = new NativeList <Mesh.PrimitiveFlags>(Allocator.Temp), Primitives = new NativeList <Mesh.PrimitiveVertexIndices>(Allocator.Temp), Vertices = new NativeList <float3>(Allocator.Temp), Ranges = new NativeList <TempSectionRanges>(Allocator.Temp) }; if (primitives.Length == 0) { // Early-out in the case of no input primitives return(tempSections); } // Traverse the tree and break out geometry into sections int *nodesIndexStack = stackalloc int[BoundingVolumeHierarchy.Constants.UnaryStackSize]; int stackSize = 1; nodesIndexStack[0] = 1; const float uniqueVerticesPerPrimitiveFactor = 1.5f; var primitivesCountInSubTree = ProducedPrimitivesCountPerSubTree(nodes, nodeCount); var subTreeIndices = new NativeList <int>(Allocator.Temp); var nodeIndices = new NativeList <int>(Allocator.Temp); var tmpVertices = new NativeList <float3>(Allocator.Temp); do { int nodeIndex = nodesIndexStack[--stackSize]; int subTreeVertexCountEstimate = (int)(uniqueVerticesPerPrimitiveFactor * primitivesCountInSubTree[nodeIndex]); subTreeIndices.Clear(); if (subTreeVertexCountEstimate < Mesh.Section.MaxNumVertices) { subTreeIndices.Add(nodeIndex); } else { // Sub tree is too big, break it up. BoundingVolumeHierarchy.Node node = nodes[nodeIndex]; for (int i = 0; i < 4; i++) { if (node.IsChildValid(i)) { int childNodeIndex = node.Data[i]; int nodeSubTreeVertexCount = (int)(uniqueVerticesPerPrimitiveFactor * primitivesCountInSubTree[childNodeIndex]); if (nodeSubTreeVertexCount < Mesh.Section.MaxNumVertices) { subTreeIndices.Add(childNodeIndex); } else { nodesIndexStack[stackSize++] = childNodeIndex; } } } } float tempUniqueVertexPrimitiveFactor = 1.0f; const float factorStepIncrement = 0.25f; while (subTreeIndices.Length > 0) { // Try to combine sub trees if multiple sub trees can fit into one section. nodeIndices.Clear(); int vertexCountEstimate = 0; for (var i = 0; i < subTreeIndices.Length; ++i) { var subTreeNodeIndex = subTreeIndices[i]; int nodeIndexCount = (int)(tempUniqueVertexPrimitiveFactor * primitivesCountInSubTree[subTreeNodeIndex]); if (vertexCountEstimate + nodeIndexCount < Mesh.Section.MaxNumVertices) { vertexCountEstimate += nodeIndexCount; nodeIndices.Add(subTreeNodeIndex); } } if (nodeIndices.Length == 0) { // We failed to fit any sub tree into sections. // Split up nodes and push them to stack. for (var index = 0; index < subTreeIndices.Length; ++index) { var subTreeNodeIndex = subTreeIndices[index]; BoundingVolumeHierarchy.Node nodeToSplit = nodes[subTreeNodeIndex]; for (int i = 0; i < 4; i++) { if (nodeToSplit.IsChildValid(i)) { nodesIndexStack[stackSize++] = nodeToSplit.Data[i]; } } } subTreeIndices.Clear(); continue; } // Collect vertices from all sub trees. tmpVertices.Clear(); for (var i = 0; i < nodeIndices.Length; ++i) { var subTreeNodeIndex = nodeIndices[i]; CollectAllVerticesFromSubTree(nodes, subTreeNodeIndex, primitives, tmpVertices); } var vertexIndices = new NativeArray <int>(tmpVertices.Length, Allocator.Temp); for (int i = 0; i < vertexIndices.Length; i++) { vertexIndices[i] = i; } NativeList <float3> uniqueVertices = MeshConnectivityBuilder.WeldVertices(vertexIndices, new NativeArray <float3>(tmpVertices, Allocator.Temp)); if (uniqueVertices.Length < Mesh.Section.MaxNumVertices) { BuildSectionGeometry(tempSections, primitives, nodeIndices, nodes, new NativeArray <float3>(uniqueVertices, Allocator.Temp)); // Remove used indices for (var i = 0; i < nodeIndices.Length; ++i) { var nodeTreeIndex = nodeIndices[i]; subTreeIndices.RemoveAtSwapBack(subTreeIndices.IndexOf(nodeTreeIndex)); } } else { // Estimate of num vertices per primitives was wrong. // Increase the tempUniqueVertexPrimitiveFactor. tempUniqueVertexPrimitiveFactor += factorStepIncrement; } } }while (stackSize > 0); return(tempSections); }
private static unsafe void BuildSectionGeometry(TempSection sections, NativeList <MeshConnectivityBuilder.Primitive> primitives, NativeList <int> subTreeNodeIndices, BoundingVolumeHierarchy.Node *nodes, NativeArray <float3> vertices) { var sectionIndex = sections.Ranges.Length; var newSectionRange = new TempSectionRanges { VerticesMin = sections.Vertices.Length, PrimitivesFlagsMin = sections.PrimitivesFlags.Length, PrimitivesMin = sections.Primitives.Length }; sections.Vertices.AddRange(vertices); int *nodesIndexStack = stackalloc int[BoundingVolumeHierarchy.Constants.UnaryStackSize]; for (var rootIndex = 0; rootIndex < subTreeNodeIndices.Length; ++rootIndex) { var root = subTreeNodeIndices[rootIndex]; int stackSize = 1; nodesIndexStack[0] = root; do { int nodeIndex = nodesIndexStack[--stackSize]; ref BoundingVolumeHierarchy.Node node = ref nodes[nodeIndex]; if (node.IsLeaf) { for (int i = 0; i < 4; i++) { if (node.IsChildValid(i)) { MeshConnectivityBuilder.Primitive p = primitives[node.Data[i]]; sections.PrimitivesFlags.Add(ConvertPrimitiveFlags(p.Flags)); int vertexCount = (p.Flags & MeshConnectivityBuilder.PrimitiveFlags.IsTrianglePair) != 0 ? 4 : 3; Mesh.PrimitiveVertexIndices sectionPrimitive = new Mesh.PrimitiveVertexIndices(); byte *vertexIndices = §ionPrimitive.A; for (int v = 0; v < vertexCount; v++) { vertexIndices[v] = (byte)vertices.IndexOf(p.Vertices[v]); } if (vertexCount == 3) { sectionPrimitive.D = sectionPrimitive.C; } sections.Primitives.Add(sectionPrimitive); int primitiveSectionIndex = sections.Primitives.Length - newSectionRange.PrimitivesMin - 1; // Update primitive index in the BVH. node.Data[i] = (sectionIndex << 8) | primitiveSectionIndex; } } } else { for (int i = 0; i < 4; i++) { if (node.IsChildValid(i)) { nodesIndexStack[stackSize++] = node.Data[i]; } } } } while (stackSize > 0); }