// TODO: turn into job void FindPlanePairs(IntersectionType type, [NoAlias] ref BrushMeshBlob mesh, [NoAlias] NativeArray <int> intersectingPlanes, int intersectingPlanesLength, [NoAlias] NativeArray <float4> localSpacePlanesPtr, [NoAlias] ref NativeArray <int> vertexUsed, float4x4 vertexTransform, bool needTransform, [NoAlias] ref NativeArray <PlanePair> usedPlanePairs, [NoAlias] ref NativeArray <float3> usedVertices, out int usedPlanePairsLength, out int usedVerticesLength) { NativeCollectionHelpers.EnsureMinimumSize(ref usedVertices, mesh.localVertices.Length); NativeCollectionHelpers.EnsureMinimumSizeAndClear(ref usedPlanePairs, mesh.halfEdges.Length); if (type != IntersectionType.Intersection) { usedPlanePairsLength = 0; usedVerticesLength = mesh.localVertices.Length; for (int i = 0; i < mesh.localVertices.Length; i++) { usedVertices[i] = mesh.localVertices[i]; } return; } NativeCollectionHelpers.EnsureMinimumSizeAndClear(ref vertexUsed, mesh.localVertices.Length); NativeCollectionHelpers.EnsureMinimumSizeAndClear(ref planeAvailable, mesh.localPlanes.Length); // TODO: this can be partially stored in brushmesh // TODO: optimize ref var halfEdgePolygonIndices = ref mesh.halfEdgePolygonIndices;
public void Execute() { var maxPairs = (maxOrder * maxOrder); NativeCollectionHelpers.EnsureMinimumSizeAndClear(ref usedLookup, maxPairs); uniqueBrushPairs.Clear(); int requiredCapacity = 0; for (int b0 = 0; b0 < allUpdateBrushIndexOrders.Length; b0++) { var brushIndexOrder0 = allUpdateBrushIndexOrders[b0]; int brushNodeOrder0 = brushIndexOrder0.nodeOrder; var brushesTouchedByBrush = brushesTouchedByBrushes[brushNodeOrder0]; if (brushesTouchedByBrush == ChiselBlobAssetReference <BrushesTouchedByBrush> .Null) { continue; } ref var intersections = ref brushesTouchedByBrush.Value.brushIntersections; if (intersections.Length == 0) { continue; } requiredCapacity += intersections.Length + 1; }
public static unsafe void ReadArrayAndEnsureSize <T>([NoAlias] ref NativeStream.Reader nativeStream, [NoAlias] ref NativeArray <T> array, out int length) where T : unmanaged { length = nativeStream.Read <int>(); NativeCollectionHelpers.EnsureMinimumSize(ref array, length); for (int i = 0; i < length; i++) { array[i] = nativeStream.Read <T>(); } }
public void Execute() { var maxPairs = (maxOrder * maxOrder); NativeCollectionHelpers.EnsureMinimumSizeAndClear(ref usedLookup, maxPairs); for (int b0 = 0; b0 < allUpdateBrushIndexOrders.Length; b0++) { var brushIndexOrder0 = allUpdateBrushIndexOrders[b0]; int brushNodeOrder0 = brushIndexOrder0.nodeOrder; var brushesTouchedByBrush = brushesTouchedByBrushes[brushNodeOrder0]; if (brushesTouchedByBrush == ChiselBlobAssetReference <BrushesTouchedByBrush> .Null) { continue; } ref var intersections = ref brushesTouchedByBrush.Value.brushIntersections; if (intersections.Length == 0) { continue; } if (uniqueBrushPairs->Capacity < intersections.Length) { uniqueBrushPairs->Capacity = intersections.Length; } // Find all intersections between brushes for (int i = 0; i < intersections.Length; i++) { var intersection = intersections[i]; var brushIndexOrder1 = intersection.nodeIndexOrder; int brushNodeOrder1 = brushIndexOrder1.nodeOrder; var brushPair = new BrushPair2 { type = intersection.type, brushIndexOrder0 = brushIndexOrder0, brushIndexOrder1 = brushIndexOrder1 }; if (brushNodeOrder0 > brushNodeOrder1) // ensures we do calculations exactly the same for each brush pair { brushPair.Flip(); } int testIndex = (brushPair.brushIndexOrder0.nodeOrder * maxOrder) + brushPair.brushIndexOrder1.nodeOrder; if (!usedLookup.IsSet(testIndex)) { usedLookup.Set(testIndex, true); uniqueBrushPairs->AddNoResize(brushPair); } } }
public void Execute() { NativeCollectionHelpers.EnsureCapacityAndClear(ref requiredTemporaryBullShitByDOTS, allTreeBrushIndexOrders.Length); NativeCollectionHelpers.EnsureMinimumSizeAndClear(ref foundBrushes, allTreeBrushIndexOrders.Length); for (int i = 0; i < rebuildTreeBrushIndexOrders.Length; i++) { foundBrushes.Set(rebuildTreeBrushIndexOrders[i].nodeOrder, true); requiredTemporaryBullShitByDOTS.AddNoResize(rebuildTreeBrushIndexOrders[i]); } for (int i = 0; i < brushesThatNeedIndirectUpdate.Length; i++) { var indexOrder = brushesThatNeedIndirectUpdate[i]; if (!foundBrushes.IsSet(indexOrder.nodeOrder)) { requiredTemporaryBullShitByDOTS.AddNoResize(indexOrder); foundBrushes.Set(indexOrder.nodeOrder, true); } } requiredTemporaryBullShitByDOTS.Sort(new IntersectionUtility.IndexOrderComparer()); allUpdateBrushIndexOrders.AddRangeNoResize(requiredTemporaryBullShitByDOTS); }
public void Execute() { var minCount = brushBrushIntersections.Count * 16; NativeCollectionHelpers.EnsureCapacityAndClear(ref intersections, minCount); for (int i = 0; i < brushBrushIntersections.Count; i++) { if (!brushBrushIntersections.IsAllocated(i)) { continue; } var subArray = brushBrushIntersections[i]; for (int j = 0; j < subArray.Count; j++) { var intersectWith = subArray[j]; var pair = new BrushPair { brushNodeOrder0 = i, brushNodeOrder1 = intersectWith.brushNodeOrder1, type = intersectWith.type }; intersections.Add(pair); pair.Flip(); intersections.Add(pair); } } brushIntersectionsWith->Clear(); if (intersections.Length == 0) { return; } intersections.Sort(new ListComparer()); var currentPair = intersections[0]; int previousOrder = currentPair.brushNodeOrder0; brushIntersectionsWith->Add(new BrushIntersectWith { brushNodeOrder1 = currentPair.brushNodeOrder1, type = currentPair.type, }); int2 range = new int2(0, 1); for (int i = 1; i < intersections.Length; i++) { currentPair = intersections[i]; int currentOrder = currentPair.brushNodeOrder0; brushIntersectionsWith->Add(new BrushIntersectWith { brushNodeOrder1 = currentPair.brushNodeOrder1, type = currentPair.type, }); if (currentOrder != previousOrder) { //Debug.Log($"{previousOrder} {range}"); brushIntersectionsWithRange[previousOrder] = range; previousOrder = currentOrder; range.x = i; range.y = 1; } else { range.y++; } } brushIntersectionsWithRange[previousOrder] = range; }
public void Execute(int index1) { if (allTreeBrushIndexOrders.Length == rebuildTreeBrushIndexOrders.Length) { //for (int index1 = 0; index1 < updateBrushIndicesArray.Length; index1++) { var brush1IndexOrder = rebuildTreeBrushIndexOrders[index1]; int brush1NodeOrder = brush1IndexOrder.nodeOrder; NativeListArray <BrushIntersectWith> .NativeList brush1Intersections; if (!brushBrushIntersections.IsAllocated(brush1NodeOrder)) { brush1Intersections = brushBrushIntersections.AllocateWithCapacityForIndex(brush1NodeOrder, 16); } else { brush1Intersections = brushBrushIntersections[brush1NodeOrder]; } for (int index0 = 0; index0 < rebuildTreeBrushIndexOrders.Length; index0++) { var brush0IndexOrder = rebuildTreeBrushIndexOrders[index0]; int brush0NodeOrder = brush0IndexOrder.nodeOrder; if (brush0NodeOrder <= brush1NodeOrder) { continue; } var result = IntersectionUtility.FindIntersection(brush0NodeOrder, brush1NodeOrder, ref brushMeshLookup, ref brushTreeSpaceBounds, ref transformationCache, ref transformedPlanes0, ref transformedPlanes1); if (result == IntersectionType.NoIntersection) { continue; } result = IntersectionUtility.Flip(result); IntersectionUtility.StoreIntersection(brush1Intersections, brush0IndexOrder, result); } } return; } NativeCollectionHelpers.EnsureMinimumSizeAndClear(ref foundBrushes, allTreeBrushIndexOrders.Length); NativeCollectionHelpers.EnsureMinimumSizeAndClear(ref usedBrushes, allTreeBrushIndexOrders.Length); // TODO: figure out a way to avoid needing this for (int a = 0; a < rebuildTreeBrushIndexOrders.Length; a++) { foundBrushes.Set(rebuildTreeBrushIndexOrders[a].nodeOrder, true); } //for (int index1 = 0; index1 < updateBrushIndicesArray.Length; index1++) { var brush1IndexOrder = rebuildTreeBrushIndexOrders[index1]; int brush1NodeOrder = brush1IndexOrder.nodeOrder; NativeListArray <BrushIntersectWith> .NativeList brush1Intersections; if (!brushBrushIntersections.IsAllocated(brush1NodeOrder)) { brush1Intersections = brushBrushIntersections.AllocateWithCapacityForIndex(brush1NodeOrder, 16); } else { brush1Intersections = brushBrushIntersections[brush1NodeOrder]; } for (int index0 = 0; index0 < allTreeBrushIndexOrders.Length; index0++) { var brush0IndexOrder = allTreeBrushIndexOrders[index0]; int brush0NodeOrder = brush0IndexOrder.nodeOrder; if (brush0NodeOrder == brush1NodeOrder) { continue; } var found = foundBrushes.IsSet(brush0NodeOrder); if (brush0NodeOrder < brush1NodeOrder && found) { continue; } var result = IntersectionUtility.FindIntersection(brush0NodeOrder, brush1NodeOrder, ref brushMeshLookup, ref brushTreeSpaceBounds, ref transformationCache, ref transformedPlanes0, ref transformedPlanes1); if (result == IntersectionType.NoIntersection) { continue; } if (!found) { if (!usedBrushes.IsSet(brush0IndexOrder.nodeOrder)) { usedBrushes.Set(brush0IndexOrder.nodeOrder, true); brushesThatNeedIndirectUpdateHashMap.Add(brush0IndexOrder); result = IntersectionUtility.Flip(result); IntersectionUtility.StoreIntersection(brush1Intersections, brush0IndexOrder, result); } } else { if (brush0NodeOrder > brush1NodeOrder) { result = IntersectionUtility.Flip(result); IntersectionUtility.StoreIntersection(brush1Intersections, brush0IndexOrder, result); } } } } }
void GenerateLoop(IndexOrder brushIndexOrder0, IndexOrder brushIndexOrder1, bool invertedTransform, [NoAlias] NativeArray <SurfaceInfo> surfaceInfos, [NoAlias] int surfaceInfosLength, [NoAlias] ref BrushTreeSpacePlanes brushTreeSpacePlanes0, [NoAlias] NativeArray <PlaneVertexIndexPair> foundIndices0, [NoAlias] ref int foundIndices0Length, [NoAlias] ref HashedVertices hashedTreeSpaceVertices, [NoAlias] NativeList <BrushIntersectionLoop> .ParallelWriter outputSurfaces) { // Why is the unity NativeSort slower than bubble sort? // TODO: revisit this assumption //* for (int i = 0; i < foundIndices0Length - 1; i++) { for (int j = i + 1; j < foundIndices0Length; j++) { var x = foundIndices0[i]; var y = foundIndices0[j]; if (x.planeIndex > y.planeIndex) { continue; } if (x.planeIndex == y.planeIndex) { if (x.vertexIndex <= y.vertexIndex) { continue; } } var t = x; foundIndices0[i] = foundIndices0[j]; foundIndices0[j] = t; } } /*/ * foundIndices0.Sort(comparer); * //*/ NativeCollectionHelpers.EnsureMinimumSize(ref planeIndexOffsets, foundIndices0Length); NativeCollectionHelpers.EnsureCapacityAndClear(ref uniqueIndices, foundIndices0Length); var planeIndexOffsetsLength = 0; //var planeIndexOffsets = stackalloc PlaneIndexOffsetLength[foundIndices0Length]; //var uniqueIndices = stackalloc ushort[foundIndices0Length]; // Now that our indices are sorted by planeIndex, we can segment them by start/end offset var previousPlaneIndex = foundIndices0[0].planeIndex; var previousVertexIndex = foundIndices0[0].vertexIndex; uniqueIndices.Add(previousVertexIndex); var loopStart = 0; for (int i = 1; i < foundIndices0Length; i++) { var indices = foundIndices0[i]; var planeIndex = indices.planeIndex; var vertexIndex = indices.vertexIndex; // TODO: why do we have soooo many duplicates sometimes? if (planeIndex == previousPlaneIndex && vertexIndex == previousVertexIndex) { continue; } if (planeIndex != previousPlaneIndex) { var currLength = RemoveDuplicateEdges(ref uniqueIndices, loopStart, uniqueIndices.Length); //var currLength = (uniqueIndices.Length - loopStart); if (currLength > 2) { planeIndexOffsets[planeIndexOffsetsLength] = new PlaneIndexOffsetLength { length = (ushort)currLength, offset = (ushort)loopStart, planeIndex = previousPlaneIndex }; planeIndexOffsetsLength++; } loopStart = uniqueIndices.Length; } uniqueIndices.Add(vertexIndex); previousVertexIndex = vertexIndex; previousPlaneIndex = planeIndex; } { var currLength = RemoveDuplicateEdges(ref uniqueIndices, loopStart, uniqueIndices.Length); //var currLength = (uniqueIndices.Length - loopStart); if (currLength > 2) { planeIndexOffsets[planeIndexOffsetsLength] = new PlaneIndexOffsetLength { length = (ushort)currLength, offset = (ushort)loopStart, planeIndex = previousPlaneIndex }; planeIndexOffsetsLength++; } } var maxLength = 0; for (int i = 0; i < planeIndexOffsetsLength; i++) { maxLength = math.max(maxLength, planeIndexOffsets[i].length); } NativeCollectionHelpers.EnsureMinimumSize(ref sortedStack, maxLength * 2); var uniqueIndicesArray = uniqueIndices.AsArray(); // For each segment, we now sort our vertices within each segment, // making the assumption that they are convex //var sortedStack = stackalloc int2[maxLength * 2]; ref var vertices = ref hashedTreeSpaceVertices;//.GetUnsafeReadOnlyPtr();
void FindIntersectionVertices(ref NativeArray <float4> intersectingPlanes0, int intersectingPlanes0Length, int intersectingPlanesAndEdges0Length, ref NativeArray <float4> intersectingPlanes1, int intersectingPlanes1Length, int intersectingPlanesAndEdges1Length, ref NativeArray <PlanePair> usedPlanePairs1, int usedPlanePairs1Length, ref NativeArray <int> intersectingPlaneIndices0, int intersectingPlaneIndices0Length, float4x4 nodeToTreeSpaceMatrix0, ref HashedVertices hashedTreeSpaceVertices, ref HashedVertices snapHashedVertices, NativeArray <PlaneVertexIndexPair> foundIndices0, ref int foundIndices0Length, NativeArray <PlaneVertexIndexPair> foundIndices1, ref int foundIndices1Length) { int foundVerticesCount = usedPlanePairs1Length * intersectingPlanes0Length; NativeCollectionHelpers.EnsureMinimumSize(ref foundVertices, foundVerticesCount); NativeCollectionHelpers.EnsureMinimumSize(ref foundEdges, foundVerticesCount); NativeCollectionHelpers.EnsureMinimumSize(ref foundIntersections, foundVerticesCount); var n = 0; for (int i = 0; i < usedPlanePairs1Length; i++) { for (int j = 0; j < intersectingPlanes0Length; j++) { var plane0 = usedPlanePairs1[i].plane0; var plane1 = usedPlanePairs1[i].plane1; var plane2 = intersectingPlanes0[j]; foundIntersections[n] = new IntersectionPlanes { //plane0 = plane0, //plane1 = plane1, plane2 = plane2, planeIndex0 = usedPlanePairs1[i].planeIndex0, planeIndex1 = usedPlanePairs1[i].planeIndex1, planeIndex2 = intersectingPlaneIndices0[j] }; foundEdges[n] = new IntersectionEdge { edgeVertex0 = usedPlanePairs1[i].edgeVertex0, edgeVertex1 = usedPlanePairs1[i].edgeVertex1 }; if (math.abs(math.dot(plane2.xyz, plane0.xyz)) >= CSGConstants.kNormalDotAlignEpsilon || math.abs(math.dot(plane2.xyz, plane1.xyz)) >= CSGConstants.kNormalDotAlignEpsilon || math.abs(math.dot(plane0.xyz, plane1.xyz)) >= CSGConstants.kNormalDotAlignEpsilon) { continue; } var localVertex = PlaneExtensions.Intersection(plane2, plane0, plane1); if (double.IsNaN(localVertex.x)) { continue; } foundVertices[n] = new float4((float3)localVertex, 1); n++; } } for (int k = n - 1; k >= 0; k--) { var edgeVertex0 = foundEdges[k].edgeVertex0; var edgeVertex1 = foundEdges[k].edgeVertex1; var plane2 = foundIntersections[k].plane2; if (math.abs(math.dot(plane2, edgeVertex0)) <= kFatPlaneWidthEpsilon && math.abs(math.dot(plane2, edgeVertex1)) <= kFatPlaneWidthEpsilon) { if (k < n - 1) { foundIntersections[k] = foundIntersections[n - 1]; foundVertices[k] = foundVertices[n - 1]; } n--; } } // TODO: since we're using a pair in the outer loop, we could also determine which // 2 planes it intersects at both ends and just check those two planes .. // NOTE: for brush2, the intersection will always be only on two planes // UNLESS it's a corner vertex along that edge (we can compare to the two vertices) // in which case we could use a pre-calculated list of planes .. // OR when the intersection is outside of the edge .. for (int k = n - 1; k >= 0; k--) { if (IsOutsidePlanes(intersectingPlanes0, intersectingPlanesAndEdges0Length, foundVertices[k]) || IsOutsidePlanes(intersectingPlanes1, intersectingPlanesAndEdges1Length, foundVertices[k])) { if (k < n - 1) { foundIntersections[k] = foundIntersections[n - 1]; foundVertices[k] = foundVertices[n - 1]; } n--; } } for (int k = 0; k < n; k++) { var planeIndex0 = (ushort)foundIntersections[k].planeIndex0; var planeIndex1 = (ushort)foundIntersections[k].planeIndex1; var planeIndex2 = (ushort)foundIntersections[k].planeIndex2; var localVertex = foundVertices[k]; // TODO: should be having a Loop for each plane that intersects this vertex, and add that vertex // to ensure they are identical var treeSpaceVertex = math.mul(nodeToTreeSpaceMatrix0, localVertex).xyz; treeSpaceVertex = snapHashedVertices[snapHashedVertices.AddNoResize(treeSpaceVertex)]; var treeSpaceVertexIndex = hashedTreeSpaceVertices.AddNoResize(treeSpaceVertex); { // TODO: optimize for (int f = 0; f < foundIndices0Length; f++) { if (foundIndices0[f].vertexIndex == treeSpaceVertexIndex && foundIndices0[f].planeIndex == planeIndex2) { goto skip0; } } foundIndices0[foundIndices0Length] = new PlaneVertexIndexPair { planeIndex = planeIndex2, vertexIndex = treeSpaceVertexIndex }; foundIndices0Length++; skip0 :; } { // TODO: optimize for (int f = 0; f < foundIndices1Length; f++) { if (foundIndices1[f].vertexIndex == treeSpaceVertexIndex && foundIndices1[f].planeIndex == planeIndex0) { goto skip1; } } foundIndices1[foundIndices1Length] = new PlaneVertexIndexPair { planeIndex = planeIndex0, vertexIndex = treeSpaceVertexIndex }; foundIndices1Length++; skip1 :; } { // TODO: optimize for (int f = 0; f < foundIndices1Length; f++) { if (foundIndices1[f].vertexIndex == treeSpaceVertexIndex && foundIndices1[f].planeIndex == planeIndex1) { goto skip2; } } foundIndices1[foundIndices1Length] = new PlaneVertexIndexPair { planeIndex = planeIndex1, vertexIndex = treeSpaceVertexIndex }; foundIndices1Length++; skip2 :; } } }
//[MethodImpl(MethodImplOptions.NoInlining)] void FindInsideVertices([NoAlias] NativeArray <float3> usedVertices0, int usedVertices0Length, [NoAlias] NativeArray <ushort> vertexIntersectionPlanes, int vertexIntersectionPlanesLength, [NoAlias] NativeArray <int2> vertexIntersectionSegments, int vertexIntersectionSegmentsLength, [NoAlias] NativeArray <float4> intersectingPlanes1, int intersectingPlanes1Length, int intersectingPlanesAndEdges1Length, float4x4 nodeToTreeSpaceMatrix1, float4x4 vertexToLocal0, [NoAlias] ref HashedVertices hashedTreeSpaceVertices, [NoAlias] ref HashedVertices snapHashedVertices, [NoAlias] NativeArray <PlaneVertexIndexPair> foundIndices0, ref int foundIndices0Length) { NativeCollectionHelpers.EnsureMinimumSize(ref localVertices, usedVertices0Length); NativeCollectionHelpers.EnsureMinimumSize(ref usedVertexIndices, usedVertices0Length); for (int j = 0; j < usedVertices0Length; j++) { var brushVertex1 = new float4(usedVertices0[j], 1); localVertices[j] = math.mul(vertexToLocal0, brushVertex1); usedVertexIndices[j] = (ushort)j; } var foundVertexCount = usedVertices0Length; for (int j = foundVertexCount - 1; j >= 0; j--) { if (IsOutsidePlanes(intersectingPlanes1, intersectingPlanesAndEdges1Length, localVertices[j])) { if (j < foundVertexCount - 1) { localVertices[j] = localVertices[foundVertexCount - 1]; usedVertexIndices[j] = usedVertexIndices[foundVertexCount - 1]; } foundVertexCount--; } } for (int j = 0; j < foundVertexCount; j++) { var usedVertexIndex = usedVertexIndices[j]; var segment = vertexIntersectionSegments[usedVertexIndex]; if (segment.y == 0) { continue; } var treeSpaceVertex = math.mul(nodeToTreeSpaceMatrix1, localVertices[j]).xyz; treeSpaceVertex = snapHashedVertices[snapHashedVertices.AddNoResize(treeSpaceVertex)]; var treeSpaceVertexIndex = hashedTreeSpaceVertices.AddNoResize(treeSpaceVertex); for (int i = segment.x; i < segment.x + segment.y; i++) { var planeIndex = vertexIntersectionPlanes[i]; // TODO: optimize for (int k = 0; k < foundIndices0Length; k++) { if (foundIndices0[k].planeIndex == planeIndex && foundIndices0[k].vertexIndex == treeSpaceVertexIndex) { goto skipMe; } } foundIndices0[foundIndices0Length] = new PlaneVertexIndexPair { planeIndex = (ushort)planeIndex, vertexIndex = (ushort)treeSpaceVertexIndex }; foundIndices0Length++; skipMe: ; } } }
public void Execute(int index) { var count = input.BeginForEachIndex(index); if (count == 0) { return; } var brushIndexOrder = input.Read <IndexOrder>(); var brushNodeOrder = brushIndexOrder.nodeOrder; var vertexCount = input.Read <int>(); NativeCollectionHelpers.EnsureCapacityAndClear(ref brushVertices, vertexCount); for (int v = 0; v < vertexCount; v++) { var vertex = input.Read <float3>(); brushVertices.AddNoResize(vertex); } var surfaceOuterCount = input.Read <int>(); NativeCollectionHelpers.EnsureSizeAndClear(ref surfaceLoopIndices, surfaceOuterCount); for (int o = 0; o < surfaceOuterCount; o++) { UnsafeList <int> inner = default; var surfaceInnerCount = input.Read <int>(); if (surfaceInnerCount > 0) { inner = new UnsafeList <int>(surfaceInnerCount, Allocator.Temp); //inner.ResizeUninitialized(surfaceInnerCount); for (int i = 0; i < surfaceInnerCount; i++) { inner.AddNoResize(input.Read <int>()); } } surfaceLoopIndices[o] = inner; } var surfaceLoopCount = input.Read <int>(); NativeCollectionHelpers.EnsureMinimumSizeAndClear(ref surfaceLoopAllInfos, surfaceLoopCount); NativeCollectionHelpers.EnsureSizeAndClear(ref surfaceLoopAllEdges, surfaceLoopCount); for (int l = 0; l < surfaceLoopCount; l++) { surfaceLoopAllInfos[l] = input.Read <SurfaceInfo>(); var edgeCount = input.Read <int>(); if (edgeCount > 0) { var edgesInner = new UnsafeList <Edge>(edgeCount, Allocator.Temp); //edgesInner.ResizeUninitialized(edgeCount); for (int e = 0; e < edgeCount; e++) { edgesInner.AddNoResize(input.Read <Edge>()); } surfaceLoopAllEdges[l] = edgesInner; } } input.EndForEachIndex(); if (!basePolygonCache[brushNodeOrder].IsCreated) { return; } var maxLoops = 0; var maxIndices = 0; for (int s = 0; s < surfaceLoopIndices.Length; s++) { if (!surfaceLoopIndices[s].IsCreated) { continue; } var length = surfaceLoopIndices[s].Length; maxIndices += length; maxLoops = math.max(maxLoops, length); } ref var baseSurfaces = ref basePolygonCache[brushNodeOrder].Value.surfaces;
// TODO: turn into job static void GetIntersectingPlanes(IntersectionType type, [NoAlias] ref ChiselBlobArray <float4> localPlanes, int localPlaneCount, [NoAlias] ref ChiselBlobArray <float3> vertices, ChiselAABB selfBounds, float4x4 treeToNodeSpaceInverseTransposed, [NoAlias] ref NativeArray <int> intersectingPlaneIndices, [NoAlias] out int intersectingPlaneLength, [NoAlias] out int intersectingPlanesAndEdgesLength) { NativeCollectionHelpers.EnsureMinimumSize(ref intersectingPlaneIndices, localPlanes.Length); if (type != IntersectionType.Intersection) { intersectingPlaneLength = localPlaneCount; intersectingPlanesAndEdgesLength = localPlanes.Length; for (int i = 0; i < intersectingPlaneLength; i++) { intersectingPlaneIndices[i] = i; } return; } var min = selfBounds.Min; var max = selfBounds.Max; //Debug.Log($"{localPlanes.Length}"); intersectingPlaneLength = 0; intersectingPlanesAndEdgesLength = 0; var verticesLength = vertices.Length; for (int i = 0; i < localPlanes.Length; i++) { // bring plane into local space of mesh, the same space as the bounds of the mesh var localPlane = localPlanes[i]; // note: a transpose is part of this transformation var transformedPlane = math.mul(treeToNodeSpaceInverseTransposed, localPlane); //var normal = transformedPlane.xyz; // only need the signs, so don't care about normalization //transformedPlane /= math.length(normal); // we don't have to normalize the plane var corner = new float4((transformedPlane.x < 0) ? max.x : min.x, (transformedPlane.y < 0) ? max.y : min.y, (transformedPlane.z < 0) ? max.z : min.z, 1.0f); float forward = math.dot(transformedPlane, corner); if (forward > kFatPlaneWidthEpsilon) // closest point is outside { intersectingPlaneLength = 0; intersectingPlanesAndEdgesLength = 0; return; } // do a bounds check corner = new float4((transformedPlane.x >= 0) ? max.x : min.x, (transformedPlane.y >= 0) ? max.y : min.y, (transformedPlane.z >= 0) ? max.z : min.z, 1.0f); float backward = math.dot(transformedPlane, corner); if (backward < -kFatPlaneWidthEpsilon) // closest point is inside { continue; } float minDistance = float.PositiveInfinity; float maxDistance = float.NegativeInfinity; int onCount = 0; for (int v = 0; v < verticesLength; v++) { float distance = math.dot(transformedPlane, new float4(vertices[v], 1)); minDistance = math.min(distance, minDistance); maxDistance = math.max(distance, maxDistance); onCount += (distance >= -kFatPlaneWidthEpsilon && distance <= kFatPlaneWidthEpsilon) ? 1 : 0; } // if all vertices are 'inside' this plane, then we're not truly intersecting with it if ((minDistance > kFatPlaneWidthEpsilon || maxDistance < -kFatPlaneWidthEpsilon)) { continue; } if (i < localPlaneCount) { intersectingPlaneIndices[intersectingPlaneLength] = i; intersectingPlaneLength++; intersectingPlanesAndEdgesLength++; } else { intersectingPlaneIndices[intersectingPlanesAndEdgesLength] = i; intersectingPlanesAndEdgesLength++; } } }
void GenerateLoop(IndexOrder brushIndexOrder0, IndexOrder brushIndexOrder1, bool invertedTransform, [NoAlias] NativeArray <SurfaceInfo> surfaceInfos, [NoAlias] int surfaceInfosLength, [NoAlias] ref BrushTreeSpacePlanes brushTreeSpacePlanes0, [NoAlias] NativeArray <PlaneVertexIndexPair> foundIndices0, [NoAlias] ref int foundIndices0Length, [NoAlias] ref HashedVertices hashedTreeSpaceVertices, [NoAlias] NativeList <BrushIntersectionLoop> .ParallelWriter outputSurfaces) { // Why is the unity NativeSort slower than bubble sort? for (int i = 0; i < foundIndices0Length - 1; i++) { for (int j = i + 1; j < foundIndices0Length; j++) { var x = foundIndices0[i]; var y = foundIndices0[j]; if (x.planeIndex > y.planeIndex) { continue; } if (x.planeIndex == y.planeIndex) { if (x.vertexIndex <= y.vertexIndex) { continue; } } var t = x; foundIndices0[i] = foundIndices0[j]; foundIndices0[j] = t; } } NativeCollectionHelpers.EnsureMinimumSize(ref planeIndexOffsets, foundIndices0Length); NativeCollectionHelpers.EnsureMinimumSize(ref uniqueIndices, foundIndices0Length); var planeIndexOffsetsLength = 0; //var planeIndexOffsets = stackalloc PlaneIndexOffsetLength[foundIndices0Length]; var uniqueIndicesLength = 0; //var uniqueIndices = stackalloc ushort[foundIndices0Length]; // Now that our indices are sorted by planeIndex, we can segment them by start/end offset var previousPlaneIndex = foundIndices0[0].planeIndex; var previousVertexIndex = foundIndices0[0].vertexIndex; uniqueIndices[uniqueIndicesLength] = previousVertexIndex; uniqueIndicesLength++; var loopStart = 0; for (int i = 1; i < foundIndices0Length; i++) { var indices = foundIndices0[i]; var planeIndex = indices.planeIndex; var vertexIndex = indices.vertexIndex; // TODO: why do we have soooo many duplicates sometimes? if (planeIndex == previousPlaneIndex && vertexIndex == previousVertexIndex) { continue; } if (planeIndex != previousPlaneIndex) { var currLength = (uniqueIndicesLength - loopStart); if (currLength > 2) { planeIndexOffsets[planeIndexOffsetsLength] = new PlaneIndexOffsetLength { length = (ushort)currLength, offset = (ushort)loopStart, planeIndex = previousPlaneIndex }; planeIndexOffsetsLength++; } loopStart = uniqueIndicesLength; } uniqueIndices[uniqueIndicesLength] = vertexIndex; uniqueIndicesLength++; previousVertexIndex = vertexIndex; previousPlaneIndex = planeIndex; } { var currLength = (uniqueIndicesLength - loopStart); if (currLength > 2) { planeIndexOffsets[planeIndexOffsetsLength] = new PlaneIndexOffsetLength { length = (ushort)currLength, offset = (ushort)loopStart, planeIndex = previousPlaneIndex }; planeIndexOffsetsLength++; } } var maxLength = 0; for (int i = 0; i < planeIndexOffsetsLength; i++) { maxLength = math.max(maxLength, planeIndexOffsets[i].length); } NativeCollectionHelpers.EnsureMinimumSize(ref sortedStack, maxLength * 2); // For each segment, we now sort our vertices within each segment, // making the assumption that they are convex //var sortedStack = stackalloc int2[maxLength * 2]; var vertices = hashedTreeSpaceVertices;//.GetUnsafeReadOnlyPtr(); for (int n = planeIndexOffsetsLength - 1; n >= 0; n--) { var planeIndexOffset = planeIndexOffsets[n]; var length = planeIndexOffset.length; var offset = planeIndexOffset.offset; var planeIndex = planeIndexOffset.planeIndex; float3 normal = brushTreeSpacePlanes0.treeSpacePlanes[planeIndex].xyz * (invertedTransform ? 1 : -1); // TODO: use plane information instead SortIndices(vertices, sortedStack, uniqueIndices, offset, length, normal); } var totalLoopsSize = 16 + (planeIndexOffsetsLength * UnsafeUtility.SizeOf <BrushIntersectionLoop>()); var totalSize = totalLoopsSize; for (int j = 0; j < planeIndexOffsetsLength; j++) { var planeIndexLength = planeIndexOffsets[j]; var loopLength = planeIndexLength.length; totalSize += (loopLength * UnsafeUtility.SizeOf <float3>()); } var srcVertices = hashedTreeSpaceVertices; for (int j = 0; j < planeIndexOffsetsLength; j++) { var planeIndexLength = planeIndexOffsets[j]; var offset = planeIndexLength.offset; var loopLength = planeIndexLength.length; var basePlaneIndex = planeIndexLength.planeIndex; var surfaceInfo = surfaceInfos[basePlaneIndex]; NativeCollectionHelpers.EnsureMinimumSize(ref temporaryVertices, loopLength); for (int d = 0; d < loopLength; d++) { temporaryVertices[d] = srcVertices[uniqueIndices[offset + d]]; } outputSurfaces.AddNoResize(new BrushIntersectionLoop { indexOrder0 = brushIndexOrder0, indexOrder1 = brushIndexOrder1, surfaceInfo = surfaceInfo, loopVertexIndex = outputSurfaceVertices.AddRangeNoResize(temporaryVertices.GetUnsafePtr(), loopLength), loopVertexCount = loopLength }); } }