public static float4 Subdivide(Allocator allocator, NativeArray <float2> points, NativeArray <int2> edges, ref NativeArray <float2> outVertices, ref int outVertexCount, ref NativeArray <int> outIndices, ref int outIndexCount, ref NativeArray <int2> outEdges, ref int outEdgeCount, float areaFactor, float targetArea, int refineIterations, int smoothenIterations) { // Inputs are garbage, just early out. float4 ret = float4.zero; outEdgeCount = 0; outIndexCount = 0; outVertexCount = 0; if (points.Length < 3 || points.Length >= kMaxVertexCount || 0 == edges.Length) { return(ret); } // Do a proper Delaunay Triangulation. int tsIndexCount = 0, tsVertexCount = 0; NativeArray <int> tsIndices = new NativeArray <int>(kMaxIndexCount, allocator); NativeArray <float2> tsVertices = new NativeArray <float2>(kMaxVertexCount, allocator); var validGraph = Tessellator.Tessellate(allocator, points, points.Length, edges, edges.Length, ref tsVertices, ref tsVertexCount, ref tsIndices, ref tsIndexCount); // Refinement and Smoothing. bool refined = false; bool refinementRequired = (targetArea != 0 || areaFactor != 0); if (validGraph && refinementRequired) { // Do Refinement until success. float maxArea = 0; float incArea = 0; int rfEdgeCount = 0, rfPointCount = 0, rfIndexCount = 0, rfVertexCount = 0; NativeArray <int2> rfEdges = new NativeArray <int2>(kMaxEdgeCount, allocator); NativeArray <float2> rfPoints = new NativeArray <float2>(kMaxVertexCount, allocator); NativeArray <int> rfIndices = new NativeArray <int>(kMaxIndexCount, allocator); NativeArray <float2> rfVertices = new NativeArray <float2>(kMaxVertexCount, allocator); ret.x = 0; refineIterations = Math.Min(refineIterations, kMaxRefineIterations); if (targetArea != 0) { // Increment for Iterations. incArea = (targetArea / 10); while (targetArea < kMaxArea && refineIterations > 0) { // Do Mesh Refinement. CopyGraph(points, points.Length, ref rfPoints, ref rfPointCount, edges, edges.Length, ref rfEdges, ref rfEdgeCount); CopyGeometry(tsIndices, tsIndexCount, ref rfIndices, ref rfIndexCount, tsVertices, tsVertexCount, ref rfVertices, ref rfVertexCount); refined = Refinery.Condition(allocator, areaFactor, targetArea, ref rfPoints, ref rfPointCount, ref rfEdges, ref rfEdgeCount, ref rfVertices, ref rfVertexCount, ref rfIndices, ref rfIndexCount, ref maxArea); if (refined && rfIndexCount > rfPointCount) { // Copy Out ret.x = areaFactor; TransferOutput(rfEdges, rfEdgeCount, ref outEdges, ref outEdgeCount, rfIndices, rfIndexCount, ref outIndices, ref outIndexCount, rfVertices, rfVertexCount, ref outVertices, ref outVertexCount); break; } refined = false; targetArea = targetArea + incArea; refineIterations--; } } else if (areaFactor != 0) { // Increment for Iterations. areaFactor = math.lerp(0.1f, 0.54f, (areaFactor - 0.05f) / 0.45f); // Specific to Animation. incArea = (areaFactor / 10); while (areaFactor < 0.8f && refineIterations > 0) { // Do Mesh Refinement. CopyGraph(points, points.Length, ref rfPoints, ref rfPointCount, edges, edges.Length, ref rfEdges, ref rfEdgeCount); CopyGeometry(tsIndices, tsIndexCount, ref rfIndices, ref rfIndexCount, tsVertices, tsVertexCount, ref rfVertices, ref rfVertexCount); refined = Refinery.Condition(allocator, areaFactor, targetArea, ref rfPoints, ref rfPointCount, ref rfEdges, ref rfEdgeCount, ref rfVertices, ref rfVertexCount, ref rfIndices, ref rfIndexCount, ref maxArea); if (refined && rfIndexCount > rfPointCount) { // Copy Out ret.x = areaFactor; TransferOutput(rfEdges, rfEdgeCount, ref outEdges, ref outEdgeCount, rfIndices, rfIndexCount, ref outIndices, ref outIndexCount, rfVertices, rfVertexCount, ref outVertices, ref outVertexCount); break; } refined = false; areaFactor = areaFactor + incArea; refineIterations--; } } if (refined) { // Sanitize generated geometry data. var preSmoothen = outVertexCount; if (ret.x != 0) { VertexCleanupConditioner(tsVertexCount, ref rfIndices, ref rfIndexCount, ref rfVertices, ref rfVertexCount); } // Smoothen. At this point only vertex relocation is allowed, not vertex addition/removal. // Note: Only refined mesh contains Steiner points and we only smoothen these points. ret.y = 0; smoothenIterations = math.clamp(smoothenIterations, 0, kMaxSmoothenIterations); while (smoothenIterations > 0) { var smoothen = Smoothen.Condition(allocator, ref rfPoints, rfPointCount, rfEdges, rfEdgeCount, ref rfVertices, ref rfVertexCount, ref rfIndices, ref rfIndexCount); if (!smoothen) { break; } // Copy Out ret.y = (float)(smoothenIterations); TransferOutput(rfEdges, rfEdgeCount, ref outEdges, ref outEdgeCount, rfIndices, rfIndexCount, ref outIndices, ref outIndexCount, rfVertices, rfVertexCount, ref outVertices, ref outVertexCount); smoothenIterations--; } // Sanitize generated geometry data. var postSmoothen = outVertexCount; if (ret.y != 0) { VertexCleanupConditioner(tsVertexCount, ref outIndices, ref outIndexCount, ref outVertices, ref outVertexCount); } } rfVertices.Dispose(); rfIndices.Dispose(); rfPoints.Dispose(); rfEdges.Dispose(); } // Refinement failed but Graph succeeded. if (validGraph && !refined) { // Copy Out TransferOutput(edges, edges.Length, ref outEdges, ref outEdgeCount, tsIndices, tsIndexCount, ref outIndices, ref outIndexCount, tsVertices, tsVertexCount, ref outVertices, ref outVertexCount); } // Dispose Temp Memory. tsVertices.Dispose(); tsIndices.Dispose(); return(ret); }
public static float4 Subdivide(Allocator allocator, NativeArray <float2> points, NativeArray <int2> edges, ref NativeArray <float2> outVertices, ref int outVertexCount, ref NativeArray <int> outIndices, ref int outIndexCount, ref NativeArray <int2> outEdges, ref int outEdgeCount, float areaFactor, float targetArea, int smoothenCount) { // Inputs are garbage, just early out. outEdgeCount = 0; outIndexCount = 0; outVertexCount = 0; if (points.Length == 0) { return(float4.zero); } // Do a proper Delaunay Triangulation. float4 ret = float4.zero; int tsIndexCount = 0, tsVertexCount = 0; NativeArray <int> tsIndices = new NativeArray <int>(kMaxIndexCount, allocator); NativeArray <float2> tsVertices = new NativeArray <float2>(kMaxVertexCount, allocator); var validGraph = Tessellator.Tessellate(allocator, points, points.Length, edges, edges.Length, ref tsVertices, ref tsVertexCount, ref tsIndices, ref tsIndexCount); // Refinement and Smoothing. bool refined = false; bool refinementRequired = (targetArea != 0 || areaFactor != 0); if (validGraph && refinementRequired) { // Do Refinement until success. float maxArea = 0; int rfEdgeCount = 0, rfPointCount = 0, rfIndexCount = 0, rfVertexCount = 0; NativeArray <int2> rfEdges = new NativeArray <int2>(kMaxEdgeCount, allocator); NativeArray <float2> rfPoints = new NativeArray <float2>(kMaxVertexCount, allocator); NativeArray <int> rfIndices = new NativeArray <int>(kMaxIndexCount, allocator); NativeArray <float2> rfVertices = new NativeArray <float2>(kMaxVertexCount, allocator); if (targetArea != 0) { while (targetArea < kMaxArea) { // Do Mesh Refinement. CopyGraph(points, points.Length, ref rfPoints, ref rfPointCount, edges, edges.Length, ref rfEdges, ref rfEdgeCount); CopyGeometry(tsIndices, tsIndexCount, ref rfIndices, ref rfIndexCount, tsVertices, tsVertexCount, ref rfVertices, ref rfVertexCount); refined = Refinery.Condition(allocator, areaFactor, targetArea, ref rfPoints, ref rfPointCount, ref rfEdges, ref rfEdgeCount, ref rfVertices, ref rfVertexCount, ref rfIndices, ref rfIndexCount, ref maxArea); if (refined && rfIndexCount > rfPointCount) { // Copy Out ret.x = areaFactor; TransferOutput(rfEdges, rfEdgeCount, ref outEdges, ref outEdgeCount, rfIndices, rfIndexCount, ref outIndices, ref outIndexCount, rfVertices, rfVertexCount, ref outVertices, ref outVertexCount); break; } refined = false; targetArea = targetArea * 2.0f; } } else if (areaFactor != 0) { while (areaFactor < 0.8f) { // Do Mesh Refinement. CopyGraph(points, points.Length, ref rfPoints, ref rfPointCount, edges, edges.Length, ref rfEdges, ref rfEdgeCount); CopyGeometry(tsIndices, tsIndexCount, ref rfIndices, ref rfIndexCount, tsVertices, tsVertexCount, ref rfVertices, ref rfVertexCount); refined = Refinery.Condition(allocator, areaFactor, targetArea, ref rfPoints, ref rfPointCount, ref rfEdges, ref rfEdgeCount, ref rfVertices, ref rfVertexCount, ref rfIndices, ref rfIndexCount, ref maxArea); if (refined && rfIndexCount > rfPointCount) { // Copy Out ret.x = areaFactor; TransferOutput(rfEdges, rfEdgeCount, ref outEdges, ref outEdgeCount, rfIndices, rfIndexCount, ref outIndices, ref outIndexCount, rfVertices, rfVertexCount, ref outVertices, ref outVertexCount); break; } refined = false; areaFactor = areaFactor * 2.0f; } } if (refined) { // Smoothen. At this point only vertex relocation is allowed, not vertex addition/removal. // Note: Only refined mesh contains Steiner points and we only smoothen these points. smoothenCount = math.clamp(smoothenCount, 0, kMaxSmoothenIterations); while (smoothenCount > 0) { var smoothen = Smoothen.Condition(allocator, ref rfPoints, rfPointCount, rfEdges, rfEdgeCount, ref rfVertices, ref rfVertexCount, ref rfIndices, ref rfIndexCount); if (!smoothen) { break; } // Copy Out ret.y = (float)(smoothenCount); TransferOutput(rfEdges, rfEdgeCount, ref outEdges, ref outEdgeCount, rfIndices, rfIndexCount, ref outIndices, ref outIndexCount, rfVertices, rfVertexCount, ref outVertices, ref outVertexCount); smoothenCount--; } } rfVertices.Dispose(); rfIndices.Dispose(); rfPoints.Dispose(); rfEdges.Dispose(); } // Refinement failed but Graph succeeded. if (validGraph && !refined) { // Copy Out TransferOutput(edges, edges.Length, ref outEdges, ref outEdgeCount, tsIndices, tsIndexCount, ref outIndices, ref outIndexCount, tsVertices, tsVertexCount, ref outVertices, ref outVertexCount); } // Dispose Temp Memory. tsVertices.Dispose(); tsIndices.Dispose(); return(ret); }