diff --git a/.gitmodules b/.gitmodules
index d298235a..5dbc4fb1 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,6 +1,3 @@
[submodule "Dependencies/CustomAssetMetadata"]
path = Dependencies/CustomAssetMetadata
url = https://github.com/LogicalError/CustomAssetMetadata.git
-[submodule "Dependencies/BurstTriangulator"]
- path = Dependencies/BurstTriangulator
- url = https://github.com/RadicalCSG/BurstTriangulator.git
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index be287c07..698043ea 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -24,7 +24,7 @@ Chisel is a Unity package. To work on it, put it in a Unity project as an embedd
`git submodule update --init` in it.
3. Open the project in Unity. The first time takes a while, because Burst compiles a lot of code.
-The package's dependencies, BurstTriangulator and CustomAssetMetadata, are git submodules in `Dependencies`.
+The package's dependency, CustomAssetMetadata, is a git submodule in `Dependencies`.
## Where things are
diff --git a/Components/Managers/ChiselModelManager.cs b/Components/Managers/ChiselModelManager.cs
index 56dc4198..77ea8b26 100644
--- a/Components/Managers/ChiselModelManager.cs
+++ b/Components/Managers/ChiselModelManager.cs
@@ -848,9 +848,8 @@ public static Hash128 GetComponentInputHash(ChiselModelComponent model)
///
/// What both hashes have to cover and neither can see in the model: the version of the code that builds the
- /// meshes, which of its two CSG algorithms builds them, and the helper materials FinishMeshUpdates hands
- /// out, which no surface names. Without the code version a saved scene would keep meshes built by code that has
- /// since changed, and without the algorithm meshes built by the other one.
+ /// meshes, and the helper materials FinishMeshUpdates hands out, which no surface names. Without the code
+ /// version a saved scene would keep meshes built by code that has since changed.
///
static void AppendEnvironment(ref Hash128 hash)
{
@@ -861,9 +860,6 @@ static void AppendEnvironment(ref Hash128 hash)
}
hash.Append(ref s_CodeVersion);
- int algorithm = CompactHierarchyManager.TreeUpdate.kExactCSG ? 1 : 0;
- hash.Append(ref algorithm);
-
AppendMaterialIdentity(ref hash, ChiselProjectSettings.ForceShadowOnlySurfacesMaterial);
AppendMaterialIdentity(ref hash, ChiselProjectSettings.CollisionSurfacesMaterial);
var debugVisualizationMaterials = ChiselProjectSettings.DebugVisualizationMaterials;
diff --git a/Core/2.Processing/CSGMath.cs b/Core/2.Processing/CSGMath.cs
index af9ffc79..2c53fff2 100644
--- a/Core/2.Processing/CSGMath.cs
+++ b/Core/2.Processing/CSGMath.cs
@@ -42,8 +42,8 @@ public static float3 EdgePlaneCrossing(float3 v0, float3 v1, float d0, float d1)
public static double3 PlaneIntersection(double4 plane0, double4 plane1, double4 plane2)
=> PlaneExtensions.Intersection(plane0, plane1, plane2);
- // One vertex-pair term of Newell's polygon-normal accumulation, in double. Matches
- // CalculatePlaneNormal in PerformCSGJob. Accumulate over consecutive (prev,curr) verts, normalize.
+ // One vertex-pair term of Newell's polygon-normal accumulation, in double. Accumulate over consecutive
+ // (prev,curr) verts, normalize.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float3 NewellTerm(float3 prev, float3 curr)
{
diff --git a/Core/2.Processing/Cache/ChiselLookup.cs b/Core/2.Processing/Cache/ChiselLookup.cs
index 8c2e95a6..49435be1 100644
--- a/Core/2.Processing/Cache/ChiselLookup.cs
+++ b/Core/2.Processing/Cache/ChiselLookup.cs
@@ -26,9 +26,8 @@ public class Data
public NativeList brushTreeSpaceBoundCache;
public NativeList> brushTreeSpacePlaneCache;
public NativeList> brushesTouchedByBrushCache;
- public NativeList> loopVerticesCache;
// Each brush as the exact CSG sees it (ExactBrush: exact planes, corners, bounds), rebuilt when the brush
- // changes (ExactInputJob). Only kept up to date while the tree is built exactly (builtExact).
+ // changes (ExactInputJob).
public NativeList> exactBrushCache;
public NativeList decalInstances;
@@ -44,9 +43,6 @@ public class Data
public NativeParallelHashMap> brushRenderBufferLookup;
- // Whether the tree's output was last built by the exact CSG (TreeUpdate.kExactCSG). An update by the other
- // algorithm rebuilds every brush of the tree, so the two never mix in one tree's output.
- public bool builtExact;
// What each hotspot layout was at the last update (ChiselHotspotStore.LayoutHashes, by id - 1)
public NativeList hotspotLayoutHashes;
// Where the weld's last step moved the corners it moved at the last update (from, to; OutputModelWeld)
@@ -79,7 +75,6 @@ internal void Initialize()
brushTreeSpacePlaneCache = new NativeList>(1000, Allocator.Persistent); // Confirmed to get disposed
brushesTouchedByBrushCache = new NativeList>(1000, Allocator.Persistent); // Confirmed to get disposed
brushRenderBufferCache = new NativeList>(1000, Allocator.Persistent); // Confirmed to get disposed
- loopVerticesCache = new NativeList>(1000, Allocator.Persistent); // Confirmed to get disposed
exactBrushCache = new NativeList>(1000, Allocator.Persistent);
decalInstances = new NativeList(16, Allocator.Persistent);
@@ -132,9 +127,6 @@ internal void EnsureCapacity(int brushCount)
if (brushRenderBufferCache.Capacity < brushCount)
brushRenderBufferCache.Capacity = brushCount;
- if (loopVerticesCache.Capacity < brushCount)
- loopVerticesCache.Capacity = brushCount;
-
if (exactBrushCache.Capacity < brushCount)
exactBrushCache.Capacity = brushCount;
}
@@ -235,18 +227,6 @@ internal void Dispose()
brushRenderBufferCache.Dispose();
}
brushRenderBufferCache = default;
- if (loopVerticesCache.IsCreated)
- {
- for (int i = 0; i < loopVerticesCache.Length; i++)
- {
- if (loopVerticesCache[i].IsCreated)
- loopVerticesCache[i].Dispose();
- loopVerticesCache[i] = default;
- }
- loopVerticesCache.Clear();
- loopVerticesCache.Dispose();
- }
- loopVerticesCache = default;
if (exactBrushCache.IsCreated)
{
for (int i = 0; i < exactBrushCache.Length; i++)
@@ -307,7 +287,6 @@ internal void Dispose()
if (brushRenderBufferLookup.IsCreated)
brushRenderBufferLookup.Dispose();
brushRenderBufferLookup = default;
- builtExact = false;
}
}
diff --git a/Core/2.Processing/Containers/InternedPlanes.cs b/Core/2.Processing/Containers/InternedPlanes.cs
deleted file mode 100644
index eb579ab4..00000000
--- a/Core/2.Processing/Containers/InternedPlanes.cs
+++ /dev/null
@@ -1,242 +0,0 @@
-using System;
-using System.Runtime.CompilerServices;
-using Unity.Burst;
-using Unity.Collections;
-using Unity.Collections.LowLevel.Unsafe;
-using Unity.Jobs;
-using Unity.Mathematics;
-
-namespace Chisel.Core
-{
- public unsafe struct InternedPlanes : INativeDisposable
- {
- internal const int kMinHashTableSize = 1024;
-
- internal const double kMaxNormalDeviation = 1e-7;
-
- // A matching normal differs by at most sqrt(2 * kMaxNormalDeviation) in a single component,
- // so it lands in this cell or an adjacent one - which is what makes the 3^4 probe exhaustive.
- internal const float kNormalCellSize = 4.4721e-4f * 2.5f;
-
- internal const float kOffsetCellSize = 1.0f;
-
- const long kHashMagicValue = (long)1099511628211ul;
-
- [NativeDisableUnsafePtrRestriction] UnsafeList* m_Planes;
- [NativeDisableUnsafePtrRestriction] UnsafeList* m_ChainedIndices;
- [NativeDisableUnsafePtrRestriction] void* m_HashTable;
-
- readonly int m_HashMask;
-
- readonly Allocator m_AllocatorLabel;
-
- public readonly bool IsCreated => m_Planes != null && m_ChainedIndices != null && m_HashTable != null;
- public readonly int Count => m_Planes == null ? 0 : m_Planes->Length;
-
- public readonly float4 this[int id] => ((float4*)m_Planes->Ptr)[id];
-
- public InternedPlanes(int minCapacity, Allocator allocator)
- {
- m_AllocatorLabel = allocator;
- var tableSize = math.max(kMinHashTableSize, math.ceilpow2(math.max(1, minCapacity)));
- m_HashMask = tableSize - 1;
- var hashTableMemSize = tableSize * UnsafeUtility.SizeOf();
- m_HashTable = UnsafeUtility.Malloc(hashTableMemSize, UnsafeUtility.AlignOf(), allocator);
- UnsafeUtility.MemClear(m_HashTable, hashTableMemSize);
- m_Planes = UnsafeList.Create(math.max(1, minCapacity), allocator);
- m_ChainedIndices = UnsafeList .Create(math.max(1, minCapacity), allocator);
- }
-
- public void Dispose()
- {
- if (m_Planes != null) { UnsafeList.Destroy(m_Planes); m_Planes = null; }
- if (m_ChainedIndices != null) { UnsafeList .Destroy(m_ChainedIndices); m_ChainedIndices = null; }
- if (m_HashTable != null) { UnsafeUtility.Free(m_HashTable, m_AllocatorLabel); m_HashTable = null; }
- }
-
- [BurstCompile]
- struct DisposeJob : IJob
- {
- [NativeDisableUnsafePtrRestriction] public UnsafeList* planes;
- [NativeDisableUnsafePtrRestriction] public UnsafeList* chainedIndices;
- [NativeDisableUnsafePtrRestriction] public void* hashTable;
- public Allocator allocator;
- public void Execute()
- {
- if (planes != null) UnsafeList.Destroy(planes);
- if (chainedIndices != null) UnsafeList .Destroy(chainedIndices);
- if (hashTable != null) UnsafeUtility.Free(hashTable, allocator);
- }
- }
-
- // Lets the table be torn down on a worker once the jobs reading it have finished, matching
- // how the rest of the pipeline's temporaries are released.
- public JobHandle Dispose(JobHandle inputDeps)
- {
- var jobHandle = new DisposeJob
- {
- planes = m_Planes,
- chainedIndices = m_ChainedIndices,
- hashTable = m_HashTable,
- allocator = m_AllocatorLabel
- }.Schedule(inputDeps);
- m_Planes = null;
- m_ChainedIndices = null;
- m_HashTable = null;
- return jobHandle;
- }
-
- public void Clear()
- {
- m_Planes->Clear();
- m_ChainedIndices->Clear();
- UnsafeUtility.MemClear(m_HashTable, (m_HashMask + 1) * UnsafeUtility.SizeOf());
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static float4 Normalize(float4 plane)
- {
- var length = math.length(plane.xyz);
- return (length > (float)CSGConstants.kDivideMinimumEpsilon) ? (plane / length) : plane;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static double Distance(float4 plane, float3 point)
- {
- return (double)plane.x * point.x + (double)plane.y * point.y + (double)plane.z * point.z + plane.w;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- static int4 CellOf(float4 plane)
- {
- // floor, not truncation: truncating toward zero makes a double-width cell straddling 0,
- // and a plane through the origin is the common case here, not a rare one.
- return new int4((int)math.floor(plane.x / kNormalCellSize),
- (int)math.floor(plane.y / kNormalCellSize),
- (int)math.floor(plane.z / kNormalCellSize),
- (int)math.floor(plane.w / kOffsetCellSize));
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- readonly int GetHash(int4 index)
- {
- var hashCode = (uint)((index.w ^ ((index.y ^ ((index.x ^ index.z) * kHashMagicValue)) * kHashMagicValue)) * kHashMagicValue);
- return (int)(hashCode & (uint)m_HashMask);
- }
-
- readonly bool Matches(float4 stored, float4 query, float3* points, int pointCount, out bool flipped)
- {
- var dot = math.dot(stored.xyz, query.xyz);
- flipped = dot < 0;
- if (1.0 - math.abs((double)dot) > kMaxNormalDeviation)
- return false;
- for (int i = 0; i < pointCount; i++)
- {
- if (math.abs(Distance(stored, points[i])) > CSGConstants.kPlaneDAlignEpsilon)
- return false;
- }
- return true;
- }
-
- readonly bool ProbeCell(int4 cell, float4 query, float3* points, int pointCount,
- out int id, out bool flipped)
- {
- var planes = (float4*)m_Planes->Ptr;
- var chained = (int*)m_ChainedIndices->Ptr;
- var chainIndex = ((int*)m_HashTable)[GetHash(cell)] - 1;
- while (chainIndex != -1)
- {
- if (Matches(planes[chainIndex], query, points, pointCount, out flipped))
- {
- id = chainIndex;
- return true;
- }
- chainIndex = chained[chainIndex] - 1;
- }
- id = -1;
- flipped = false;
- return false;
- }
-
- readonly bool ProbeNeighbourhood(float4 cellSource, float4 query, float3* points, int pointCount,
- out int id, out bool flipped)
- {
- var center = CellOf(cellSource);
- if (ProbeCell(center, query, points, pointCount, out id, out flipped))
- return true;
- for (int dx = -1; dx <= 1; dx++)
- for (int dy = -1; dy <= 1; dy++)
- for (int dz = -1; dz <= 1; dz++)
- for (int dw = -1; dw <= 1; dw++)
- {
- if ((dx | dy | dz | dw) == 0)
- continue; // already done
- if (ProbeCell(center + new int4(dx, dy, dz, dw), query, points, pointCount, out id, out flipped))
- return true;
- }
- id = -1;
- flipped = false;
- return false;
- }
-
- public readonly bool TryFind(float4 plane, float3* points, int pointCount, out int id, out bool flipped)
- {
- plane = Normalize(plane);
- var cell = CellOf(plane);
- var flippedCell = CellOf(-plane);
- if (ProbeCell(cell, plane, points, pointCount, out id, out flipped)) return true;
- if (ProbeCell(flippedCell, plane, points, pointCount, out id, out flipped)) return true;
- if (ProbeNeighbourhood(plane, plane, points, pointCount, out id, out flipped)) return true;
- if (ProbeNeighbourhood(-plane, plane, points, pointCount, out id, out flipped)) return true;
- return false;
- }
-
- public readonly bool TryFind(float4 plane, float3 pointOnPlane, out int id, out bool flipped)
- {
- return TryFind(plane, &pointOnPlane, 1, out id, out flipped);
- }
-
- public readonly bool TryFind(float4 plane, NativeArray pointsOnPlane, out int id, out bool flipped)
- {
- return TryFind(plane, (float3*)pointsOnPlane.GetUnsafeReadOnlyPtr(), pointsOnPlane.Length, out id, out flipped);
- }
-
- // Returns the shared id for this plane, inserting it if it is new.
- public int Add(float4 plane, float3* points, int pointCount, out bool flipped)
- {
- plane = Normalize(plane);
- if (TryFind(plane, points, pointCount, out int existing, out flipped))
- return existing;
-
- flipped = false;
- var hash = GetHash(CellOf(plane));
- var hashTable = (int*)m_HashTable;
- var previousChain = hashTable[hash];
- m_Planes->Add(plane);
- m_ChainedIndices->Add(previousChain);
- hashTable[hash] = m_Planes->Length; // stored as id + 1, so 0 means "empty"
- return m_Planes->Length - 1;
- }
-
- public int Add(float4 plane, float3 pointOnPlane, out bool flipped)
- {
- return Add(plane, &pointOnPlane, 1, out flipped);
- }
-
- public int Add(float4 plane, NativeArray pointsOnPlane, out bool flipped)
- {
- return Add(plane, (float3*)pointsOnPlane.GetUnsafeReadOnlyPtr(), pointsOnPlane.Length, out flipped);
- }
-
- public int Add(float4 plane, float3 pointOnPlane)
- {
- return Add(plane, &pointOnPlane, 1, out _);
- }
-
- public NativeArray AsArray()
- {
- return NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray(
- m_Planes->Ptr, m_Planes->Length, Allocator.None);
- }
- }
-}
diff --git a/Core/2.Processing/Containers/InternedPlanes.cs.meta b/Core/2.Processing/Containers/InternedPlanes.cs.meta
deleted file mode 100644
index c7310008..00000000
--- a/Core/2.Processing/Containers/InternedPlanes.cs.meta
+++ /dev/null
@@ -1,2 +0,0 @@
-fileFormatVersion: 2
-guid: c8393009ff3e5494eb51d132e37b149f
\ No newline at end of file
diff --git a/Core/2.Processing/Exact/ExactFace.cs b/Core/2.Processing/Exact/ExactFace.cs
index 43536a27..95aaeba5 100644
--- a/Core/2.Processing/Exact/ExactFace.cs
+++ b/Core/2.Processing/Exact/ExactFace.cs
@@ -723,7 +723,7 @@ int Route(ref ExactList inside, ref ExactList routingRows, ref Exa
int row = lookupStart[k] + input;
if (row < lookupStart[k] || row >= lookupEnd[k])
{
- // the same as PerformCSGJob: a lookup without a row for this input leaves the input as it is
+ // a lookup without a row for this input leaves the input as it is
routingErrors++;
continue;
}
diff --git a/Core/2.Processing/Jobs/CacheRemappingJob.cs b/Core/2.Processing/Jobs/CacheRemappingJob.cs
index 2f424a96..b9c3f216 100644
--- a/Core/2.Processing/Jobs/CacheRemappingJob.cs
+++ b/Core/2.Processing/Jobs/CacheRemappingJob.cs
@@ -47,7 +47,6 @@ public int Compare(int2 a, int2 b)
[NoAlias] public NativeList> brushTreeSpacePlaneCache;
[NoAlias] public NativeList brushTreeSpaceBoundCache;
[NoAlias] public NativeList> brushesTouchedByBrushCache;
- [NoAlias] public NativeList> loopVerticesCache;
[NoAlias] public NativeList> exactBrushCache;
// Write
@@ -188,8 +187,6 @@ public void Execute()
brushTreeSpacePlaneCache.Resize(maxCount, NativeArrayOptions.ClearMemory);
if (brushesTouchedByBrushCache.Length < maxCount)
brushesTouchedByBrushCache.Resize(maxCount, NativeArrayOptions.ClearMemory);
- if (loopVerticesCache.Length < maxCount)
- loopVerticesCache.Resize(maxCount, NativeArrayOptions.ClearMemory);
if (exactBrushCache.Length < maxCount)
exactBrushCache.Resize(maxCount, NativeArrayOptions.ClearMemory);
@@ -213,7 +210,6 @@ public void Execute()
{ var tmp = brushTreeSpaceBoundCache[source]; brushTreeSpaceBoundCache[source] = default; }
{ var tmp = brushTreeSpacePlaneCache[source]; brushTreeSpacePlaneCache[source] = default; if (tmp.IsCreated) tmp.Dispose(); }
{ var tmp = brushesTouchedByBrushCache[source]; brushesTouchedByBrushCache[source] = default; if (tmp.IsCreated) tmp.Dispose(); }
- { var tmp = loopVerticesCache[source]; loopVerticesCache[source] = default; if (tmp.IsCreated) tmp.Dispose(); }
{ var tmp = exactBrushCache[source]; exactBrushCache[source] = default; if (tmp.IsCreated) tmp.Dispose(); }
continue;
}
@@ -226,7 +222,6 @@ public void Execute()
(brushTreeSpaceBoundCache[source], brushTreeSpaceBoundCache[destination]) = (brushTreeSpaceBoundCache[destination], brushTreeSpaceBoundCache[source]);
(brushTreeSpacePlaneCache[source], brushTreeSpacePlaneCache[destination]) = (brushTreeSpacePlaneCache[destination], brushTreeSpacePlaneCache[source]);
(brushesTouchedByBrushCache[source], brushesTouchedByBrushCache[destination]) = (brushesTouchedByBrushCache[destination], brushesTouchedByBrushCache[source]);
- (loopVerticesCache[source], loopVerticesCache[destination]) = (loopVerticesCache[destination], loopVerticesCache[source]);
(exactBrushCache[source], exactBrushCache[destination]) = (exactBrushCache[destination], exactBrushCache[source]);
}
}
diff --git a/Core/2.Processing/Jobs/CountIntersectionLoopsJob.cs b/Core/2.Processing/Jobs/CountIntersectionLoopsJob.cs
deleted file mode 100644
index a1f05a67..00000000
--- a/Core/2.Processing/Jobs/CountIntersectionLoopsJob.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-using Unity.Burst;
-using Unity.Collections;
-using Unity.Jobs;
-using Unity.Collections.LowLevel.Unsafe;
-using ReadOnlyAttribute = Unity.Collections.ReadOnlyAttribute;
-using WriteOnlyAttribute = Unity.Collections.WriteOnlyAttribute;
-using Unity.Entities;
-
-namespace Chisel.Core
-{
- [BurstCompile(CompileSynchronously = true)]
- struct CountIntersectionLoopsJob : IJob
- {
- // Read
- [NoAlias, ReadOnly] public NativeList uniqueBrushPairs;
- [NoAlias, ReadOnly] public NativeArray> brushMeshLookup;
-
- // Write
- [NoAlias, WriteOnly] public NativeReference intersectionLoopCountRef;
-
- readonly int FaceCountOf(int nodeOrder)
- {
- if (nodeOrder < 0 || nodeOrder >= brushMeshLookup.Length)
- return 0;
- var brushMesh = brushMeshLookup[nodeOrder];
- // A brush without a mesh has no faces, so it makes no loops.
- if (!brushMesh.IsCreated)
- return 0;
- return brushMesh.Value.localPlaneCount;
- }
-
- public void Execute()
- {
- var total = 0;
- for (int i = 0; i < uniqueBrushPairs.Length; i++)
- {
- var pair = uniqueBrushPairs[i];
- if (pair.type == IntersectionType.InvalidValue)
- continue;
- total += FaceCountOf(pair.brushIndexOrder0.nodeOrder) +
- FaceCountOf(pair.brushIndexOrder1.nodeOrder);
- }
- intersectionLoopCountRef.Value = total;
- }
- }
-}
diff --git a/Core/2.Processing/Jobs/CountIntersectionLoopsJob.cs.meta b/Core/2.Processing/Jobs/CountIntersectionLoopsJob.cs.meta
deleted file mode 100644
index 1179d5fd..00000000
--- a/Core/2.Processing/Jobs/CountIntersectionLoopsJob.cs.meta
+++ /dev/null
@@ -1,2 +0,0 @@
-fileFormatVersion: 2
-guid: 5473274e6fbcfa5dd8e040da6ef7473b
\ No newline at end of file
diff --git a/Core/2.Processing/Jobs/CreateIntersectionLoopsJob.cs b/Core/2.Processing/Jobs/CreateIntersectionLoopsJob.cs
deleted file mode 100644
index 75b61abf..00000000
--- a/Core/2.Processing/Jobs/CreateIntersectionLoopsJob.cs
+++ /dev/null
@@ -1,1172 +0,0 @@
-using System;
-using Unity.Burst;
-using Unity.Collections;
-using Unity.Jobs;
-using Unity.Mathematics;
-using Unity.Collections.LowLevel.Unsafe;
-using System.Runtime.CompilerServices;
-using System.Collections.Generic;
-using Debug = UnityEngine.Debug;
-using ReadOnlyAttribute = Unity.Collections.ReadOnlyAttribute;
-using WriteOnlyAttribute = Unity.Collections.WriteOnlyAttribute;
-using Unity.Entities;
-
-namespace Chisel.Core
-{
- [BurstCompile(CompileSynchronously = true)]
- struct CreateIntersectionLoopsJob : IJobParallelForDefer
- {
- const float kFatPlaneWidthEpsilon = CSGConstants.kFatPlaneWidthEpsilon;
-
- // Needed for count (forced & unused)
- [NoAlias, ReadOnly] public NativeList uniqueBrushPairs;
-
- // Read
- // Gate the vertex weld on plane incidence (WeldIncidenceFilter); set from CSGManager's kUseIncidenceWeld.
- [NoAlias, ReadOnly] public bool useIncidenceWeld;
- [NoAlias, ReadOnly] public NativeList> brushTreeSpacePlaneCache;
- [NoAlias, ReadOnly] public NativeList> treeSpaceVerticesCache;
- [NoAlias, ReadOnly] public NativeStream.Reader intersectingBrushesStream;
-
- // Canonical vertices (see CanonicalVertices)
- [NoAlias, ReadOnly] public CanonicalVertexStage canonicalVertexStage;
- [NoAlias, ReadOnly] public NativeList> brushesTouchedByBrushCache;
-
- // Write
- [NoAlias, WriteOnly] public NativeListExtensions.ParallelWriterExt outputSurfaceVertices;
- [NoAlias, WriteOnly] public NativeList.ParallelWriter outputSurfaces;
-
- // Per thread scratch memory
- //[NativeDisableContainerSafetyRestriction] NativeArray localVertices;
- //[NativeDisableContainerSafetyRestriction] NativeArray usedVertexIndices;
- //[NativeDisableContainerSafetyRestriction] NativeArray planeIndexOffsets;
- //[NativeDisableContainerSafetyRestriction] NativeList uniqueIndices;
- //[NativeDisableContainerSafetyRestriction] NativeArray sortedStack;
- //[NativeDisableContainerSafetyRestriction] NativeArray foundIndices0;
- //[NativeDisableContainerSafetyRestriction] NativeArray foundIndices1;
- //[NativeDisableContainerSafetyRestriction] NativeArray foundVertices;
- //[NativeDisableContainerSafetyRestriction] NativeArray foundEdges;
- //[NativeDisableContainerSafetyRestriction] NativeArray foundIntersections;
- //[NativeDisableContainerSafetyRestriction] NativeArray temporaryVertices;
- //[NativeDisableContainerSafetyRestriction] HashedVertices hashedTreeSpaceVertices;
- //[NativeDisableContainerSafetyRestriction] HashedVertices snapHashedVertices;
-
- internal struct PlaneVertexIndexPair
- {
- public ushort planeIndex;
- public ushort vertexIndex;
- }
-
- struct PlaneIndexOffsetLength
- {
- public ushort length;
- public ushort offset;
- public ushort planeIndex;
- }
-
- static bool IsOutsidePlanes([NoAlias, ReadOnly] NativeArray planes, int planesLength, float4 localVertex)
- {
- int n = 0;
- for (; n + 4 < planesLength; n+=4)
- {
- var distance = new float4(math.dot(planes[n+0], localVertex),
- math.dot(planes[n+1], localVertex),
- math.dot(planes[n+2], localVertex),
- math.dot(planes[n+3], localVertex));
-
- // will be 'false' when distance is NaN or Infinity
- if (!math.all(distance <= kFatPlaneWidthEpsilon))
- return true;
- }
- for (; n < planesLength; n ++)
- {
- var distance = math.dot(planes[n], localVertex);
-
- // will be 'false' when distance is NaN or Infinity
- if (!(distance <= kFatPlaneWidthEpsilon))
- return true;
- }
- return false;
- }
-
-
- #region Sort
- static float3 FindPolygonCentroid([NoAlias, ReadOnly] HashedVertices vertices, [NoAlias, ReadOnly] NativeArray indices, int offset, int indicesCount)
- {
- var centroid = float3.zero;
- for (int i = 0; i < indicesCount; i++, offset++)
- centroid += vertices[indices[offset]];
- return centroid / indicesCount;
- }
-
- // TODO: sort by using plane information instead of unreliable floating point math ..
- static void SortIndices([NoAlias, ReadOnly] HashedVertices vertices, [NoAlias, ReadOnly] NativeArray sortedStack, [NoAlias, ReadOnly] NativeArray indices, int offset, int indicesCount, float3 normal)
- {
- // There's no point in trying to sort a point or a line
- if (indicesCount < 3)
- return;
-
- float3 tangentX, tangentY;
- if (normal.x > normal.y)
- {
- if (normal.x > normal.z)
- {
- tangentX = math.cross(normal, new float3(0, 1, 0));
- tangentY = math.cross(normal, tangentX);
- } else
- {
- tangentX = math.cross(normal, new float3(0, 0, 1));
- tangentY = math.cross(normal, tangentX);
- }
- } else
- {
- if (normal.y > normal.z)
- {
- tangentX = math.cross(normal, new float3(1, 0, 0));
- tangentY = math.cross(normal, tangentX);
- } else
- {
- tangentX = math.cross(normal, new float3(0, 1, 0));
- tangentY = math.cross(normal, tangentX);
- }
- }
-
- var centroid = FindPolygonCentroid(vertices, indices, offset, indicesCount);
- var center = new float2(math.dot(tangentX, centroid), // distance in direction of tangentX
- math.dot(tangentY, centroid)); // distance in direction of tangentY
-
-
- var sortedStackLength = 1;
- sortedStack[0] = new int2(0, indicesCount - 1);
- while (sortedStackLength > 0)
- {
- var top = sortedStack[sortedStackLength - 1];
- sortedStackLength--;
- var l = top.x;
- var r = top.y;
- var left = l;
- var right = r;
- var va = vertices[indices[offset + (left + right) / 2]];
- while (true)
- {
- var a_angle = math.atan2(math.dot(tangentX, va) - center.x, math.dot(tangentY, va) - center.y);
-
- {
- var vb = vertices[indices[offset + left]];
- var b_angle = math.atan2(math.dot(tangentX, vb) - center.x, math.dot(tangentY, vb) - center.y);
- while (b_angle > a_angle)
- {
- left++;
- vb = vertices[indices[offset + left]];
- b_angle = math.atan2(math.dot(tangentX, vb) - center.x, math.dot(tangentY, vb) - center.y);
- }
- }
-
- {
- var vb = vertices[indices[offset + right]];
- var b_angle = math.atan2(math.dot(tangentX, vb) - center.x, math.dot(tangentY, vb) - center.y);
- while (a_angle > b_angle)
- {
- right--;
- vb = vertices[indices[offset + right]];
- b_angle = math.atan2(math.dot(tangentX, vb) - center.x, math.dot(tangentY, vb) - center.y);
- }
- }
-
- if (left <= right)
- {
- if (left != right)
- {
- var t = indices[offset + left];
- indices[offset + left] = indices[offset + right];
- indices[offset + right] = t;
- }
-
- left++;
- right--;
- }
- if (left > right)
- break;
- }
- if (l < right)
- {
- sortedStack[sortedStackLength] = new int2(l, right);
- sortedStackLength++;
- }
- if (left < r)
- {
- sortedStack[sortedStackLength] = new int2(left, r);
- sortedStackLength++;
- }
- }
- }
- #endregion
-
- //[MethodImpl(MethodImplOptions.NoInlining)]
- void FindInsideVertices([NoAlias, ReadOnly] NativeArray usedVertices0,
- int usedVertices0Length,
- [NoAlias, ReadOnly] NativeArray vertexIntersectionPlanes,
- int vertexIntersectionPlanesLength,
- [NoAlias, ReadOnly] NativeArray vertexIntersectionSegments,
- int vertexIntersectionSegmentsLength,
- [NoAlias, ReadOnly] NativeArray intersectingPlanes1,
- int intersectingPlanes1Length,
- int intersectingPlanesAndEdges1Length,
- float4x4 nodeToTreeSpaceMatrix1,
- float4x4 vertexToLocal0,
- [NoAlias] ref HashedVertices hashedTreeSpaceVertices,
- [NoAlias] ref HashedVertices snapHashedVertices,
- [NoAlias] NativeArray foundIndices0,
- ref int foundIndices0Length,
- in WeldIncidenceFilter weldFilter = default,
- in CanonicalVertices canonical = default,
- int canonicalNodeOrder = -1)
- {
- NativeArray localVertices;
- using var _localVertices = localVertices = new NativeArray(usedVertices0Length, Allocator.Temp);
- //NativeCollectionHelpers.EnsureMinimumSize(ref localVertices, usedVertices0Length);
-
- NativeArray usedVertexIndices;
- using var _usedVertexIndices = usedVertexIndices = new NativeArray(usedVertices0Length, Allocator.Temp);
- //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 = canonical.Canonicalize(treeSpaceVertex, canonicalNodeOrder, CanonicalVertexSite.InsideVertex);
- treeSpaceVertex = snapHashedVertices[snapHashedVertices.AddNoResize(treeSpaceVertex, in weldFilter)];
- var treeSpaceVertexIndex = hashedTreeSpaceVertices.AddNoResize(treeSpaceVertex, in weldFilter);
- 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:
- ;
- }
- }
- }
-
- struct IntersectionPlanes
- {
- //public float4 plane0;
- //public float4 plane1;
- public float4 plane2;
- public int planeIndex0;
- public int planeIndex1;
- public int planeIndex2;
- }
-
- struct IntersectionEdge
- {
- public float4 edgeVertex0;
- public float4 edgeVertex1;
- }
-
- [MethodImpl(MethodImplOptions.NoInlining)]
- void FindIntersectionVertices(ref NativeArray intersectingPlanes0,
- int intersectingPlanes0Length,
- int intersectingPlanesAndEdges0Length,
- ref NativeArray intersectingPlanes1,
- int intersectingPlanes1Length,
- int intersectingPlanesAndEdges1Length,
- ref NativeArray usedPlanePairs1,
- int usedPlanePairs1Length,
- ref NativeArray intersectingPlaneIndices0,
- int intersectingPlaneIndices0Length,
- float4x4 nodeToTreeSpaceMatrix0,
- ref HashedVertices hashedTreeSpaceVertices,
- ref HashedVertices snapHashedVertices,
- NativeArray foundIndices0,
- ref int foundIndices0Length,
- NativeArray foundIndices1,
- ref int foundIndices1Length,
- in WeldIncidenceFilter weldFilter = default,
- in CanonicalVertices canonical = default,
- int canonicalNodeOrder = -1)
- {
- int foundVerticesCount = usedPlanePairs1Length * intersectingPlanes0Length;
- NativeArray foundVertices;
- using var _foundVertices = foundVertices = new NativeArray (foundVerticesCount, Allocator.Temp);
- //NativeCollectionHelpers.EnsureMinimumSize(ref foundVertices, foundVerticesCount);
-
- NativeArray foundEdges;
- using var _foundEdges = foundEdges = new NativeArray (foundVerticesCount, Allocator.Temp);
- //NativeCollectionHelpers.EnsureMinimumSize(ref foundEdges, foundVerticesCount);
-
- NativeArray foundIntersections;
- using var _foundIntersections = foundIntersections = new NativeArray (foundVerticesCount, Allocator.Temp);
- //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 = canonical.Canonicalize(treeSpaceVertex, canonicalNodeOrder, CanonicalVertexSite.PairIntersection);
- treeSpaceVertex = snapHashedVertices[snapHashedVertices.AddNoResize(treeSpaceVertex, in weldFilter)];
- var treeSpaceVertexIndex = hashedTreeSpaceVertices.AddNoResize(treeSpaceVertex, in weldFilter);
-
- {
- // 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: ;
- }
- }
- }
- /*
- struct Comparer : IComparer
- {
- public int Compare(PlaneVertexIndexPair x, PlaneVertexIndexPair y)
- {
- 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;
- }
- }
- readonly static readonly Comparer kComparer = new Comparer();
- */
- internal void AddFullSurfaceLoopsForAlignedFaces(
- [NoAlias, ReadOnly] ref BlobArray treeSpaceVertices0,
- [NoAlias, ReadOnly] ref BrushTreeSpacePlanes brushTreeSpacePlanes0,
- [NoAlias, ReadOnly] ref BrushTreeSpacePlanes brushTreeSpacePlanes1,
- [NoAlias, ReadOnly] NativeArray surfaceInfos0, int surfaceInfosLength0,
- [NoAlias, ReadOnly] NativeArray intersectingPlaneIndices0, int intersectingPlanesLength0,
- int facePlaneCount1,
- [NoAlias] NativeArray foundIndices0, ref int foundIndices0Length,
- [NoAlias] ref HashedVertices hashedTreeSpaceVertices,
- [NoAlias] ref HashedVertices snapHashedVertices,
- in WeldIncidenceFilter weldFilter = default,
- in CanonicalVertices canonical = default,
- int canonicalNodeOrder = -1)
- {
- ref var planes0 = ref brushTreeSpacePlanes0.treeSpacePlanes;
- ref var planes1 = ref brushTreeSpacePlanes1.treeSpacePlanes;
- facePlaneCount1 = math.min(facePlaneCount1, planes1.Length);
- if (facePlaneCount1 < 4) // fewer than a tetrahedron's faces cannot bound a volume
- return;
-
- for (int i = 0; i < intersectingPlanesLength0; i++)
- {
- var planeIndex = intersectingPlaneIndices0[i];
- if (planeIndex < 0 || planeIndex >= surfaceInfosLength0 || planeIndex >= planes0.Length)
- continue;
-
- var category = (CategoryIndex)surfaceInfos0[planeIndex].interiorCategory;
-
- if (category != CategoryIndex.Aligned &&
- category != CategoryIndex.ReverseAligned)
- continue;
-
- // leave any face that already got a real crossing loop completely alone
- int alreadyFound = 0;
- for (int f = 0; f < foundIndices0Length; f++)
- {
- if (foundIndices0[f].planeIndex == planeIndex)
- alreadyFound++;
- }
- if (alreadyFound >= 3)
- continue;
-
- var facePlane = planes0[planeIndex];
-
- float4 counterpartProbe = default;
- bool haveCounterpartProbe = false;
- for (int v = 0; v < treeSpaceVertices0.Length; v++)
- {
- var candidate = new float4(treeSpaceVertices0[v], 1);
- if (math.abs(math.dot(facePlane, candidate)) > kFatPlaneWidthEpsilon)
- continue;
- counterpartProbe = candidate;
- haveCounterpartProbe = true;
- break;
- }
- if (!haveCounterpartProbe)
- continue;
-
- int coplanarPlane1 = -1;
- float coplanarDistance = float.MaxValue;
- for (int q = 0; q < facePlaneCount1; q++)
- {
- if (math.abs(math.dot(facePlane.xyz, planes1[q].xyz)) < CSGConstants.kNormalDotAlignEpsilon)
- continue;
- var distance = math.abs(math.dot(planes1[q], counterpartProbe));
- if (distance < coplanarDistance)
- {
- coplanarDistance = distance;
- coplanarPlane1 = q;
- }
- }
-
- // every vertex of this face must lie inside the other brush
- int onFace = 0;
- bool covered = true;
- for (int v = 0; v < treeSpaceVertices0.Length && covered; v++)
- {
- var vertex = new float4(treeSpaceVertices0[v], 1);
- if (math.abs(math.dot(facePlane, vertex)) > kFatPlaneWidthEpsilon)
- continue;
- onFace++;
- for (int q = 0; q < facePlaneCount1; q++)
- {
- if (q == coplanarPlane1)
- continue;
- if (math.dot(planes1[q], vertex) > kFatPlaneWidthEpsilon)
- { covered = false; break; }
- }
- }
- if (!covered || onFace < 3)
- continue;
-
- // the face's own vertices become the loop; GenerateLoop sorts them around the normal
- for (int v = 0; v < treeSpaceVertices0.Length; v++)
- {
- if (foundIndices0Length >= foundIndices0.Length)
- return;
- var treeSpaceVertex = treeSpaceVertices0[v];
- if (math.abs(math.dot(facePlane, new float4(treeSpaceVertex, 1))) > kFatPlaneWidthEpsilon)
- continue;
- treeSpaceVertex = canonical.Canonicalize(treeSpaceVertex, canonicalNodeOrder, CanonicalVertexSite.AlignedFace);
- treeSpaceVertex = snapHashedVertices[snapHashedVertices.AddNoResize(treeSpaceVertex, in weldFilter)];
- var vertexIndex = hashedTreeSpaceVertices.AddNoResize(treeSpaceVertex, in weldFilter);
- bool duplicate = false;
- for (int f = 0; f < foundIndices0Length; f++)
- {
- if (foundIndices0[f].vertexIndex == vertexIndex &&
- foundIndices0[f].planeIndex == planeIndex)
- { duplicate = true; break; }
- }
- if (duplicate)
- continue;
- foundIndices0[foundIndices0Length] = new PlaneVertexIndexPair
- { planeIndex = (ushort)planeIndex, vertexIndex = vertexIndex };
- foundIndices0Length++;
- }
- }
- }
-
- [MethodImpl(MethodImplOptions.NoInlining)]
- void GenerateLoop(IndexOrder brushIndexOrder0,
- IndexOrder brushIndexOrder1,
- bool invertedTransform,
- [NoAlias, ReadOnly] NativeArray surfaceInfos,
- [NoAlias] int surfaceInfosLength,
- [NoAlias, ReadOnly] ref BrushTreeSpacePlanes brushTreeSpacePlanes0,
- [NoAlias, ReadOnly] NativeArray foundIndices0,
- [NoAlias] ref int foundIndices0Length,
- [NoAlias] ref HashedVertices hashedTreeSpaceVertices,
- [NoAlias] NativeList.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(kComparer);
- //*/
-
- NativeArray planeIndexOffsets;
- using var _planeIndexOffsets = planeIndexOffsets = new NativeArray(foundIndices0Length, Allocator.Temp);
- //NativeCollectionHelpers.EnsureMinimumSize(ref planeIndexOffsets, foundIndices0Length);
-
- NativeList uniqueIndices;
- using var _uniqueIndices = uniqueIndices = new NativeList(foundIndices0Length, Allocator.Temp);
- //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);
-
- var uniqueIndicesArray = uniqueIndices.AsArray();
-
- using var sortedStack = new NativeArray(maxLength * 2, Allocator.Temp);
- //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];
- ref var vertices = ref 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, uniqueIndicesArray, offset, length, normal);
- }
-
-
- var totalLoopsSize = 16 + (planeIndexOffsetsLength * UnsafeUtility.SizeOf());
- var totalSize = totalLoopsSize;
- for (int j = 0; j < planeIndexOffsetsLength; j++)
- {
- var planeIndexLength = planeIndexOffsets[j];
- var loopLength = planeIndexLength.length;
- totalSize += (loopLength * UnsafeUtility.SizeOf());
- }
-
- ref var srcVertices = ref 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];
-
- NativeArray temporaryVertices;
- using var _temporaryVertices = temporaryVertices = new NativeArray(loopLength, Allocator.Temp);
- //NativeCollectionHelpers.EnsureMinimumSize(ref temporaryVertices, loopLength);
-
- for (int d = 0; d < loopLength; d++)
- temporaryVertices[d] = srcVertices[uniqueIndicesArray[offset + d]];
-
- var loopVertexIndex = outputSurfaceVertices.AddRangeNoResize(temporaryVertices, loopLength);
-
- outputSurfaces.AddNoResize(new BrushIntersectionLoop
- {
- indexOrder0 = brushIndexOrder0,
- indexOrder1 = brushIndexOrder1,
- surfaceInfo = surfaceInfo,
- loopVertexIndex = loopVertexIndex,
- loopVertexCount = loopLength
- });
- }
- }
-
- // Handles situation where a vertex leads back to itself, could potentially happen when planes graze edges
- private readonly int RemoveDuplicateEdges(ref NativeList uniqueIndices, int start, int end)
- {
- int length = end - start;
- if (length <= 2)
- return 0;
-
- // UNTESTED
- for (int indexA = end - 1, indexB = start, indexC = start + 1; indexA >= start; )
- {
- var vertexIndexA = uniqueIndices[indexA];
- //var vertexIndexB = uniqueIndices[indexB];
- var vertexIndexC = uniqueIndices[indexC];
-
- // B
- // *
- // |
- // A * C
-
- if (vertexIndexA != vertexIndexC)
- {
- indexC = indexB;
- indexB = indexA;
- indexA --;
- continue;
- }
-
- // TODO: test this
- Debug.Log("Untested condition occured, please share scene");
- length -=2;
- if (length <= 2)
- return 0;
-
- if (indexC > end - 2)
- {
- // 0 1 2 3 5 6 1
- // B C A
- uniqueIndices.MemMove(start, indexC + 1, end - (indexC + 1));
- indexA -= 2;
- end -= 2;
- } else
- if (indexC < end - 2)
- {
- // 0 1 2 3 4 5 6
- // A B C
- uniqueIndices.MemMove(indexA, indexC + 1, end - (indexC + 1));
- end -= 2;
- } else
- if (indexC == end - 2)
- {
- // 0 1 2 3 4 5 6
- // A B C
- end -= 2;
- }
-
- indexB = indexA + 1; if (indexB >= end) indexB = start;
- indexC = indexB + 1; if (indexC >= end) indexC = start;
- }
- return length;
- }
-
- // Note: Temporary BlobAssetReference that only exists during a single frame
- public struct BrushPairIntersection
- {
- public IntersectionType type;
- // Note: that the localSpacePlanes0/localSpacePlaneIndices0 parameters for both brush0 and brush1 are in localspace of >brush0<
- public BrushIntersectionInfo brush0;
- public BrushIntersectionInfo brush1;
- }
-
- public struct BrushIntersectionInfo
- {
- public IndexOrder brushIndexOrder;
-
- [NativeDisableContainerSafetyRestriction]
- public NativeArray usedVertices;
- public int usedVerticesLength;
-
- [NativeDisableContainerSafetyRestriction]
- public NativeArray usedPlanePairs;
- public int usedPlanePairsLength;
-
- [NativeDisableContainerSafetyRestriction]
- public NativeArray localSpacePlanes0; // planes in local space of >brush0<
- public int localSpacePlanes0Length;
- public int localSpacePlanesAndEdges0Length;
-
- [NativeDisableContainerSafetyRestriction]
- public NativeArray localSpacePlaneIndices0; // planes indices of >brush0<
- public int localSpacePlaneIndices0Length;
-
- public float4x4 nodeToTreeSpace;
- public float4x4 toOtherBrushSpace;
-
- [NativeDisableContainerSafetyRestriction]
- public NativeArray vertexIntersectionPlanes;
- public int vertexIntersectionPlanesLength;
-
- [NativeDisableContainerSafetyRestriction]
- public NativeArray vertexIntersectionSegments;
- public int vertexIntersectionSegmentsLength;
-
- [NativeDisableContainerSafetyRestriction]
- public NativeArray surfaceInfos;
- public int surfaceInfosLength;
- }
-
- [NativeDisableContainerSafetyRestriction]
- BrushPairIntersection intersection;
-
- public void Execute(int index)
- {
- intersectingBrushesStream.BeginForEachIndex(index);
-
- intersectingBrushesStream.Read(out this.intersection.type);
- if (this.intersection.type == IntersectionType.InvalidValue)
- return;
-
- intersectingBrushesStream.Read(out this.intersection.brush0.brushIndexOrder);
- intersectingBrushesStream.Read(out this.intersection.brush0.nodeToTreeSpace);
- intersectingBrushesStream.Read(out this.intersection.brush0.toOtherBrushSpace);
-
- intersectingBrushesStream.ReadArrayAndEnsureSize(ref this.intersection.brush0.usedVertices, out this.intersection.brush0.usedVerticesLength);
- intersectingBrushesStream.ReadArrayAndEnsureSize(ref this.intersection.brush0.usedPlanePairs, out this.intersection.brush0.usedPlanePairsLength);
- intersectingBrushesStream.ReadArrayAndEnsureSize(ref this.intersection.brush0.localSpacePlanes0, out this.intersection.brush0.localSpacePlanesAndEdges0Length);
-
- intersectingBrushesStream.Read(out this.intersection.brush0.localSpacePlanes0Length);
-
- intersectingBrushesStream.ReadArrayAndEnsureSize(ref this.intersection.brush0.localSpacePlaneIndices0, out this.intersection.brush0.localSpacePlaneIndices0Length);
- intersectingBrushesStream.ReadArrayAndEnsureSize(ref this.intersection.brush0.vertexIntersectionPlanes, out this.intersection.brush0.vertexIntersectionPlanesLength);
- intersectingBrushesStream.ReadArrayAndEnsureSize(ref this.intersection.brush0.vertexIntersectionSegments, out this.intersection.brush0.vertexIntersectionSegmentsLength);
- intersectingBrushesStream.ReadArrayAndEnsureSize(ref this.intersection.brush0.surfaceInfos, out this.intersection.brush0.surfaceInfosLength);
-
- intersectingBrushesStream.Read(out this.intersection.brush1.brushIndexOrder);
- intersectingBrushesStream.Read(out this.intersection.brush1.nodeToTreeSpace);
- intersectingBrushesStream.Read(out this.intersection.brush1.toOtherBrushSpace);
-
- intersectingBrushesStream.ReadArrayAndEnsureSize(ref this.intersection.brush1.usedVertices, out this.intersection.brush1.usedVerticesLength);
- intersectingBrushesStream.ReadArrayAndEnsureSize(ref this.intersection.brush1.usedPlanePairs, out this.intersection.brush1.usedPlanePairsLength);
- intersectingBrushesStream.ReadArrayAndEnsureSize(ref this.intersection.brush1.localSpacePlanes0, out this.intersection.brush1.localSpacePlanesAndEdges0Length);
-
- intersectingBrushesStream.Read(out this.intersection.brush1.localSpacePlanes0Length);
-
- intersectingBrushesStream.ReadArrayAndEnsureSize(ref this.intersection.brush1.localSpacePlaneIndices0, out this.intersection.brush1.localSpacePlaneIndices0Length);
- intersectingBrushesStream.ReadArrayAndEnsureSize(ref this.intersection.brush1.vertexIntersectionPlanes, out this.intersection.brush1.vertexIntersectionPlanesLength);
- intersectingBrushesStream.ReadArrayAndEnsureSize(ref this.intersection.brush1.vertexIntersectionSegments, out this.intersection.brush1.vertexIntersectionSegmentsLength);
- intersectingBrushesStream.ReadArrayAndEnsureSize(ref this.intersection.brush1.surfaceInfos, out this.intersection.brush1.surfaceInfosLength);
- intersectingBrushesStream.EndForEachIndex();
-
-
- ref var brushPairIntersection0 = ref intersection.brush0;
- ref var brushPairIntersection1 = ref intersection.brush1;
- var brushIndexOrder0 = brushPairIntersection0.brushIndexOrder;
- var brushIndexOrder1 = brushPairIntersection1.brushIndexOrder;
-
- UnityEngine.Debug.Assert(brushPairIntersection0.brushIndexOrder.compactNodeID == brushIndexOrder0.compactNodeID);
- UnityEngine.Debug.Assert(brushPairIntersection1.brushIndexOrder.compactNodeID == brushIndexOrder1.compactNodeID);
-
- var weldFilter = WeldIncidenceFilter.Disabled;
- if (useIncidenceWeld &&
- brushTreeSpacePlaneCache[brushIndexOrder0.nodeOrder].IsCreated &&
- brushTreeSpacePlaneCache[brushIndexOrder1.nodeOrder].IsCreated)
- weldFilter = WeldIncidenceFilter.Create(ref brushTreeSpacePlaneCache[brushIndexOrder0.nodeOrder].Value.treeSpacePlanes, brushPairIntersection0.surfaceInfosLength,
- ref brushTreeSpacePlaneCache[brushIndexOrder1.nodeOrder].Value.treeSpacePlanes, brushPairIntersection1.surfaceInfosLength);
-
- // Canonical vertices: every vertex this pair creates lies on its first brush, and that brush's touching
- // brushes include the second, so the first brush is where each vertex's key is gathered.
- var canonical = CanonicalVertices.Create(canonicalVertexStage, brushTreeSpacePlaneCache, brushesTouchedByBrushCache);
- var canonicalNodeOrder = brushIndexOrder0.nodeOrder;
- if (canonical.DecidesLoopIdentity)
- weldFilter = WeldIncidenceFilter.SameVertexOnly;
-
- int insideVerticesStream0Capacity = math.max(1, brushPairIntersection0.usedVerticesLength);
- int insideVerticesStream1Capacity = math.max(1, brushPairIntersection1.usedVerticesLength);
- int intersectionStream0Capacity = math.max(1, brushPairIntersection1.usedPlanePairsLength) * brushPairIntersection0.localSpacePlanes0Length;
- int intersectionStream1Capacity = math.max(1, brushPairIntersection0.usedPlanePairsLength) * brushPairIntersection1.localSpacePlanes0Length;
- int foundIndices0Capacity = intersectionStream0Capacity + (2 * intersectionStream1Capacity) + (brushPairIntersection0.localSpacePlanes0Length * insideVerticesStream0Capacity);
- int foundIndices1Capacity = intersectionStream1Capacity + (2 * intersectionStream0Capacity) + (brushPairIntersection1.localSpacePlanes0Length * insideVerticesStream1Capacity);
-
- var foundIndices0Length = 0;
- var foundIndices1Length = 0;
-
- var desiredVertexCapacity = math.max(foundIndices0Capacity, foundIndices1Capacity);
-
- NativeArray foundIndices0;
- using var _foundIndices0 = foundIndices0 = new NativeArray(foundIndices0Capacity, Allocator.Temp);
- //NativeCollectionHelpers.EnsureMinimumSize(ref foundIndices0, foundIndices0Capacity);
-
- NativeArray foundIndices1;
- using var _foundIndices1 = foundIndices1 = new NativeArray(foundIndices1Capacity, Allocator.Temp);
- //NativeCollectionHelpers.EnsureMinimumSize(ref foundIndices1, foundIndices1Capacity);
-
- HashedVertices hashedTreeSpaceVertices;
- using var _hashedTreeSpaceVertices = hashedTreeSpaceVertices = new HashedVertices(desiredVertexCapacity, Allocator.Temp);
- //NativeCollectionHelpers.EnsureCapacityAndClear(ref hashedTreeSpaceVertices, desiredVertexCapacity);
-
- HashedVertices snapHashedVertices;
- using var _snapHashedVertices = snapHashedVertices = new HashedVertices(desiredVertexCapacity, Allocator.Temp);
- //NativeCollectionHelpers.EnsureCapacityAndClear(ref snapHashedVertices, desiredVertexCapacity);
-
-
- // TODO: fill them with original brush vertices so that they're always snapped to these
-
- // With canonical positions the brush corners here would be raw ones, and snapping a canonical vertex onto
- // them would undo it; a canonical corner that is the same vertex has the same bits anyway.
- if (canonical.MovesVertices)
- {
- } else
- if (brushIndexOrder0.nodeOrder < brushIndexOrder1.nodeOrder)
- {
- snapHashedVertices.AddUniqueVertices(ref treeSpaceVerticesCache[brushIndexOrder0.nodeOrder].Value.treeSpaceVertices);
- snapHashedVertices.ReplaceIfExists(ref treeSpaceVerticesCache[brushIndexOrder1.nodeOrder].Value.treeSpaceVertices, in weldFilter);
- } else
- {
- snapHashedVertices.AddUniqueVertices(ref treeSpaceVerticesCache[brushIndexOrder1.nodeOrder].Value.treeSpaceVertices);
- snapHashedVertices.ReplaceIfExists(ref treeSpaceVerticesCache[brushIndexOrder0.nodeOrder].Value.treeSpaceVertices, in weldFilter);
- }
-
-
-
- // First find vertices from other brush that are inside the other brush, so that any vertex we
- // find during the intersection part will be snapped to those vertices and not the other way around
-
- // TODO: when all vertices of a polygon are inside the other brush, don't bother intersecting it.
- // same when two planes overlap each other ...
-
- // Now find all the intersection vertices
- if (intersection.type == IntersectionType.Intersection)
- {
- if (brushPairIntersection1.usedPlanePairsLength > 0)
- {
- FindIntersectionVertices(ref brushPairIntersection0.localSpacePlanes0,
- brushPairIntersection0.localSpacePlanes0Length,
- brushPairIntersection0.localSpacePlanesAndEdges0Length,
- ref brushPairIntersection1.localSpacePlanes0,
- brushPairIntersection1.localSpacePlanes0Length,
- brushPairIntersection1.localSpacePlanesAndEdges0Length,
- ref brushPairIntersection1.usedPlanePairs,
- brushPairIntersection1.usedPlanePairsLength,
- ref brushPairIntersection0.localSpacePlaneIndices0,
- brushPairIntersection0.localSpacePlaneIndices0Length,
- brushPairIntersection0.nodeToTreeSpace,
- ref hashedTreeSpaceVertices,
- ref snapHashedVertices,
- foundIndices0, ref foundIndices0Length,
- foundIndices1, ref foundIndices1Length, in weldFilter, in canonical, canonicalNodeOrder);
- }
-
- if (brushPairIntersection0.usedPlanePairsLength > 0)
- {
- FindIntersectionVertices(ref brushPairIntersection1.localSpacePlanes0,
- brushPairIntersection1.localSpacePlanes0Length,
- brushPairIntersection1.localSpacePlanesAndEdges0Length,
- ref brushPairIntersection0.localSpacePlanes0,
- brushPairIntersection0.localSpacePlanes0Length,
- brushPairIntersection0.localSpacePlanesAndEdges0Length,
- ref brushPairIntersection0.usedPlanePairs,
- brushPairIntersection0.usedPlanePairsLength,
- ref brushPairIntersection1.localSpacePlaneIndices0,
- brushPairIntersection1.localSpacePlaneIndices0Length,
- brushPairIntersection0.nodeToTreeSpace,
- ref hashedTreeSpaceVertices,
- ref snapHashedVertices,
- foundIndices1, ref foundIndices1Length,
- foundIndices0, ref foundIndices0Length, in weldFilter, in canonical, canonicalNodeOrder);
- }
- }
-
- // Find all vertices of brush0 that are inside brush1, and put their intersections into the appropriate loops
- if (foundIndices0Length > 0 &&
- brushPairIntersection0.usedVerticesLength > 0)
- {
- FindInsideVertices(brushPairIntersection0.usedVertices,
- brushPairIntersection0.usedVerticesLength,
- brushPairIntersection0.vertexIntersectionPlanes,
- brushPairIntersection0.vertexIntersectionPlanesLength,
- brushPairIntersection0.vertexIntersectionSegments,
- brushPairIntersection0.vertexIntersectionSegmentsLength,
- brushPairIntersection1.localSpacePlanes0,
- brushPairIntersection1.localSpacePlanes0Length,
- brushPairIntersection1.localSpacePlanesAndEdges0Length,
- brushPairIntersection0.nodeToTreeSpace,
- float4x4.identity,
- ref hashedTreeSpaceVertices,
- ref snapHashedVertices,
- foundIndices0, ref foundIndices0Length, in weldFilter, in canonical, canonicalNodeOrder);
- }
-
- // Find all vertices of brush1 that are inside brush0, and put their intersections into the appropriate loops
- if (foundIndices1Length > 0 &&
- brushPairIntersection1.usedVerticesLength > 0)
- {
- FindInsideVertices(brushPairIntersection1.usedVertices,
- brushPairIntersection1.usedVerticesLength,
- brushPairIntersection1.vertexIntersectionPlanes,
- brushPairIntersection1.vertexIntersectionPlanesLength,
- brushPairIntersection1.vertexIntersectionSegments,
- brushPairIntersection1.vertexIntersectionSegmentsLength,
- brushPairIntersection0.localSpacePlanes0,
- brushPairIntersection0.localSpacePlanes0Length,
- brushPairIntersection0.localSpacePlanesAndEdges0Length,
- brushPairIntersection0.nodeToTreeSpace,
- brushPairIntersection1.toOtherBrushSpace,
- ref hashedTreeSpaceVertices,
- ref snapHashedVertices,
- foundIndices1, ref foundIndices1Length, in weldFilter, in canonical, canonicalNodeOrder);
- }
-
-
- ref var brushTreeSpacePlanes0 = ref brushTreeSpacePlaneCache[brushIndexOrder0.nodeOrder].Value;
- ref var brushTreeSpacePlanes1 = ref brushTreeSpacePlaneCache[brushIndexOrder1.nodeOrder].Value;
-
- // Give a coplanar aligned face a loop to carry its category on; see the method comment.
- if (intersection.type == IntersectionType.Intersection &&
- treeSpaceVerticesCache[brushIndexOrder0.nodeOrder].IsCreated &&
- treeSpaceVerticesCache[brushIndexOrder1.nodeOrder].IsCreated &&
- brushTreeSpacePlaneCache[brushIndexOrder0.nodeOrder].IsCreated &&
- brushTreeSpacePlaneCache[brushIndexOrder1.nodeOrder].IsCreated)
- {
- AddFullSurfaceLoopsForAlignedFaces(
- ref treeSpaceVerticesCache[brushIndexOrder0.nodeOrder].Value.treeSpaceVertices,
- ref brushTreeSpacePlanes0, ref brushTreeSpacePlanes1,
- brushPairIntersection0.surfaceInfos, brushPairIntersection0.surfaceInfosLength,
- brushPairIntersection0.localSpacePlaneIndices0, brushPairIntersection0.localSpacePlaneIndices0Length,
- brushPairIntersection1.surfaceInfosLength,
- foundIndices0, ref foundIndices0Length,
- ref hashedTreeSpaceVertices, ref snapHashedVertices, in weldFilter, in canonical, canonicalNodeOrder);
-
- AddFullSurfaceLoopsForAlignedFaces(
- ref treeSpaceVerticesCache[brushIndexOrder1.nodeOrder].Value.treeSpaceVertices,
- ref brushTreeSpacePlanes1, ref brushTreeSpacePlanes0,
- brushPairIntersection1.surfaceInfos, brushPairIntersection1.surfaceInfosLength,
- brushPairIntersection1.localSpacePlaneIndices0, brushPairIntersection1.localSpacePlaneIndices0Length,
- brushPairIntersection0.surfaceInfosLength,
- foundIndices1, ref foundIndices1Length,
- ref hashedTreeSpaceVertices, ref snapHashedVertices, in weldFilter, in canonical, canonicalNodeOrder);
- }
-
- if (foundIndices0Length >= 3)
- {
- if (brushTreeSpacePlaneCache[brushIndexOrder0.nodeOrder].IsCreated)
- {
- var brushTransformations0 = brushPairIntersection0.nodeToTreeSpace;
- var invertedTransform = math.determinant(brushTransformations0) < 0;
-
- GenerateLoop(brushIndexOrder0,
- brushIndexOrder1,
- invertedTransform,
- brushPairIntersection0.surfaceInfos,
- brushPairIntersection0.surfaceInfosLength,
- ref brushTreeSpacePlanes0,
- foundIndices0, ref foundIndices0Length,
- ref hashedTreeSpaceVertices,
- outputSurfaces);
- } else
- {
- UnityEngine.Debug.LogError($"brushTreeSpacePlaneCache not initialized for brush with index {brushIndexOrder0.compactNodeID}");
- }
- }
-
- if (foundIndices1Length >= 3)
- {
- if (brushTreeSpacePlaneCache[brushIndexOrder1.nodeOrder].IsCreated)
- {
- var brushTransformations1 = brushPairIntersection1.nodeToTreeSpace;
- var invertedTransform = math.determinant(brushTransformations1) < 0;
-
- GenerateLoop(brushIndexOrder1,
- brushIndexOrder0,
- invertedTransform,
- brushPairIntersection1.surfaceInfos,
- brushPairIntersection1.surfaceInfosLength,
- ref brushTreeSpacePlanes1,
- foundIndices1,
- ref foundIndices1Length,
- ref hashedTreeSpaceVertices,
- outputSurfaces);
- } else
- {
- UnityEngine.Debug.LogError($"brushTreeSpacePlaneCache not initialized for brush with index {brushIndexOrder1.compactNodeID}");
- }
- }
- }
- }
-}
diff --git a/Core/2.Processing/Jobs/CreateIntersectionLoopsJob.cs.meta b/Core/2.Processing/Jobs/CreateIntersectionLoopsJob.cs.meta
deleted file mode 100644
index 1fa3f039..00000000
--- a/Core/2.Processing/Jobs/CreateIntersectionLoopsJob.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: 82d79b9244f8ea14581b8ea24149a243
-MonoImporter:
- externalObjects: {}
- serializedVersion: 2
- defaultReferences: []
- executionOrder: 0
- icon: {instanceID: 0}
- userData:
- assetBundleName:
- assetBundleVariant:
diff --git a/Core/2.Processing/Jobs/FindAllBrushIntersectionPairsJob.cs b/Core/2.Processing/Jobs/FindAllBrushIntersectionPairsJob.cs
index 0288597a..8d36a356 100644
--- a/Core/2.Processing/Jobs/FindAllBrushIntersectionPairsJob.cs
+++ b/Core/2.Processing/Jobs/FindAllBrushIntersectionPairsJob.cs
@@ -17,14 +17,11 @@ struct FindAllBrushIntersectionPairsJob : IJobParallelForDefer
{
// Read
[NoAlias, ReadOnly] public NativeList allTreeBrushIndexOrders;
- [NoAlias, ReadOnly] public NativeList transformationCache;
- [NoAlias, ReadOnly] public NativeArray> brushMeshLookup;
[NoAlias, ReadOnly] public NativeList brushTreeSpaceBounds;
[NoAlias, ReadOnly] public NativeList rebuildTreeBrushIndexOrders;
// Broad-phase over every brush in the tree (BuildBrushBoundsSweepJob): only brushes whose
// bounds can overlap this brush's are tested, instead of all of them.
[NoAlias, ReadOnly] public NativeList brushBoundsSweep;
- [NoAlias, ReadOnly] public bool exactCSG;
[NoAlias, ReadOnly] public NativeList> exactBrushCache;
// Read (Re-alloc) / Write
@@ -37,13 +34,11 @@ struct FindAllBrushIntersectionPairsJob : IJobParallelForDefer
IntersectionType Intersect(int brush0NodeOrder, int brush1NodeOrder)
{
- if (exactCSG)
- return IntersectionUtility.FindIntersectionExact(exactBrushCache[brush0NodeOrder], exactBrushCache[brush1NodeOrder]);
- return IntersectionUtility.FindIntersection(brush0NodeOrder, brush1NodeOrder, ref brushMeshLookup, ref brushTreeSpaceBounds, ref transformationCache);
+ return IntersectionUtility.FindIntersectionExact(exactBrushCache[brush0NodeOrder], exactBrushCache[brush1NodeOrder]);
}
- // How far apart bounds may be and still be tested: none for the exact CSG, whose bounds contain its exact corners
- double BoundsMargin => exactCSG ? 0 : IntersectionUtility.kBoundsDistanceEpsilon;
+ // Bounds contain the exact corners, so they are tested without a margin
+ const double BoundsMargin = 0;
// Per thread scratch memory
//[NativeDisableContainerSafetyRestriction] NativeArray transformedPlanes0;
@@ -196,12 +191,9 @@ struct FindAllIndirectBrushIntersectionPairsJob : IJobParallelForDefer
{
// Read
[NoAlias, ReadOnly] public NativeList allTreeBrushIndexOrders;
- [NoAlias, ReadOnly] public NativeList transformationCache;
- [NoAlias, ReadOnly] public NativeArray> brushMeshLookup;
[NoAlias, ReadOnly] public NativeList brushTreeSpaceBounds;
[NoAlias, ReadOnly] public NativeList brushesThatNeedIndirectUpdate;
[NoAlias, ReadOnly] public NativeList brushBoundsSweep;
- [NoAlias, ReadOnly] public bool exactCSG;
[NoAlias, ReadOnly] public NativeList> exactBrushCache;
// Read (Re-alloc) / Write
@@ -211,13 +203,11 @@ struct FindAllIndirectBrushIntersectionPairsJob : IJobParallelForDefer
IntersectionType Intersect(int brush0NodeOrder, int brush1NodeOrder)
{
- if (exactCSG)
- return IntersectionUtility.FindIntersectionExact(exactBrushCache[brush0NodeOrder], exactBrushCache[brush1NodeOrder]);
- return IntersectionUtility.FindIntersection(brush0NodeOrder, brush1NodeOrder, ref brushMeshLookup, ref brushTreeSpaceBounds, ref transformationCache);
+ return IntersectionUtility.FindIntersectionExact(exactBrushCache[brush0NodeOrder], exactBrushCache[brush1NodeOrder]);
}
- // How far apart bounds may be and still be tested: none for the exact CSG, whose bounds contain its exact corners
- double BoundsMargin => exactCSG ? 0 : IntersectionUtility.kBoundsDistanceEpsilon;
+ // Bounds contain the exact corners, so they are tested without a margin
+ const double BoundsMargin = 0;
// Per thread scratch memory
//[NativeDisableContainerSafetyRestriction] NativeArray transformedPlanes0;
@@ -535,9 +525,6 @@ public void Execute(int index)
sealed class IntersectionUtility
{
- public const double kBoundsDistanceEpsilon = CSGConstants.kBoundsDistanceEpsilon;
-
-
public struct IndexOrderComparer : System.Collections.Generic.IComparer
{
public int Compare(IndexOrder x, IndexOrder y)
@@ -546,151 +533,6 @@ public int Compare(IndexOrder x, IndexOrder y)
}
}
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void TransformOtherIntoBrushSpace([NoAlias, ReadOnly] ref float4x4 treeToBrushSpaceMatrix, [NoAlias, ReadOnly] ref float4x4 brushToTreeSpaceMatrix, [NoAlias, ReadOnly] ref BlobArray srcPlanes, [NoAlias, WriteOnly] NativeArray dstPlanes)
- {
- var brush1ToBrush0LocalLocalSpace = math.transpose(math.mul(treeToBrushSpaceMatrix, brushToTreeSpaceMatrix));
- for (int plane_index = 0; plane_index < srcPlanes.Length; plane_index++)
- {
- ref var srcPlane = ref srcPlanes[plane_index];
- dstPlanes[plane_index] = math.mul(brush1ToBrush0LocalLocalSpace, srcPlane);
- }
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static IntersectionType ConvexPolytopeTouching([NoAlias, ReadOnly] ref BrushMeshBlob brushMesh0,
- [NoAlias, ReadOnly] ref float4x4 treeToNode0SpaceMatrix,
- [NoAlias, ReadOnly] ref float4x4 nodeToTree0SpaceMatrix,
- [NoAlias, ReadOnly] ref BrushMeshBlob brushMesh1,
- [NoAlias, ReadOnly] ref float4x4 treeToNode1SpaceMatrix,
- [NoAlias, ReadOnly] ref float4x4 nodeToTree1SpaceMatrix//,
- //[NoAlias, ReadOnly] ref NativeArray transformedPlanes0,
- //[NoAlias, ReadOnly] ref NativeArray transformedPlanes1
- )
- {
- ref var brushPlanes0 = ref brushMesh0.localPlanes;
-
- NativeArray transformedPlanes0;
- using var _transformedPlanes0 = transformedPlanes0 = new NativeArray(brushPlanes0.Length, Allocator.Temp);
-
- //NativeCollectionHelpers.EnsureMinimumSize(ref transformedPlanes0, brushPlanes0.Length);
- TransformOtherIntoBrushSpace(ref treeToNode0SpaceMatrix, ref nodeToTree1SpaceMatrix, ref brushPlanes0, transformedPlanes0);
-
- ref var brushVertices1 = ref brushMesh1.localVertices;
- int negativeSides1 = 0;
- for (var i = 0; i < brushPlanes0.Length; i++)
- {
- var plane0 = transformedPlanes0[i];
- int side = WhichSide(ref brushVertices1, plane0, kBoundsDistanceEpsilon);
- if (side < 0) negativeSides1++;
- if (side > 0) return IntersectionType.NoIntersection;
- }
-
- //if (intersectingSides1 != transformedPlanes0.Length) return IntersectionType.Intersection;
- //if (intersectingSides > 0) return IntersectionType.Intersection;
- //if (positiveSides1 > 0) return IntersectionType.NoIntersection;
- //if (negativeSides > 0 && positiveSides > 0) return IntersectionType.Intersection;
- if (negativeSides1 == brushPlanes0.Length)
- return IntersectionType.BInsideA;
-
- ref var brushPlanes1 = ref brushMesh1.localPlanes;
- //*
-
- NativeArray transformedPlanes1;
- using var _transformedPlanes1 = transformedPlanes1 = new NativeArray(brushPlanes1.Length, Allocator.Temp);
-
- //NativeCollectionHelpers.EnsureMinimumSize(ref transformedPlanes1, brushPlanes1.Length);
- TransformOtherIntoBrushSpace(ref treeToNode1SpaceMatrix, ref nodeToTree0SpaceMatrix, ref brushPlanes1, transformedPlanes1);
-
-
- ref var brushVertices0 = ref brushMesh0.localVertices;
- int negativeSides2 = 0;
- int intersectingSides2 = 0;
- for (var i = 0; i < brushPlanes1.Length; i++)
- {
- var plane1 = transformedPlanes1[i];
- int side = WhichSide(ref brushVertices0, plane1, kBoundsDistanceEpsilon);
- if (side < 0) negativeSides2++;
- if (side > 0) return IntersectionType.NoIntersection;
- if (side == 0) intersectingSides2++;
- }
-
- if (intersectingSides2 > 0) return IntersectionType.Intersection;
- //if (negativeSides > 0 && positiveSides > 0) return IntersectionType.Intersection;
- if (negativeSides2 == brushPlanes1.Length)
- return IntersectionType.AInsideB;
-
- return IntersectionType.Intersection;//*/
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- static int WhichSide([NoAlias,ReadOnly] ref BlobArray vertices, float4 plane, double epsilon)
- {
- {
- var t = math.dot(plane, new float4(vertices[0], 1));
- if (t >= epsilon) goto HavePositive;
- if (t <= -epsilon) goto HaveNegative;
- return 0;
- }
- HaveNegative:
- for (var i = 1; i < vertices.Length; i++)
- {
- var t = math.dot(plane, new float4(vertices[i], 1));
- if (t > -epsilon)
- return 0;
- }
- return -1;
- HavePositive:
- for (var i = 1; i < vertices.Length; i++)
- {
- var t = math.dot(plane, new float4(vertices[i], 1));
- if (t < epsilon)
- return 0;
- }
- return 1;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static IntersectionType FindIntersection(int brush0NodeOrder, int brush1NodeOrder,
- [NoAlias, ReadOnly] ref NativeArray> brushMeshLookup,
- [NoAlias, ReadOnly] ref NativeList brushTreeSpaceBounds,
- [NoAlias, ReadOnly] ref NativeList transformations//,
- //[NoAlias, ReadOnly] ref NativeArray transformedPlanes0,
- //[NoAlias, ReadOnly] ref NativeArray transformedPlanes1
- )
- {
- var brushMesh0 = brushMeshLookup[brush0NodeOrder];
- var brushMesh1 = brushMeshLookup[brush1NodeOrder];
- if (!brushMesh0.IsCreated || !brushMesh1.IsCreated)
- return IntersectionType.NoIntersection;
-
- var bounds0 = brushTreeSpaceBounds[brush0NodeOrder];
- var bounds1 = brushTreeSpaceBounds[brush1NodeOrder];
-
- if (!bounds0.Intersects(bounds1, IntersectionUtility.kBoundsDistanceEpsilon))
- return IntersectionType.NoIntersection;
-
- var transformation0 = transformations[brush0NodeOrder];
- var transformation1 = transformations[brush1NodeOrder];
-
- var treeToNode0SpaceMatrix = transformation0.treeToNode;
- var nodeToTree0SpaceMatrix = transformation0.nodeToTree;
- var treeToNode1SpaceMatrix = transformation1.treeToNode;
- var nodeToTree1SpaceMatrix = transformation1.nodeToTree;
-
- var result = IntersectionUtility.ConvexPolytopeTouching(ref brushMesh0.Value,
- ref treeToNode0SpaceMatrix,
- ref nodeToTree0SpaceMatrix,
- ref brushMesh1.Value,
- ref treeToNode1SpaceMatrix,
- ref nodeToTree1SpaceMatrix//,
- //ref transformedPlanes0,
- //ref transformedPlanes1
- );
-
- return result;
- }
-
public static IntersectionType FindIntersectionExact(BlobAssetReference brush0, BlobAssetReference brush1)
{
if (!brush0.IsCreated || !brush1.IsCreated)
diff --git a/Core/2.Processing/Jobs/FindBrushPairsJob.cs b/Core/2.Processing/Jobs/FindBrushPairsJob.cs
deleted file mode 100644
index 5433e238..00000000
--- a/Core/2.Processing/Jobs/FindBrushPairsJob.cs
+++ /dev/null
@@ -1,99 +0,0 @@
-using System;
-using Unity.Burst;
-using Unity.Collections;
-using Unity.Jobs;
-using Unity.Collections.LowLevel.Unsafe;
-using Debug = UnityEngine.Debug;
-using ReadOnlyAttribute = Unity.Collections.ReadOnlyAttribute;
-using WriteOnlyAttribute = Unity.Collections.WriteOnlyAttribute;
-using Unity.Entities;
-
-namespace Chisel.Core
-{
- [BurstCompile(CompileSynchronously = true)]
- struct FindBrushPairsJob : IJob
- {
- // Read
- [NoAlias, ReadOnly] public int maxOrder;
- [NoAlias, ReadOnly] public NativeList allUpdateBrushIndexOrders;
- [NoAlias, ReadOnly] public NativeList> brushesTouchedByBrushes;
-
- // Read (Re-allocate) / Write
- [NoAlias] public NativeList uniqueBrushPairs;
-
- // Per thread scratch memory
- //[NativeDisableContainerSafetyRestriction] NativeBitArray usedLookup;
-
- public void Execute()
- {
- var maxPairs = (maxOrder * maxOrder);
-
- NativeBitArray usedLookup;
- using var _usedLookup = usedLookup = new NativeBitArray(maxPairs, Allocator.Temp);
- //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 == BlobAssetReference.Null)
- continue;
-
- ref var intersections = ref brushesTouchedByBrush.Value.brushIntersections;
- if (intersections.Length == 0)
- continue;
-
- requiredCapacity += intersections.Length + 1;
- }
-
- if (uniqueBrushPairs.Capacity < requiredCapacity + 1)
- uniqueBrushPairs.Capacity = requiredCapacity + 1;
- // Workaround for the incredibly dumb "can't create a stream that is zero sized" when the value is determined at runtime. Yeah, thanks
- uniqueBrushPairs.AddNoResize(new BrushPair2 { type = IntersectionType.InvalidValue });
-
- for (int b0 = 0; b0 < allUpdateBrushIndexOrders.Length; b0++)
- {
- var brushIndexOrder0 = allUpdateBrushIndexOrders[b0];
- int brushNodeOrder0 = brushIndexOrder0.nodeOrder;
-
- var brushesTouchedByBrush = brushesTouchedByBrushes[brushNodeOrder0];
- if (brushesTouchedByBrush == BlobAssetReference.Null)
- continue;
-
- ref var intersections = ref brushesTouchedByBrush.Value.brushIntersections;
- if (intersections.Length == 0)
- continue;
-
- // 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);
- }
- }
- }
- }
- }
-}
diff --git a/Core/2.Processing/Jobs/FindBrushPairsJob.cs.meta b/Core/2.Processing/Jobs/FindBrushPairsJob.cs.meta
deleted file mode 100644
index 8ac69baf..00000000
--- a/Core/2.Processing/Jobs/FindBrushPairsJob.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: 38ac1a09e7e8d9f44970a7abd9739d73
-MonoImporter:
- externalObjects: {}
- serializedVersion: 2
- defaultReferences: []
- executionOrder: 0
- icon: {instanceID: 0}
- userData:
- assetBundleName:
- assetBundleVariant:
diff --git a/Core/2.Processing/Jobs/FindLoopOverlapIntersectionJob.cs b/Core/2.Processing/Jobs/FindLoopOverlapIntersectionJob.cs
deleted file mode 100644
index f683c667..00000000
--- a/Core/2.Processing/Jobs/FindLoopOverlapIntersectionJob.cs
+++ /dev/null
@@ -1,1035 +0,0 @@
-using System;
-using Unity.Burst;
-using Unity.Collections;
-using Unity.Jobs;
-using Unity.Mathematics;
-using Unity.Collections.LowLevel.Unsafe;
-using Debug = UnityEngine.Debug;
-using ReadOnlyAttribute = Unity.Collections.ReadOnlyAttribute;
-using WriteOnlyAttribute = Unity.Collections.WriteOnlyAttribute;
-using Unity.Entities;
-
-namespace Chisel.Core
-{
-
- [BurstCompile(CompileSynchronously = true)]
- struct FindLoopOverlapIntersectionsJob : IJobParallelForDefer
- {
- public const int kMaxVertexCount = short.MaxValue;
- const float kSqrVertexEqualEpsilon = CSGConstants.kSqrVertexEqualEpsilon;
- const float kFatPlaneWidthEpsilon = CSGConstants.kFatPlaneWidthEpsilon;
-
- // Set false to skip the base-polygon T-junction split.
- const bool kSplitBasePolygonsAtIntersectionVertices = true;
-
- // Gate the vertex weld on plane incidence (WeldIncidenceFilter); set from CSGManager's kUseIncidenceWeld.
- [NoAlias, ReadOnly] public bool useIncidenceWeld;
-
- // Canonical vertices (see CanonicalVertices)
- [NoAlias, ReadOnly] public CanonicalVertexStage canonicalVertexStage;
- [NoAlias, ReadOnly] public NativeList> brushesTouchedByBrushCache;
-
- // Read
- [NoAlias, ReadOnly] public NativeList allUpdateBrushIndexOrders;
- [NoAlias, ReadOnly] public NativeList outputSurfaceVertices;
- [NoAlias, ReadOnly] public NativeList outputSurfaces;
- [NoAlias, ReadOnly] public NativeArray outputSurfacesRange;
- [NoAlias, ReadOnly] public int maxNodeOrder;
- [NoAlias, ReadOnly] public NativeList> basePolygonCache;
- [NoAlias, ReadOnly] public NativeList> brushTreeSpacePlaneCache;
-
- // Read Write
- public Allocator allocator;
- [NativeDisableParallelForRestriction]
- [NoAlias] public NativeArray> loopVerticesLookup;
-
- // Write
- [NativeDisableParallelForRestriction]
- [NoAlias, WriteOnly] public NativeStream.Writer output;
-
- // Per thread scratch memory
- //[NativeDisableContainerSafetyRestriction] NativeArray newSelfEdges;
- //[NativeDisableContainerSafetyRestriction] NativeArray srcIndices;
- //[NativeDisableContainerSafetyRestriction] NativeArray basePolygonSurfaceInfos;
- //[NativeDisableContainerSafetyRestriction] NativeList tempList;
- //[NativeDisableContainerSafetyRestriction] NativeList brushIntersections;
- //[NativeDisableContainerSafetyRestriction] NativeList intersectionSurfaceInfos;
- //[NativeDisableContainerSafetyRestriction] NativeList> basePolygonEdges;
- //[NativeDisableContainerSafetyRestriction] NativeList> intersectionEdges;
- //[NativeDisableContainerSafetyRestriction] NativeBitArray usedNodeOrders;
- //[NativeDisableContainerSafetyRestriction] HashedVertices hashedTreeSpaceVertices;
- //[NativeDisableContainerSafetyRestriction] NativeArray intersectionSurfaceSegments;
- //[NativeDisableContainerSafetyRestriction] NativeArray otherVertices;
-
- struct CompareSortByBasePlaneIndex : System.Collections.Generic.IComparer
- {
- public readonly int Compare(BrushIntersectionLoop x, BrushIntersectionLoop y)
- {
- var diff = x.surfaceInfo.basePlaneIndex - y.surfaceInfo.basePlaneIndex;
- if (diff != 0)
- return diff;
-
- return x.indexOrder1.nodeOrder - y.indexOrder1.nodeOrder;
- }
- }
-
- readonly static CompareSortByBasePlaneIndex kCompareSortByBasePlaneIndex = new CompareSortByBasePlaneIndex();
-
- // The faces of this brush and of the brush it is being cut by are what identify the vertices here.
- WeldIncidenceFilter CreateWeldFilter(int selfNodeOrder, int otherNodeOrder)
- {
- // Canonical vertices: a vertex computed twice has the same bits, so only the same position is the same vertex.
- if (canonicalVertexStage >= CanonicalVertexStage.LoopIdentity &&
- CanonicalVertices.IsAvailable(canonicalVertexStage, brushTreeSpacePlaneCache, brushesTouchedByBrushCache))
- return WeldIncidenceFilter.SameVertexOnly;
- if (!useIncidenceWeld ||
- !brushTreeSpacePlaneCache[selfNodeOrder].IsCreated || !basePolygonCache[selfNodeOrder].IsCreated ||
- !brushTreeSpacePlaneCache[otherNodeOrder].IsCreated || !basePolygonCache[otherNodeOrder].IsCreated)
- return WeldIncidenceFilter.Disabled;
- return WeldIncidenceFilter.Create(ref brushTreeSpacePlaneCache[selfNodeOrder].Value.treeSpacePlanes, basePolygonCache[selfNodeOrder].Value.polygons.Length,
- ref brushTreeSpacePlaneCache[otherNodeOrder].Value.treeSpacePlanes, basePolygonCache[otherNodeOrder].Value.polygons.Length);
- }
-
- void CopyFrom(NativeList> dst, int index, ref BrushIntersectionLoop brushIntersectionLoop, HashedVertices hashedTreeSpaceVertices, int extraCapacity, in WeldIncidenceFilter weldFilter)
- {
- Debug.Assert(extraCapacity >= 0);
- ref var vertexIndex = ref brushIntersectionLoop.loopVertexIndex;
- ref var loopVertexCount = ref brushIntersectionLoop.loopVertexCount;
-
- NativeArray srcIndices;
- using var _srcIndices = srcIndices = new NativeArray(loopVertexCount, Allocator.Temp);
- //NativeCollectionHelpers.EnsureMinimumSize(ref srcIndices, loopVertexCount);
-
- hashedTreeSpaceVertices.ReserveAdditionalVertices(loopVertexCount);
- for (int j = 0; j < loopVertexCount; j++)
- srcIndices[j] = hashedTreeSpaceVertices.AddNoResize(outputSurfaceVertices[vertexIndex + j], in weldFilter);
-
- var dstEdges = new UnsafeList(loopVertexCount + extraCapacity, Allocator.Temp);
- for (int j = 1; j < loopVertexCount; j++)
- {
- dstEdges.AddNoResize(new Edge { index1 = srcIndices[j - 1], index2 = srcIndices[j] });
- }
- dstEdges.AddNoResize(new Edge { index1 = srcIndices[loopVertexCount - 1], index2 = srcIndices[0] });
-
- dst[index] = dstEdges;
- }
-
-
- public void Execute(int index)
- {
- var brushIndexOrder = allUpdateBrushIndexOrders[index];
- int brushNodeOrder = brushIndexOrder.nodeOrder;
-
- // Can happen when BrushMeshes are not initialized correctly
- if (basePolygonCache[brushNodeOrder] == BlobAssetReference.Null)
- {
- loopVerticesLookup[brushIndexOrder.nodeOrder] = new UnsafeList(16, allocator);
- output.BeginForEachIndex(index);
- output.Write(brushIndexOrder);
- output.Write(0);
- output.Write(0);
- output.Write(0);
- output.EndForEachIndex();
- return;
- }
-
- ref var basePolygonBlob = ref basePolygonCache[brushNodeOrder].Value;
- var surfaceCount = basePolygonBlob.polygons.Length;
- if (surfaceCount == 0)
- {
- loopVerticesLookup[brushIndexOrder.nodeOrder] = new UnsafeList(16, allocator);
- output.BeginForEachIndex(index);
- output.Write(brushIndexOrder);
- output.Write(0);
- output.Write(0);
- output.Write(0);
- output.EndForEachIndex();
- return;
- }
-
- HashedVertices hashedTreeSpaceVertices;
- using var _hashedTreeSpaceVertices = hashedTreeSpaceVertices = new HashedVertices(HashedVertices.kMaxVertexCount, Allocator.Temp);
- //NativeCollectionHelpers.EnsureCapacityAndClear(ref hashedTreeSpaceVertices, HashedVertices.kMaxVertexCount);
-
- NativeArray basePolygonSurfaceInfos;
- using var _basePolygonSurfaceInfos = basePolygonSurfaceInfos = new NativeArray(surfaceCount, Allocator.Temp);
- //NativeCollectionHelpers.EnsureMinimumSize(ref basePolygonSurfaceInfos, surfaceCount);
- NativeList> basePolygonEdges;
- using var _basePolygonEdges = basePolygonEdges = new NativeList>(surfaceCount, Allocator.Temp);
- basePolygonEdges.Resize(surfaceCount, NativeArrayOptions.ClearMemory);
- //NativeCollectionHelpers.EnsureSizeAndClear(ref basePolygonEdges, surfaceCount);
- try
- {
-
-
- var intersectionOffset = outputSurfacesRange[brushNodeOrder].x;
- var intersectionCount = outputSurfacesRange[brushNodeOrder].y;
-
- hashedTreeSpaceVertices.AddUniqueVertices(ref basePolygonBlob.vertices); /*OUTPUT*/
-
- if (intersectionCount == 0)
- {
- // If we don't have any intersection loops, just convert basePolygonBlob to loops and be done
- // TODO: should do this per surface!
-
- for (int s = 0; s < basePolygonBlob.polygons.Length; s++)
- {
- ref var input = ref basePolygonBlob.polygons[s];
-
- ref var nodeIndexOrder = ref basePolygonBlob.polygons[s].nodeIndexOrder;
- ref var surfaceInfo = ref basePolygonBlob.polygons[s].surfaceInfo;
- basePolygonSurfaceInfos[s] = new IndexSurfaceInfo
- {
- brushIndexOrder = nodeIndexOrder,
- interiorCategory = surfaceInfo.interiorCategory,
- basePlaneIndex = surfaceInfo.basePlaneIndex
- };
-
- if (input.endEdgeIndex == input.startEdgeIndex)
- continue;
-
- var edges = new UnsafeList(input.endEdgeIndex - input.startEdgeIndex, Allocator.Temp);
- for (int e = input.startEdgeIndex; e < input.endEdgeIndex; e++)
- edges.AddNoResize(basePolygonBlob.edges[e]);
- basePolygonEdges[s] = edges;
- }
-
- //if (intersectionEdges.IsCreated)
- // intersectionEdges.Clear();
-
- //if (intersectionSurfaceInfos.IsCreated)
- // intersectionSurfaceInfos.Clear();
-
- var writeVertices = new UnsafeList(hashedTreeSpaceVertices.Length, allocator);
- writeVertices.Resize(hashedTreeSpaceVertices.Length,
- NativeArrayOptions.ClearMemory);
- //NativeArrayOptions.UninitializedMemory);
- for (int l = 0; l < hashedTreeSpaceVertices.Length; l++)
- writeVertices[l] = hashedTreeSpaceVertices[l];
- loopVerticesLookup[brushIndexOrder.nodeOrder] = writeVertices;
-
- output.BeginForEachIndex(index);
- output.Write(brushIndexOrder);
- output.Write(surfaceCount);
-
- output.Write(basePolygonEdges.Length);
- for (int l = 0; l < basePolygonEdges.Length; l++)
- {
- output.Write(basePolygonSurfaceInfos[l]);
- if (!basePolygonEdges[l].IsCreated)
- {
- output.Write(0);
- continue;
- }
- var edges = basePolygonEdges[l];
- output.Write(edges.Length);
- for (int e = 0; e < edges.Length; e++)
- output.Write(edges[e]);
- }
-
- output.Write(0);
- output.EndForEachIndex();
- }
- else
- {
- // Canonical vertices: every split point lies on this brush, so its key is gathered here.
- var canonical = CanonicalVertices.Create(canonicalVertexStage, brushTreeSpacePlaneCache, brushesTouchedByBrushCache);
-
- NativeList brushIntersections;
- using var _brushIntersections = brushIntersections = new NativeList(intersectionCount, Allocator.Temp);
- //NativeCollectionHelpers.EnsureCapacityAndClear(ref brushIntersections, intersectionCount);
-
- NativeBitArray usedNodeOrders;
- using var _usedNodeOrders = usedNodeOrders = new NativeBitArray(maxNodeOrder, Allocator.Temp);
- //NativeCollectionHelpers.EnsureMinimumSizeAndClear(ref usedNodeOrders, maxNodeOrder);
-
- var lastIntersectionIndex = intersectionCount + intersectionOffset;
- for (int i = intersectionOffset; i < lastIntersectionIndex; i++)
- {
- var item = outputSurfaces[i];
- var otherNodeOrder1 = item.indexOrder1.nodeOrder;
-
- usedNodeOrders.Set(otherNodeOrder1, true);
-
- //Debug.Assert(outputSurface.surfaceInfo.brushIndex == pair.brushNodeIndex1);
- //Debug.Assert(outputSurface.surfaceInfo.basePlaneIndex == pair.basePlaneIndex);
-
- brushIntersections.AddNoResize(item);
- }
- brushIntersections.Sort(kCompareSortByBasePlaneIndex);
-
- NativeList> intersectionEdges;
- using var _intersectionEdges = intersectionEdges = new NativeList>(brushIntersections.Length, Allocator.Temp);
- intersectionEdges.Resize(brushIntersections.Length, NativeArrayOptions.ClearMemory);
- //NativeCollectionHelpers.EnsureSizeAndClear(ref intersectionEdges, brushIntersections.Length);
-
- NativeArray intersectionSurfaceSegments;
- using var _intersectionSurfaceSegments = intersectionSurfaceSegments = new NativeArray(surfaceCount + 1, Allocator.Temp);
- //NativeCollectionHelpers.EnsureMinimumSize(ref intersectionSurfaceSegments, surfaceCount + 1);
-
- NativeList intersectionSurfaceInfos;
- using var _intersectionSurfaceInfos = intersectionSurfaceInfos = new NativeList(brushIntersections.Length, Allocator.Temp);
- //NativeCollectionHelpers.EnsureCapacityAndClear(ref intersectionSurfaceInfos, brushIntersections.Length);
- try
- {
- {
- for (int s = 0; s < basePolygonBlob.polygons.Length; s++)
- {
- ref var input = ref basePolygonBlob.polygons[s];
-
- ref var surfaceInfo = ref basePolygonBlob.polygons[s].surfaceInfo;
- ref var nodeIndexOrder = ref basePolygonBlob.polygons[s].nodeIndexOrder;
- basePolygonSurfaceInfos[s] = new IndexSurfaceInfo
- {
- brushIndexOrder = nodeIndexOrder,
- interiorCategory = surfaceInfo.interiorCategory,
- basePlaneIndex = surfaceInfo.basePlaneIndex
- };
-
- if (input.endEdgeIndex == input.startEdgeIndex)
- continue;
-
- var edges = new UnsafeList((input.endEdgeIndex - input.startEdgeIndex) + (brushIntersections.Length * 4), Allocator.Temp);
- for (int e = input.startEdgeIndex; e < input.endEdgeIndex; e++)
- edges.AddNoResize(basePolygonBlob.edges[e]);
- basePolygonEdges[s] = edges;
- }
-
-
- int prevBasePlaneIndex = 0;
- int startIndex = 0;
- for (int l = 0; l < brushIntersections.Length; l++)
- {
- var brushIntersectionLoop = brushIntersections[l];
- ref var surfaceInfo = ref brushIntersectionLoop.surfaceInfo;
- //UnityEngine.Debug.Assert(brushIntersectionLoop.indexOrder0.compactNodeID == brushIndexOrder.compactNodeID);
- UnityEngine.Debug.Assert(brushIntersectionLoop.indexOrder0.nodeOrder == brushIndexOrder.nodeOrder);
-
- var basePlaneIndex = surfaceInfo.basePlaneIndex;
- if (prevBasePlaneIndex != basePlaneIndex)
- {
- intersectionSurfaceSegments[prevBasePlaneIndex] = new int2(startIndex, l - startIndex);
- startIndex = l;
- for (int s = prevBasePlaneIndex + 1; s < basePlaneIndex; s++)
- intersectionSurfaceSegments[s] = new int2(startIndex, 0);
- prevBasePlaneIndex = basePlaneIndex;
- }
- CopyFrom(intersectionEdges, l, ref brushIntersectionLoop, hashedTreeSpaceVertices, brushIntersections.Length * 4,
- CreateWeldFilter(brushNodeOrder, brushIntersectionLoop.indexOrder1.nodeOrder));
- }
-
- intersectionSurfaceSegments[prevBasePlaneIndex] = new int2(startIndex, brushIntersections.Length - startIndex);
- startIndex = brushIntersections.Length;
- for (int s = prevBasePlaneIndex + 1; s < surfaceCount; s++)
- intersectionSurfaceSegments[s] = new int2(startIndex, 0);
-
-
- for (int s = 0; s < surfaceCount; s++)
- {
- var intersectionSurfaceCount = intersectionSurfaceSegments[s].y;
- var intersectionSurfaceOffset = intersectionSurfaceSegments[s].x;
- for (int l0 = intersectionSurfaceCount - 1; l0 >= 0; l0--)
- {
- //int intersectionBrushOrder0 = brushIntersections[intersectionSurfaceOffset + l0].indexOrder1.nodeOrder;
- var edges = intersectionEdges[intersectionSurfaceOffset + l0];
- for (int l1 = 0; l1 < intersectionSurfaceCount; l1++)
- {
- if (l0 == l1)
- continue;
-
- int intersectionBrushOrder1 = brushIntersections[intersectionSurfaceOffset + l1].indexOrder1.nodeOrder;// intersectionIndex1.w;
-
- FindLoopPlaneIntersections(brushTreeSpacePlaneCache.AsArray(),
- CreateWeldFilter(brushNodeOrder, intersectionBrushOrder1),
- intersectionBrushOrder1,
- //intersectionBrushOrder0,
- hashedTreeSpaceVertices, ref edges,
- in canonical, brushNodeOrder);
-
- // TODO: merge these so that intersections will be identical on both loops (without using math, use logic)
- // TODO: make sure that intersections between loops will be identical on OTHER brushes (without using math, use logic)
- }
-
- intersectionEdges[intersectionSurfaceOffset + l0] = edges;
- }
- }
-
- ref var selfPlanes = ref brushTreeSpacePlaneCache[brushIndexOrder.nodeOrder].Value.treeSpacePlanes;
-
- // TODO: should only intersect with all brushes that each particular basepolygon intersects with
- // but also need adjency information between basePolygons to ensure that intersections exist on
- // both sides of each edge on a brush.
- for (int otherBrushNodeOrder = 0; otherBrushNodeOrder < maxNodeOrder; otherBrushNodeOrder++)
- {
- if (!usedNodeOrders.IsSet(otherBrushNodeOrder) ||
- otherBrushNodeOrder == brushNodeOrder)
- continue;
-
- ref var otherPlanes = ref brushTreeSpacePlaneCache[otherBrushNodeOrder].Value.treeSpacePlanes;
- for (int b = 0; b < basePolygonEdges.Length; b++)
- {
- if (!basePolygonEdges[b].IsCreated)
- continue;
- var selfEdges = basePolygonEdges[b];
- //var before = selfEdges.Length;
-
- FindBasePolygonPlaneIntersections(ref otherPlanes, //ref selfPlanes,
- CreateWeldFilter(brushNodeOrder, otherBrushNodeOrder),
- ref selfEdges, hashedTreeSpaceVertices,
- in canonical, brushNodeOrder);
- basePolygonEdges[b] = selfEdges;
- }
- }
-
- for (int s = 0; s < surfaceCount; s++)
- {
- var intersectionSurfaceCount = intersectionSurfaceSegments[s].y;
- var intersectionSurfaceOffset = intersectionSurfaceSegments[s].x;
- if (intersectionSurfaceCount == 0)
- continue;
-
- if (!basePolygonEdges[s].IsCreated)
- continue;
-
- var bp_edges = basePolygonEdges[s];
- for (int l0 = 0; l0 < intersectionSurfaceCount; l0++)
- {
- int intersectionBrushOrder = brushIntersections[intersectionSurfaceOffset + l0].indexOrder1.nodeOrder;// intersectionIndex.w;
- var in_edges = intersectionEdges[intersectionSurfaceOffset + l0];
-
- ref var otherPlanes = ref brushTreeSpacePlaneCache[intersectionBrushOrder].Value.treeSpacePlanes;
-
- FindLoopVertexOverlaps(ref selfPlanes, ref in_edges, bp_edges, hashedTreeSpaceVertices);
- intersectionEdges[intersectionSurfaceOffset + l0] = in_edges;
-
- // TODO: The following call, strictly speaking, is unncessary, but it'll hide bugs in other parts of the pipeline.
- // it'll add missing vertices on overlapping loops, but they will be missing on touching surfaces, so there will be gaps.
- // the alternative is that this surface could possible fail to triangulate and be completely missing .. (larger gap)
- // Somehow it can also cause artifacts sometimes???
- //FindLoopVertexOverlaps(ref otherPlanes, ref bp_edges, in_edges, hashedTreeSpaceVertices);
- }
- }
-
- if (kSplitBasePolygonsAtIntersectionVertices)
- {
- var splitVertexCount = hashedTreeSpaceVertices.Length;
-
- // Mark which vertices belong to any intersection loop.
- var isIntersectionVertex = new NativeArray(splitVertexCount, Allocator.Temp);
- for (int i = 0; i < intersectionEdges.Length; i++)
- {
- if (!intersectionEdges[i].IsCreated)
- continue;
- var ie = intersectionEdges[i];
- for (int e = 0; e < ie.Length; e++)
- {
- isIntersectionVertex[ie[e].index1] = true;
- isIntersectionVertex[ie[e].index2] = true;
- }
- }
-
- var candidateCount = 0;
- for (int v = 0; v < splitVertexCount; v++)
- if (isIntersectionVertex[v]) candidateCount++;
-
- if (candidateCount > 0)
- {
- var splitPositions = new NativeArray(splitVertexCount, Allocator.Temp);
- for (int v = 0; v < splitVertexCount; v++)
- splitPositions[v] = hashedTreeSpaceVertices[v];
-
- var splitCandidates = new NativeArray(candidateCount, Allocator.Temp);
- var k = 0;
- for (int v = 0; v < splitVertexCount; v++)
- if (isIntersectionVertex[v]) splitCandidates[k++] = (ushort)v;
-
- for (int b = 0; b < basePolygonEdges.Length; b++)
- {
- if (!basePolygonEdges[b].IsCreated)
- continue;
- var splitEdges = basePolygonEdges[b];
- LoopEdgeSplitter.SplitEdgesAtVertices(ref splitEdges, in splitPositions, in splitCandidates, candidateCount, CSGConstants.kSqrEdgeDistanceEpsilon);
- basePolygonEdges[b] = splitEdges;
- }
-
- splitPositions.Dispose();
- splitCandidates.Dispose();
- }
- isIntersectionVertex.Dispose();
- }
-
- for (int i = 0; i < intersectionEdges.Length; i++)
- {
- // TODO: might not be necessary
- var edges = intersectionEdges[i];
- RemoveDuplicates(ref edges);
- intersectionEdges[i] = edges;
- }
-
- for (int i = 0; i < basePolygonEdges.Length; i++)
- {
- if (!basePolygonEdges[i].IsCreated)
- continue;
- // TODO: might not be necessary
- var edges = basePolygonEdges[i];
- RemoveDuplicates(ref edges);
- basePolygonEdges[i] = edges;
- }
-
-
- // TODO: merge indices across multiple loops when vertices are identical
- }
-
-
-
- for (int k = 0; k < brushIntersections.Length; k++)
- {
- var intersection = brushIntersections[k];
- ref var surfaceInfo = ref intersection.surfaceInfo;
- intersectionSurfaceInfos.AddNoResize(
- new IndexSurfaceInfo
- {
- brushIndexOrder = intersection.indexOrder1,
- interiorCategory = surfaceInfo.interiorCategory,
- basePlaneIndex = surfaceInfo.basePlaneIndex
- }); //OUTPUT
- }
-
- var writeVertices = new UnsafeList(hashedTreeSpaceVertices.Length, allocator);
- writeVertices.Resize(hashedTreeSpaceVertices.Length,
- NativeArrayOptions.ClearMemory);
- //NativeArrayOptions.UninitializedMemory);
- for (int l = 0; l < hashedTreeSpaceVertices.Length; l++)
- writeVertices[l] = hashedTreeSpaceVertices[l];
- loopVerticesLookup[brushIndexOrder.nodeOrder] = writeVertices;
-
- output.BeginForEachIndex(index);
- output.Write(brushIndexOrder);
- output.Write(surfaceCount);
-
- output.Write(basePolygonEdges.Length);
- for (int l = 0; l < basePolygonEdges.Length; l++)
- {
- output.Write(basePolygonSurfaceInfos[l]);
- if (!basePolygonEdges[l].IsCreated)
- {
- output.Write(0);
- continue;
- }
- var edges = basePolygonEdges[l];
- output.Write(edges.Length);
- for (int e = 0; e < edges.Length; e++)
- output.Write(edges[e]);
- }
-
- output.Write(intersectionEdges.Length);
- for (int l = 0; l < intersectionEdges.Length; l++)
- {
- output.Write(intersectionSurfaceInfos[l]);
- var edges = intersectionEdges[l];
- output.Write(edges.Length);
- for (int e = 0; e < edges.Length; e++)
- output.Write(edges[e]);
- }
- output.EndForEachIndex();
- }
- finally
- {
- if (intersectionEdges.IsCreated)
- {
- for (int i = 0; i < intersectionEdges.Length; i++)
- {
- if (intersectionEdges[i].IsCreated)
- intersectionEdges[i].Dispose();
- intersectionEdges[i] = default;
- }
- }
- }
- }
- }
- finally
- {
- if (basePolygonEdges.IsCreated)
- {
- for (int i = 0; i < basePolygonEdges.Length; i++)
- {
- if (basePolygonEdges[i].IsCreated)
- basePolygonEdges[i].Dispose();
- basePolygonEdges[i] = default;
- }
- }
- }
- }
-
- public void FindLoopPlaneIntersections(NativeArray> brushTreeSpacePlanes,
- in WeldIncidenceFilter weldFilter,
- int intersectionBrushOrder1, //int intersectionBrushOrder0,
- HashedVertices hashedTreeSpaceVertices,
- ref UnsafeList edges,
- in CanonicalVertices canonical = default,
- int canonicalNodeOrder = -1)
- {
- if (edges.Length < 3)
- return;
-
- var inputEdgesLength = edges.Length;
-
- NativeArray newSelfEdges;
- using var _newSelfEdges = newSelfEdges = new (inputEdgesLength, Allocator.Temp);
- //NativeCollectionHelpers.EnsureMinimumSize(ref newSelfEdges, inputEdgesLength);
-
- newSelfEdges.CopyFrom(edges, 0, edges.Length);
- edges.Clear();
-
- int4 tempVertices = int4.zero;
-
- ref var otherPlanes = ref brushTreeSpacePlanes[intersectionBrushOrder1].Value.treeSpacePlanes;
- //ref var selfPlanes = ref brushTreeSpacePlanes[intersectionBrushOrder0].Value.treeSpacePlanes;
-
- var otherPlaneCount = otherPlanes.Length;
- //var selfPlaneCount = selfPlanes.Length;
-
- hashedTreeSpaceVertices.ReserveAdditionalVertices(inputEdgesLength * 2);
-
- // TODO: Optimize the hell out of this
- for (int e = 0; e < inputEdgesLength; e++)
- {
- var vertexIndex0 = newSelfEdges[e].index1;
- var vertexIndex1 = newSelfEdges[e].index2;
-
- var vertex0 = hashedTreeSpaceVertices[vertexIndex0];
- var vertex1 = hashedTreeSpaceVertices[vertexIndex1];
-
- var vertex0w = new float4(vertex0, 1);
- var vertex1w = new float4(vertex1, 1);
-
- var foundVertices = 0;
-
- for (int p = 0; p < otherPlaneCount; p++)
- {
- var otherPlane = otherPlanes[p];
-
- var distance0 = math.dot(otherPlane, vertex0w);
- var distance1 = math.dot(otherPlane, vertex1w);
-
- if (distance0 < 0)
- {
- if (distance1 <= kFatPlaneWidthEpsilon ||
- distance0 >= -kFatPlaneWidthEpsilon) continue;
- } else
- {
- if (distance1 >= -kFatPlaneWidthEpsilon ||
- distance0 <= kFatPlaneWidthEpsilon) continue;
- }
-
- float3 newVertex;
-
- // Ensure we always do the intersection calculations in the exact same
- // direction across a plane to increase floating point consistency
- if (distance0 > 0)
- {
- var length = distance0 - distance1;
- var delta = distance0 / length;
- if (delta <= 0 || delta >= 1)
- continue;
- var vector = vertex0 - vertex1;
- newVertex = vertex0 - (vector * delta);
- } else
- {
- var length = distance1 - distance0;
- var delta = distance1 / length;
- if (delta <= 0 || delta >= 1)
- continue;
- var vector = vertex1 - vertex0;
- newVertex = vertex1 - (vector * delta);
- }
-
- // Whether the crossing exists at all is decided with the computed point, before canonicalization,
- // so that moving it cannot carry it across the other brush's planes (and most candidates end here).
- var newVertex4 = new float4(newVertex, 1);
- for (int p2 = 0; p2 < otherPlaneCount; p2++)
- {
- otherPlane = otherPlanes[p2];
- var distance = math.dot(otherPlane, newVertex4);
- if (distance > kFatPlaneWidthEpsilon)
- goto SkipEdge;
- }
-
- // TODO: store two end planes for each edge instead (the planes whose intersections with the infinite edge create the vertices)
- /*
- for (int p1 = 0; p1 < selfPlaneCount; p1++)
- {
- otherPlane = selfPlanes[p1];
- var distance = math.dot(otherPlane, newVertexw);
- if (distance > kFatPlaneWidthEpsilon)
- goto SkipEdge;
- }
- //*/
-
- // The position this crossing is identified by.
- var identityVertex = canonical.Canonicalize(newVertex, canonicalNodeOrder, CanonicalVertexSite.LoopSplit);
-
- // Check if the new vertex is identical to one of the edge vertices
- if ((math.lengthsq(vertex0 - identityVertex) <= kSqrVertexEqualEpsilon && weldFilter.Allows(identityVertex, vertex0)) ||
- (math.lengthsq(vertex1 - identityVertex) <= kSqrVertexEqualEpsilon && weldFilter.Allows(identityVertex, vertex1)))
- continue;
-
- var tempVertexIndex = hashedTreeSpaceVertices.AddNoResize(identityVertex, in weldFilter);
- if ((foundVertices == 0 || tempVertexIndex != tempVertices[1]) &&
- vertexIndex0 != tempVertexIndex &&
- vertexIndex1 != tempVertexIndex)
- {
- tempVertices[foundVertices + 1] = tempVertexIndex;
- foundVertices++;
-
- // It's impossible to have more than 2 intersections on a single edge when intersecting with a convex shape
- if (foundVertices == 2)
- break;
- }
- SkipEdge:
- ;
- }
-
- if (foundVertices > 0)
- {
- if (foundVertices == 2)
- {
- var tempVertexIndex0 = tempVertices[1];
- var tempVertexIndex1 = tempVertices[2];
- var tempVertex0 = hashedTreeSpaceVertices[tempVertexIndex0];
- var tempVertex1 = hashedTreeSpaceVertices[tempVertexIndex1];
- var dot0 = math.lengthsq(tempVertex0 - vertex1);
- var dot1 = math.lengthsq(tempVertex1 - vertex1);
- if (dot0 < dot1)
- {
- tempVertices[1] = tempVertexIndex1;
- tempVertices[2] = tempVertexIndex0;
- }
- }
- tempVertices[0] = vertexIndex0;
- tempVertices[1 + foundVertices] = vertexIndex1;
- for (int i = 1; i < 2 + foundVertices; i++)
- {
- if (tempVertices[i - 1] != tempVertices[i])
- edges.Add(new Edge() { index1 = (ushort)tempVertices[i - 1], index2 = (ushort)tempVertices[i] });
- }
- } else
- {
- edges.Add(newSelfEdges[e]);
- }
- }
- }
-
- public void FindBasePolygonPlaneIntersections([NoAlias, ReadOnly] ref BlobArray otherPlanes,
- in WeldIncidenceFilter weldFilter,
- //[NoAlias] ref BlobArray selfPlanes,
- [NoAlias] ref UnsafeList selfEdges,
- [NoAlias, ReadOnly] HashedVertices combinedVertices,
- in CanonicalVertices canonical = default,
- int canonicalNodeOrder = -1)
- {
- if (selfEdges.Length < 3)
- return;
-
- var newSelfEdgesLength = selfEdges.Length;
-
- NativeArray newSelfEdges;
- using var _newSelfEdges = newSelfEdges = new NativeArray(newSelfEdgesLength, Allocator.Temp);
- //NativeCollectionHelpers.EnsureMinimumSize(ref newSelfEdges, newSelfEdgesLength);
-
- newSelfEdges.CopyFrom(selfEdges, 0, selfEdges.Length);
- // Re-added with Add for the reason given in FindLoopPlaneIntersections: this runs once per other brush.
- selfEdges.Clear();
-
- int4 tempVertices = int4.zero;
-
- var otherPlaneCount = otherPlanes.Length;
- //var selfPlaneCount = selfPlanes.Length;
-
- // At most two new vertices per edge; see FindLoopPlaneIntersections for why one per plane was not enough.
- combinedVertices.ReserveAdditionalVertices(newSelfEdgesLength * 2);
-
- // TODO: Optimize the hell out of this
- for (int e = 0; e < newSelfEdgesLength; e++)
- {
- var vertexIndex0 = newSelfEdges[e].index1;
- var vertexIndex1 = newSelfEdges[e].index2;
-
- var vertex0 = combinedVertices[vertexIndex0];
- var vertex1 = combinedVertices[vertexIndex1];
-
- var vertex0w = new float4(vertex0, 1);
- var vertex1w = new float4(vertex1, 1);
-
- var foundVertices = 0;
-
- for (int p = 0; p < otherPlaneCount; p++)
- {
- var otherPlane = otherPlanes[p];
-
- var distance0 = math.dot(otherPlane, vertex0w);
- var distance1 = math.dot(otherPlane, vertex1w);
-
- if (distance0 < 0)
- {
- if (distance1 <= kFatPlaneWidthEpsilon ||
- distance0 >= -kFatPlaneWidthEpsilon) continue;
- } else
- {
- if (distance1 >= -kFatPlaneWidthEpsilon ||
- distance0 <= kFatPlaneWidthEpsilon) continue;
- }
-
- float3 newVertex;
-
- // Ensure we always do the intersection calculations in the exact same
- // direction across a plane to increase floating point consistency
- if (distance0 > 0)
- {
- var length = distance0 - distance1;
- var delta = distance0 / length;
- if (delta <= 0 || delta >= 1)
- continue;
- var vector = vertex0 - vertex1;
- newVertex = vertex0 - (vector * delta);
- } else
- {
- var length = distance1 - distance0;
- var delta = distance1 / length;
- if (delta <= 0 || delta >= 1)
- continue;
- var vector = vertex1 - vertex0;
- newVertex = vertex1 - (vector * delta);
- }
-
- // Existence first, with the computed point, as in FindLoopPlaneIntersections.
- var newVertexw = new float4(newVertex, 1);
- for (int p2 = 0; p2 < otherPlaneCount; p2++)
- {
- otherPlane = otherPlanes[p2];
- var distance = math.dot(otherPlane, newVertexw);
- if (distance > kFatPlaneWidthEpsilon)
- goto SkipEdge;
- }
- // TODO: store two end planes for each edge instead (the planes whose intersections with the infinite edge create the vertices)
- /*
- for (int p1 = 0; p1 < selfPlaneCount; p1++)
- {
- otherPlane = selfPlanes[p1];
- var distance = math.dot(otherPlane, newVertexw);
- if (distance > kFatPlaneWidthEpsilon)
- goto SkipEdge;
- }
- //*/
-
- // Identified by its canonical position.
- var identityVertex = canonical.Canonicalize(newVertex, canonicalNodeOrder, CanonicalVertexSite.BaseSplit);
-
- // Check if the new vertex is identical to one of our existing vertices
- if ((math.lengthsq(vertex0 - identityVertex) <= kSqrVertexEqualEpsilon && weldFilter.Allows(identityVertex, vertex0)) ||
- (math.lengthsq(vertex1 - identityVertex) <= kSqrVertexEqualEpsilon && weldFilter.Allows(identityVertex, vertex1)))
- continue;
-
- var tempVertexIndex = combinedVertices.AddNoResize(identityVertex, in weldFilter);
- if ((foundVertices == 0 || tempVertexIndex != tempVertices[1]) &&
- vertexIndex0 != tempVertexIndex &&
- vertexIndex1 != tempVertexIndex)
- {
- tempVertices[foundVertices + 1] = tempVertexIndex;
- foundVertices++;
-
- // It's impossible to have more than 2 intersections on a single edge when intersecting with a convex shape
- if (foundVertices == 2)
- break;
- }
- SkipEdge:
- ;
- }
-
- if (foundVertices > 0)
- {
- if (foundVertices == 2)
- {
- var tempVertexIndex0 = tempVertices[1];
- var tempVertexIndex1 = tempVertices[2];
- var tempVertex0 = combinedVertices[tempVertexIndex0];
- var tempVertex1 = combinedVertices[tempVertexIndex1];
- var dot0 = math.lengthsq(tempVertex0 - vertex1);
- var dot1 = math.lengthsq(tempVertex1 - vertex1);
- if (dot0 < dot1)
- {
- tempVertices[1] = tempVertexIndex1;
- tempVertices[2] = tempVertexIndex0;
- }
- }
- tempVertices[0] = vertexIndex0;
- tempVertices[1 + foundVertices] = vertexIndex1;
- for (int i = 1; i < 2 + foundVertices; i++)
- {
- if (tempVertices[i - 1] != tempVertices[i])
- selfEdges.Add(new Edge() { index1 = (ushort)tempVertices[i - 1], index2 = (ushort)tempVertices[i] });
- }
- } else
- {
- selfEdges.Add(newSelfEdges[e]);
- }
- }
- }
-
-
- public void FindLoopVertexOverlaps([NoAlias, ReadOnly] ref BlobArray selfPlanes,
- [NoAlias] ref UnsafeList selfEdges,
- [NoAlias, ReadOnly] UnsafeList otherEdges,
- [NoAlias, ReadOnly] HashedVertices combinedVertices)
- {
- if (selfEdges.Length < 3 ||
- otherEdges.Length < 3)
- return;
-
- var otherVerticesLength = 0;
-
- NativeArray otherVertices;
- using var _otherVertices = otherVertices = new (otherEdges.Length, Allocator.Temp);
- //NativeCollectionHelpers.EnsureMinimumSize(ref otherVertices, otherEdges.Length);
-
- // TODO: use edges instead + 2 planes intersecting each edge
- for (int v = 0; v < otherEdges.Length; v++)
- {
- var vertexIndex = otherEdges[v].index1; // <- assumes no gaps
- for (int e = 0; e < selfEdges.Length; e++)
- {
- // If the exact edge already exists in other polygon, skip it
- if (selfEdges[e].index1 == vertexIndex ||
- selfEdges[e].index2 == vertexIndex)
- goto NextVertex;
- }
-
- // TODO: store two end planes for each edge instead (the planes whose intersections with the infinite edge create the vertices)
- //*
- var vertex = combinedVertices[vertexIndex];
- for (int p = 0; p < selfPlanes.Length; p++)
- {
- var distance = math.dot(selfPlanes[p], new float4(vertex, 1));
- if (distance > kFatPlaneWidthEpsilon)
- goto NextVertex;
- }
- //*/
-
- // TODO: Check if vertex intersects at least 2 selfPlanes
- otherVertices[otherVerticesLength] = vertexIndex;
- otherVerticesLength++;
- NextVertex:
- ;
- }
-
- if (otherVerticesLength == 0)
- return;
-
- //NativeCollectionHelpers.EnsureCreatedAndClear(ref tempList);
-
- var tempListCapacity = (selfEdges.Length * 2) + otherVerticesLength;
- //if (tempList.Capacity < tempListCapacity)
- // tempList.Capacity = tempListCapacity;
-
- var inputEdgesLength = selfEdges.Length;
-
- NativeList tempList;
- using var _tempList = tempList = new NativeList (tempListCapacity, Allocator.Temp);
-
- NativeArray newSelfEdges;
- using var _newSelfEdges = newSelfEdges = new NativeArray(inputEdgesLength, Allocator.Temp);
- //NativeCollectionHelpers.EnsureMinimumSize(ref newSelfEdges, inputEdgesLength);
-
- newSelfEdges.CopyFrom(selfEdges, 0, selfEdges.Length);
- // Re-added with Add: every vertex of the other loop that lies on an edge adds one, which no capacity the
- // caller reserved accounts for (see FindLoopPlaneIntersections).
- selfEdges.Clear();
-
- // TODO: Optimize the hell out of this
- for (int e = 0; e < inputEdgesLength && otherVerticesLength > 0; e++)
- {
- var vertexIndex0 = newSelfEdges[e].index1;
- var vertexIndex1 = newSelfEdges[e].index2;
-
- var vertex0 = combinedVertices[vertexIndex0];
- var vertex1 = combinedVertices[vertexIndex1];
-
- tempList.Clear();
-
- var delta = math.normalize(vertex1 - vertex0);
- var max = math.dot(vertex1 - vertex0, delta);
- for (int v1 = otherVerticesLength - 1; v1 >= 0; v1--)
- {
- var otherVertexIndex = otherVertices[v1];
- if (otherVertexIndex == vertexIndex0 ||
- otherVertexIndex == vertexIndex1)
- continue;
- var otherVertex = combinedVertices[otherVertexIndex];
- var dot = math.dot(otherVertex - vertex0, delta);
- if (dot <= 0 || dot >= max)
- continue;
- // Both epsilons are compared against SQUARED distances (see IsPointOnLineSegment).
- if (!MathExtensions.IsPointOnLineSegment(otherVertex, vertex0, vertex1, CSGConstants.kSqrVertexEqualEpsilon, CSGConstants.kSqrEdgeDistanceEpsilon))
- continue;
-
- // Note: the otherVertices array cannot contain any indices that are part in
- // the input indices, since we checked for that when we created it.
- tempList.AddNoResize(otherVertexIndex);
-
- // TODO: figure out why removing vertices fails?
- //if (v1 != otherVerticesLength - 1 && otherVerticesLength > 0)
- // otherVertices[v1] = otherVertices[otherVerticesLength - 1];
- //otherVerticesLength--;
- }
-
- if (tempList.Length > 0)
- {
- float dot1, dot2;
- for (int v1 = 0; v1 < tempList.Length - 1; v1++)
- {
- for (int v2 = v1 + 1; v2 < tempList.Length; v2++)
- {
- var otherVertexIndex1 = tempList[v1];
- var otherVertexIndex2 = tempList[v2];
- dot1 = math.dot(combinedVertices[otherVertexIndex1] - vertex0, delta);
- dot2 = math.dot(combinedVertices[otherVertexIndex2] - vertex0, delta);
- if (dot1 >= dot2)
- {
- tempList[v1] = otherVertexIndex2;
- tempList[v2] = otherVertexIndex1;
- }
- }
- }
- if (vertexIndex0 != tempList[0])
- selfEdges.Add(new Edge { index1 = vertexIndex0, index2 = tempList[0] });
- for (int i = 1; i < tempList.Length; i++)
- {
- if (tempList[i - 1] != tempList[i])
- selfEdges.Add(new Edge { index1 = tempList[i - 1], index2 = tempList[i] });
- }
- if (tempList[tempList.Length - 1] != vertexIndex1)
- selfEdges.Add(new Edge { index1 = tempList[tempList.Length - 1], index2 = vertexIndex1 });
- } else
- {
- selfEdges.Add(newSelfEdges[e]);
- }
- }
- }
-
- public static void RemoveDuplicates(ref UnsafeList edges)
- {
- if (edges.Length < 3)
- {
- edges.Clear();
- return;
- }
-
- for (int e = edges.Length - 1; e >= 0; e--)
- {
- if (edges[e].index1 != edges[e].index2)
- continue;
- edges.RemoveAtSwapBack(e);
- }
- }
- }
-}
diff --git a/Core/2.Processing/Jobs/FindLoopOverlapIntersectionJob.cs.meta b/Core/2.Processing/Jobs/FindLoopOverlapIntersectionJob.cs.meta
deleted file mode 100644
index e5fb659f..00000000
--- a/Core/2.Processing/Jobs/FindLoopOverlapIntersectionJob.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: 71dc194ba8ed8fc409d03c027d48e129
-MonoImporter:
- externalObjects: {}
- serializedVersion: 2
- defaultReferences: []
- executionOrder: 0
- icon: {instanceID: 0}
- userData:
- assetBundleName:
- assetBundleVariant:
diff --git a/Core/2.Processing/Jobs/FindModifiedBrushesJob.cs b/Core/2.Processing/Jobs/FindModifiedBrushesJob.cs
index 3e047306..9df8dcb3 100644
--- a/Core/2.Processing/Jobs/FindModifiedBrushesJob.cs
+++ b/Core/2.Processing/Jobs/FindModifiedBrushesJob.cs
@@ -18,7 +18,6 @@ unsafe struct FindModifiedBrushesJob : IJob
[NoAlias, ReadOnly] public NativeList brushes;
[NoAlias, ReadOnly] public int brushCount;
[NoAlias, ReadOnly] public NativeList allTreeBrushIndexOrders;
- [NoAlias, ReadOnly] public bool rebuildAll; // every brush, flagged or not
// Read/Write
[NoAlias] public NativeList rebuildTreeBrushIndexOrders;
@@ -36,7 +35,7 @@ public void Execute()
for (int nodeOrder = 0; nodeOrder < brushes.Length; nodeOrder++)
{
var brushCompactNodeID = brushes[nodeOrder];
- if (rebuildAll || compactHierarchy.IsAnyStatusFlagSet(brushCompactNodeID))
+ if (compactHierarchy.IsAnyStatusFlagSet(brushCompactNodeID))
{
var indexOrder = allTreeBrushIndexOrders[nodeOrder];
Debug.Assert(indexOrder.nodeOrder == nodeOrder);
diff --git a/Core/2.Processing/Jobs/GatherOutputSurfacesJob.cs b/Core/2.Processing/Jobs/GatherOutputSurfacesJob.cs
deleted file mode 100644
index 0bf60a8d..00000000
--- a/Core/2.Processing/Jobs/GatherOutputSurfacesJob.cs
+++ /dev/null
@@ -1,66 +0,0 @@
-using System;
-using Unity.Burst;
-using Unity.Collections;
-using Unity.Jobs;
-using Unity.Mathematics;
-using Debug = UnityEngine.Debug;
-using ReadOnlyAttribute = Unity.Collections.ReadOnlyAttribute;
-
-namespace Chisel.Core
-{
- [BurstCompile(CompileSynchronously = true)]
- struct GatherOutputSurfacesJob : IJob
- {
- // Read / Write (Sort)
- [NoAlias] public NativeList outputSurfaces;
-
- // Write
- //[NoAlias, WriteOnly] public NativeReference> outputSurfaceLoops;
- [NoAlias, WriteOnly] public NativeArray outputSurfacesRange;
-
- struct ListComparer : System.Collections.Generic.IComparer
- {
- public int Compare(BrushIntersectionLoop x, BrushIntersectionLoop y)
- {
- var orderX = x.indexOrder0.nodeOrder;
- var orderY = y.indexOrder0.nodeOrder;
- var diff = orderX.CompareTo(orderY);
- if (diff != 0)
- return diff;
- orderX = x.indexOrder1.nodeOrder;
- orderY = y.indexOrder1.nodeOrder;
- return orderX.CompareTo(orderY);
- }
- }
-
- readonly static ListComparer listComparer = new ListComparer();
-
-
- public void Execute()
- {
- if (outputSurfaces.Length == 0)
- return;
-
- outputSurfaces.Sort(listComparer);
-
- int previousOrder = outputSurfaces[0].indexOrder0.nodeOrder;
- int2 range = new int2(0, 1);
- for (int i = 1; i < outputSurfaces.Length; i++)
- {
- int currentOrder = outputSurfaces[i].indexOrder0.nodeOrder;
- if (currentOrder != previousOrder)
- {
- //Debug.Log($"{previousOrder} {range}");
- outputSurfacesRange[previousOrder] = range;
- previousOrder = currentOrder;
- range.x = i;
- range.y = 1;
- } else
- range.y++;
- }
-
- //throw new Exception($"{previousOrder} {range.x} {range.y} / {brushBrushIntersections.Length}");
- outputSurfacesRange[previousOrder] = range;
- }
- }
-}
diff --git a/Core/2.Processing/Jobs/GatherOutputSurfacesJob.cs.meta b/Core/2.Processing/Jobs/GatherOutputSurfacesJob.cs.meta
deleted file mode 100644
index 2a0d2feb..00000000
--- a/Core/2.Processing/Jobs/GatherOutputSurfacesJob.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: a1c295f7a84fad34bb2fc69f493e92cc
-MonoImporter:
- externalObjects: {}
- serializedVersion: 2
- defaultReferences: []
- executionOrder: 0
- icon: {instanceID: 0}
- userData:
- assetBundleName:
- assetBundleVariant:
diff --git a/Core/2.Processing/Jobs/GenerateSurfaceTrianglesJob.cs b/Core/2.Processing/Jobs/GenerateSurfaceTrianglesJob.cs
index 81644494..44988c0f 100644
--- a/Core/2.Processing/Jobs/GenerateSurfaceTrianglesJob.cs
+++ b/Core/2.Processing/Jobs/GenerateSurfaceTrianglesJob.cs
@@ -6,47 +6,24 @@
using Debug = UnityEngine.Debug;
using ReadOnlyAttribute = Unity.Collections.ReadOnlyAttribute;
using Unity.Entities;
-using andywiecko.BurstTriangulator.LowLevel.Unsafe;
-using andywiecko.BurstTriangulator;
namespace Chisel.Core
{
- // GenerateSurfaceTrianglesJob for the exact CSG's input (triangles already made), Burst compiled: the FIXME below is
- // about the loops' triangulation, which this does not run
[BurstCompile(FloatPrecision.High, FloatMode.Strict, CompileSynchronously = true)]
- struct GenerateExactSurfaceTrianglesJob : IJobParallelForDefer
- {
- public GenerateSurfaceTrianglesJob job;
-
- public void Execute(int index) => job.ExecuteExact(index);
- }
-
- //[BurstCompile(CompileSynchronously = true)] // FIXME: If enabled, it causes more missing triangles in the mesh
struct GenerateSurfaceTrianglesJob : IJobParallelForDefer
{
// Read
// 'Required' for scheduling with index count
[NoAlias, ReadOnly] public NativeList allUpdateBrushIndexOrders;
- // Gate the vertex re-add and the T-junction insert on plane incidence; set from CSGManager's kUseIncidenceWeld.
- [NoAlias, ReadOnly] public bool useIncidenceWeld;
- // Canonical vertices (see CanonicalVertices): from Everywhere on, only the same vertex is merged here.
- [NoAlias, ReadOnly] public CanonicalVertexStage canonicalVertexStage;
- [NoAlias, ReadOnly] public NativeList> brushTreeSpacePlaneCache;
[NoAlias, ReadOnly] public NativeList> basePolygonCache;
[NoAlias, ReadOnly] public NativeList transformationCache;
- [NativeDisableParallelForRestriction]
- [NoAlias, ReadOnly] public NativeArray> loopVerticesLookup;
- [NoAlias, ReadOnly] public NativeList> brushesTouchedByBrushCache;
-
[NoAlias, ReadOnly] public NativeStream.Reader input;
[NoAlias, ReadOnly] public NativeArray meshQueries;
[NoAlias, ReadOnly] public CompactHierarchyManagerInstance.ReadOnlyEntityIDLookup entityIDLookup;
[NoAlias, ReadOnly] public bool subtractiveWorkflow;
[NoAlias, ReadOnly] public float normalSmoothingAngle;
- // Set when the input comes from ExactCSGJob (triangles already made) instead of PerformCSGJob (loops).
- [NoAlias, ReadOnly] public bool exactInput;
// Decals, lowest first. Empty when the tree has none.
[NoAlias, ReadOnly] public NativeArray decalVolumes;
// The surfaces decals are limited to (DecalVolume.targetStart/targetCount)
@@ -61,164 +38,6 @@ struct GenerateSurfaceTrianglesJob : IJobParallelForDefer
[NativeDisableParallelForRestriction]
[NoAlias] public NativeList> brushRenderBufferCache;
- [BurstDiscard]
- public static void InvalidFinalCategory(CategoryIndex _interiorCategory)
- {
- Debug.Assert(false, $"Invalid final category {_interiorCategory}");
- }
-
-
-#if UNITY_EDITOR
- static readonly bool kLogTriangulationIssues = false;
-
-#endif
-
- static readonly bool kCleanupNonSimpleLoops = true;
-
- static readonly bool kCloseOpenChains2D = true;
-
- static readonly bool kInsertTJunctions = true;
-
- const float kTJunctionPlaneBand = 0.05f;
-
- static readonly bool kLogTJunctionInsertions = false;
-
- // Logs this brush's touch-graph neighbours (entityID:IntersectionType), so a brush whose vertex
- // lands on this brush's edge can be checked against the touch graph for presence.
- [BurstDiscard]
- static void LogTouchedNeighbours(ulong entityID, ref BlobArray touched,
- CompactHierarchyManagerInstance.ReadOnlyEntityIDLookup lookup)
- {
-#if UNITY_EDITOR
- if (!kLogTJunctionInsertions)
- return;
- var sb = new System.Text.StringBuilder(160);
- sb.Append($"TJTOUCH b{entityID}:");
- for (int i = 0; i < touched.Length; i++)
- {
- var id = lookup.SafeGetNodeEntityID(touched[i].nodeIndexOrder.compactNodeID);
- sb.Append($" {id}:{touched[i].type}");
- }
- Debug.LogWarning(sb.ToString());
-#endif
- }
-
- static void LogClosestApproach(in UnsafeList edges, in NativeList candidates,
- HashedVertices vertices, ref double minPerp)
- {
- for (int c = 0; c < candidates.Length; c++)
- {
- double3 w = candidates[c];
- for (int e = 0; e < edges.Length; e++)
- {
- double3 a = vertices[edges[e].index1];
- double3 ab = (double3)vertices[edges[e].index2] - a, aw = w - a;
- double L2 = math.dot(ab, ab);
- if (L2 <= 1e-12)
- continue;
- double t = math.dot(aw, ab) / L2;
- if (t <= 0.0 || t >= 1.0)
- continue;
- double pp = math.length(math.cross(aw, ab)) / math.sqrt(L2);
- if (pp < minPerp) minPerp = pp;
- }
- }
- }
-
- [BurstDiscard]
- static void LogTJunctionInsertions(ulong entityID, int touched, int withVerts, int planeCand, int inserted, double selfPlaneMax, double minPerp)
- {
-#if UNITY_EDITOR
- if (!kLogTJunctionInsertions)
- return;
- var ci = System.Globalization.CultureInfo.InvariantCulture;
- Debug.LogWarning($"TJINS b{entityID}: touched={touched} withVerts={withVerts} planeCand={planeCand} inserted={inserted} selfPlaneMax={selfPlaneMax.ToString("0.######", ci)} minPerp={minPerp.ToString("0.######", ci)}");
-#endif
- }
-
- static readonly bool kLogBoundaryEdges = false;
-
- [BurstDiscard]
- static unsafe void LogBoundaryEdges(ulong entityID, int surfaceIndex, int loopIndex, in UnsafeList edges, float3* verts)
- {
-#if UNITY_EDITOR
- if (!kLogBoundaryEdges)
- return;
- var ci = System.Globalization.CultureInfo.InvariantCulture;
- var sb = new System.Text.StringBuilder(256);
- sb.Append($"BEDGE b{entityID} s{surfaceIndex} l{loopIndex}:");
- for (int e = 0; e < edges.Length; e++)
- {
- var a = verts[edges[e].index1];
- var b = verts[edges[e].index2];
- sb.Append($" {a.x.ToString("0.####", ci)},{a.y.ToString("0.####", ci)},{a.z.ToString("0.####", ci)}|{b.x.ToString("0.####", ci)},{b.y.ToString("0.####", ci)},{b.z.ToString("0.####", ci)}");
- }
- sb.Append(" | I:");
- for (int e = 0; e < edges.Length; e++)
- sb.Append($" {edges[e].index1}-{edges[e].index2}");
- Debug.LogWarning(sb.ToString());
-#endif
- }
-
- enum SurfaceDropReason : byte
- {
- SurfaceHasNoLoops, // all loops on this surface were filtered out before triangulation
- TooFewPointsAfterDedup, // < 3 unique points / edges left once duplicates were removed
- DegenerateInput, // the 2D input collapsed to a line / point
- TriangulatorError, // BurstTriangulator returned a non-OK Status (see decoded flags)
- ZeroTrianglesReturned, // Status was OK but the triangulator produced no triangles
- }
-
- [BurstDiscard]
- static void LogSurfaceDrop(ulong entityID, int surfaceIndex, int loopIndex,
- int pointCount, int edgeCount, SurfaceDropReason reason, Status status)
- {
-#if UNITY_EDITOR && DEBUG
- if (!kLogTriangulationIssues)
- return;
- var detail = reason == SurfaceDropReason.TriangulatorError ? $", status={status} (0x{(int)status:X})" : "";
- // NOTE: edgeCount is roVerts.edgeIndices.Length, which is FLATTENED (2 ints per edge), so the
- // real edge count is edgeCount/2.
- Debug.LogWarning($"[Chisel.Triangulation] No geometry for brush {entityID}, surface {surfaceIndex}, " +
- $"loop {loopIndex}: {reason}{detail} (points={pointCount}, edges={edgeCount}).");
-#endif
- }
-
-#if UNITY_EDITOR
- static readonly bool kLogDropDetail = false;
-#endif
-
- [BurstDiscard]
- static void LogDropDetail(ulong entityID, int surfaceIndex, int loopIndex, SurfaceDropReason reason,
- NativeArray positions2D, NativeArray edgeIndices)
- {
-#if UNITY_EDITOR
- if (!kLogDropDetail)
- return;
- // InvariantCulture so decimals use '.' (not the OS locale's ',') and stay parseable - the
- // only separators inside the line are then the ',' between x and y and spaces between points.
- var ci = System.Globalization.CultureInfo.InvariantCulture;
- var sb = new System.Text.StringBuilder(256);
- sb.Append($"DROPDET b{entityID} s{surfaceIndex} l{loopIndex} {reason} pts={positions2D.Length} edges={edgeIndices.Length / 2} | P:");
- for (int i = 0; i < positions2D.Length; i++)
- sb.Append($" {i}=({positions2D[i].x.ToString("0.####", ci)},{positions2D[i].y.ToString("0.####", ci)})");
- sb.Append(" | E:");
- for (int i = 0; i + 1 < edgeIndices.Length; i += 2)
- sb.Append($" {edgeIndices[i]}-{edgeIndices[i + 1]}");
- Debug.LogWarning(sb.ToString());
-#endif
- }
-
- [BurstDiscard]
- static void SelfIntersectionDetected(int surf, int loopIdx)
- {
-#if UNITY_EDITOR && DEBUG
- if (!kLogTriangulationIssues)
- return;
- Debug.LogWarning($"Self-intersection detected in surface {surf}, loop index {loopIdx}.");
-#endif
- }
-
struct CompareSortByBasePlaneIndex : System.Collections.Generic.IComparer
{
public readonly int Compare(ChiselQuerySurface x, ChiselQuerySurface y)
@@ -231,560 +50,8 @@ public readonly int Compare(ChiselQuerySurface x, ChiselQuerySurface y)
}
readonly static CompareSortByBasePlaneIndex kCompareSortByBasePlaneIndex = new();
-
- public unsafe void Execute(int index)
- {
- if (exactInput)
- {
- ExecuteExact(index);
- return;
- }
-
- var count = input.BeginForEachIndex(index);
- if (count == 0)
- return;
-
- // Read brush data
- var brushIndexOrder = input.Read();
- var brushNodeOrder = brushIndexOrder.nodeOrder;
- var vertexCount = input.Read();
-
- if (vertexCount < 3)
- return;
-
- // PerformCSGJob already welded this list; re-adding it may only merge what this brush's own faces allow.
- var weldFilter = WeldIncidenceFilter.Disabled;
- if (canonicalVertexStage >= CanonicalVertexStage.Everywhere)
- weldFilter = WeldIncidenceFilter.SameVertexOnly; // canonical vertices: only the same vertex is merged
- else
- if (useIncidenceWeld && brushNodeOrder < brushTreeSpacePlaneCache.Length &&
- brushTreeSpacePlaneCache[brushNodeOrder].IsCreated && basePolygonCache[brushNodeOrder].IsCreated)
- weldFilter = WeldIncidenceFilter.Create(ref brushTreeSpacePlaneCache[brushNodeOrder].Value.treeSpacePlanes,
- basePolygonCache[brushNodeOrder].Value.polygons.Length);
-
- HashedVertices brushVertices;
- using var _brushVertices = brushVertices = new HashedVertices(vertexCount, Allocator.Temp);
- for (int v = 0; v < vertexCount; v++)
- {
- var vertex = input.Read();
- brushVertices.AddNoResize(vertex, in weldFilter);
- }
-
- // Read surface loops
- var surfaceOuterCount = input.Read();
- NativeList> surfaceLoopIndices;
- using var _surfaceLoopIndices = surfaceLoopIndices = new NativeList>(surfaceOuterCount, Allocator.Temp);
- surfaceLoopIndices.Resize(surfaceOuterCount, NativeArrayOptions.ClearMemory);
- try
- {
- for (int o = 0; o < surfaceOuterCount; o++)
- {
- var countInner = input.Read();
- if (countInner > 0)
- {
- var inner = new UnsafeList(countInner, Allocator.Temp);
- for (int i = 0; i < countInner; i++)
- {
- inner.AddNoResize(input.Read());
- }
- surfaceLoopIndices[o] = inner;
- }
- else
- surfaceLoopIndices[o] = default;
- }
-
- // Read loop infos and edges
- var loopCount = input.Read();
- NativeArray surfaceLoopAllInfos;
- using var _surfaceLoopAllInfos = surfaceLoopAllInfos = new NativeArray(loopCount, Allocator.Temp);
-
- NativeList> surfaceLoopAllEdges;
- using var _surfaceLoopAllEdges = surfaceLoopAllEdges = new NativeList>(loopCount, Allocator.Temp);
- surfaceLoopAllEdges.Resize(loopCount, NativeArrayOptions.ClearMemory);
-
- // Declared before the try so the finally can dispose it; populated by the cross-brush
- // T-junction pre-pass below (default/uncreated when that pass is disabled or no-op).
- NativeArray protectedVertices = default;
- // Created only for a brush that decals may reach. Disposed explicitly, never through a copy: its lists
- // reallocate as they grow.
- DecalSurfaceBuilder decalBuilder = default;
- try
- {
- for (int l = 0; l < loopCount; l++)
- {
- surfaceLoopAllInfos[l] = input.Read();
- var edgeCount = input.Read();
- if (edgeCount > 0)
- {
- var edges = new UnsafeList(edgeCount, Allocator.Temp);
- for (int e = 0; e < edgeCount; e++)
- {
- edges.AddNoResize(input.Read());
- }
- surfaceLoopAllEdges[l] = edges;
- }
- }
- input.EndForEachIndex();
-
- if (!basePolygonCache[brushNodeOrder].IsCreated)
- return;
-
- ulong entityID = entityIDLookup.SafeGetNodeEntityID(brushIndexOrder.compactNodeID);
-
- // Compute maximum sizes
- int maxLoops = 0, 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;
- var transform = transformationCache[brushNodeOrder];
- var treeToNode = transform.treeToNode;
- var nodeToTreeInvTrans = math.transpose(treeToNode);
-
- protectedVertices = default;
- if (kInsertTJunctions &&
- brushNodeOrder < brushesTouchedByBrushCache.Length &&
- brushesTouchedByBrushCache[brushNodeOrder].IsCreated)
- {
- var tjProtected = new NativeList