Beispiel #1
0
        // TODO: turn into job
        void FindPlanePairs(IntersectionType type,
                            [NoAlias] ref BrushMeshBlob mesh,
                            [NoAlias] NativeArray <int> intersectingPlanes,
                            int intersectingPlanesLength,
                            [NoAlias] NativeArray <float4> localSpacePlanesPtr,
                            [NoAlias] ref NativeArray <int> vertexUsed,
                            float4x4 vertexTransform,
                            bool needTransform,
                            [NoAlias] ref NativeArray <PlanePair> usedPlanePairs,
                            [NoAlias] ref NativeArray <float3> usedVertices,
                            out int usedPlanePairsLength,
                            out int usedVerticesLength)
        {
            NativeCollectionHelpers.EnsureMinimumSize(ref usedVertices, mesh.localVertices.Length);
            NativeCollectionHelpers.EnsureMinimumSizeAndClear(ref usedPlanePairs, mesh.halfEdges.Length);

            if (type != IntersectionType.Intersection)
            {
                usedPlanePairsLength = 0;
                usedVerticesLength   = mesh.localVertices.Length;
                for (int i = 0; i < mesh.localVertices.Length; i++)
                {
                    usedVertices[i] = mesh.localVertices[i];
                }
                return;
            }
            NativeCollectionHelpers.EnsureMinimumSizeAndClear(ref vertexUsed, mesh.localVertices.Length);
            NativeCollectionHelpers.EnsureMinimumSizeAndClear(ref planeAvailable, mesh.localPlanes.Length);

            // TODO: this can be partially stored in brushmesh
            // TODO: optimize

            ref var halfEdgePolygonIndices = ref mesh.halfEdgePolygonIndices;
Beispiel #2
0
        public void Execute()
        {
            var maxPairs = (maxOrder * maxOrder);

            NativeCollectionHelpers.EnsureMinimumSizeAndClear(ref usedLookup, maxPairs);

            uniqueBrushPairs.Clear();

            int requiredCapacity = 0;

            for (int b0 = 0; b0 < allUpdateBrushIndexOrders.Length; b0++)
            {
                var brushIndexOrder0 = allUpdateBrushIndexOrders[b0];
                int brushNodeOrder0  = brushIndexOrder0.nodeOrder;

                var brushesTouchedByBrush = brushesTouchedByBrushes[brushNodeOrder0];
                if (brushesTouchedByBrush == ChiselBlobAssetReference <BrushesTouchedByBrush> .Null)
                {
                    continue;
                }

                ref var intersections = ref brushesTouchedByBrush.Value.brushIntersections;
                if (intersections.Length == 0)
                {
                    continue;
                }

                requiredCapacity += intersections.Length + 1;
            }
Beispiel #3
0
 public static unsafe void ReadArrayAndEnsureSize <T>([NoAlias] ref NativeStream.Reader nativeStream, [NoAlias] ref NativeArray <T> array, out int length) where T : unmanaged
 {
     length = nativeStream.Read <int>();
     NativeCollectionHelpers.EnsureMinimumSize(ref array, length);
     for (int i = 0; i < length; i++)
     {
         array[i] = nativeStream.Read <T>();
     }
 }
Beispiel #4
0
        public void Execute()
        {
            var maxPairs = (maxOrder * maxOrder);

            NativeCollectionHelpers.EnsureMinimumSizeAndClear(ref usedLookup, maxPairs);

            for (int b0 = 0; b0 < allUpdateBrushIndexOrders.Length; b0++)
            {
                var brushIndexOrder0 = allUpdateBrushIndexOrders[b0];
                int brushNodeOrder0  = brushIndexOrder0.nodeOrder;

                var brushesTouchedByBrush = brushesTouchedByBrushes[brushNodeOrder0];
                if (brushesTouchedByBrush == ChiselBlobAssetReference <BrushesTouchedByBrush> .Null)
                {
                    continue;
                }

                ref var intersections = ref brushesTouchedByBrush.Value.brushIntersections;
                if (intersections.Length == 0)
                {
                    continue;
                }

                if (uniqueBrushPairs->Capacity < intersections.Length)
                {
                    uniqueBrushPairs->Capacity = intersections.Length;
                }

                // Find all intersections between brushes
                for (int i = 0; i < intersections.Length; i++)
                {
                    var intersection     = intersections[i];
                    var brushIndexOrder1 = intersection.nodeIndexOrder;
                    int brushNodeOrder1  = brushIndexOrder1.nodeOrder;

                    var brushPair = new BrushPair2
                    {
                        type             = intersection.type,
                        brushIndexOrder0 = brushIndexOrder0,
                        brushIndexOrder1 = brushIndexOrder1
                    };

                    if (brushNodeOrder0 > brushNodeOrder1) // ensures we do calculations exactly the same for each brush pair
                    {
                        brushPair.Flip();
                    }

                    int testIndex = (brushPair.brushIndexOrder0.nodeOrder * maxOrder) + brushPair.brushIndexOrder1.nodeOrder;

                    if (!usedLookup.IsSet(testIndex))
                    {
                        usedLookup.Set(testIndex, true);
                        uniqueBrushPairs->AddNoResize(brushPair);
                    }
                }
            }
        public void Execute()
        {
            NativeCollectionHelpers.EnsureCapacityAndClear(ref requiredTemporaryBullShitByDOTS, allTreeBrushIndexOrders.Length);
            NativeCollectionHelpers.EnsureMinimumSizeAndClear(ref foundBrushes, allTreeBrushIndexOrders.Length);

            for (int i = 0; i < rebuildTreeBrushIndexOrders.Length; i++)
            {
                foundBrushes.Set(rebuildTreeBrushIndexOrders[i].nodeOrder, true);
                requiredTemporaryBullShitByDOTS.AddNoResize(rebuildTreeBrushIndexOrders[i]);
            }
            for (int i = 0; i < brushesThatNeedIndirectUpdate.Length; i++)
            {
                var indexOrder = brushesThatNeedIndirectUpdate[i];
                if (!foundBrushes.IsSet(indexOrder.nodeOrder))
                {
                    requiredTemporaryBullShitByDOTS.AddNoResize(indexOrder);
                    foundBrushes.Set(indexOrder.nodeOrder, true);
                }
            }
            requiredTemporaryBullShitByDOTS.Sort(new IntersectionUtility.IndexOrderComparer());
            allUpdateBrushIndexOrders.AddRangeNoResize(requiredTemporaryBullShitByDOTS);
        }
Beispiel #6
0
        public void Execute()
        {
            var minCount = brushBrushIntersections.Count * 16;

            NativeCollectionHelpers.EnsureCapacityAndClear(ref intersections, minCount);

            for (int i = 0; i < brushBrushIntersections.Count; i++)
            {
                if (!brushBrushIntersections.IsAllocated(i))
                {
                    continue;
                }
                var subArray = brushBrushIntersections[i];
                for (int j = 0; j < subArray.Count; j++)
                {
                    var intersectWith = subArray[j];
                    var pair          = new BrushPair
                    {
                        brushNodeOrder0 = i,
                        brushNodeOrder1 = intersectWith.brushNodeOrder1,
                        type            = intersectWith.type
                    };
                    intersections.Add(pair);
                    pair.Flip();
                    intersections.Add(pair);
                }
            }
            brushIntersectionsWith->Clear();
            if (intersections.Length == 0)
            {
                return;
            }

            intersections.Sort(new ListComparer());

            var currentPair   = intersections[0];
            int previousOrder = currentPair.brushNodeOrder0;

            brushIntersectionsWith->Add(new BrushIntersectWith
            {
                brushNodeOrder1 = currentPair.brushNodeOrder1,
                type            = currentPair.type,
            });
            int2 range = new int2(0, 1);

            for (int i = 1; i < intersections.Length; i++)
            {
                currentPair = intersections[i];
                int currentOrder = currentPair.brushNodeOrder0;
                brushIntersectionsWith->Add(new BrushIntersectWith
                {
                    brushNodeOrder1 = currentPair.brushNodeOrder1,
                    type            = currentPair.type,
                });
                if (currentOrder != previousOrder)
                {
                    //Debug.Log($"{previousOrder} {range}");
                    brushIntersectionsWithRange[previousOrder] = range;
                    previousOrder = currentOrder;
                    range.x       = i;
                    range.y       = 1;
                }
                else
                {
                    range.y++;
                }
            }
            brushIntersectionsWithRange[previousOrder] = range;
        }
Beispiel #7
0
        public void Execute(int index1)
        {
            if (allTreeBrushIndexOrders.Length == rebuildTreeBrushIndexOrders.Length)
            {
                //for (int index1 = 0; index1 < updateBrushIndicesArray.Length; index1++)
                {
                    var brush1IndexOrder = rebuildTreeBrushIndexOrders[index1];
                    int brush1NodeOrder  = brush1IndexOrder.nodeOrder;
                    NativeListArray <BrushIntersectWith> .NativeList brush1Intersections;
                    if (!brushBrushIntersections.IsAllocated(brush1NodeOrder))
                    {
                        brush1Intersections = brushBrushIntersections.AllocateWithCapacityForIndex(brush1NodeOrder, 16);
                    }
                    else
                    {
                        brush1Intersections = brushBrushIntersections[brush1NodeOrder];
                    }
                    for (int index0 = 0; index0 < rebuildTreeBrushIndexOrders.Length; index0++)
                    {
                        var brush0IndexOrder = rebuildTreeBrushIndexOrders[index0];
                        int brush0NodeOrder  = brush0IndexOrder.nodeOrder;
                        if (brush0NodeOrder <= brush1NodeOrder)
                        {
                            continue;
                        }
                        var result = IntersectionUtility.FindIntersection(brush0NodeOrder, brush1NodeOrder,
                                                                          ref brushMeshLookup, ref brushTreeSpaceBounds, ref transformationCache,
                                                                          ref transformedPlanes0, ref transformedPlanes1);
                        if (result == IntersectionType.NoIntersection)
                        {
                            continue;
                        }
                        result = IntersectionUtility.Flip(result);
                        IntersectionUtility.StoreIntersection(brush1Intersections, brush0IndexOrder, result);
                    }
                }
                return;
            }

            NativeCollectionHelpers.EnsureMinimumSizeAndClear(ref foundBrushes, allTreeBrushIndexOrders.Length);
            NativeCollectionHelpers.EnsureMinimumSizeAndClear(ref usedBrushes, allTreeBrushIndexOrders.Length);

            // TODO: figure out a way to avoid needing this
            for (int a = 0; a < rebuildTreeBrushIndexOrders.Length; a++)
            {
                foundBrushes.Set(rebuildTreeBrushIndexOrders[a].nodeOrder, true);
            }

            //for (int index1 = 0; index1 < updateBrushIndicesArray.Length; index1++)
            {
                var brush1IndexOrder = rebuildTreeBrushIndexOrders[index1];
                int brush1NodeOrder  = brush1IndexOrder.nodeOrder;

                NativeListArray <BrushIntersectWith> .NativeList brush1Intersections;
                if (!brushBrushIntersections.IsAllocated(brush1NodeOrder))
                {
                    brush1Intersections = brushBrushIntersections.AllocateWithCapacityForIndex(brush1NodeOrder, 16);
                }
                else
                {
                    brush1Intersections = brushBrushIntersections[brush1NodeOrder];
                }
                for (int index0 = 0; index0 < allTreeBrushIndexOrders.Length; index0++)
                {
                    var brush0IndexOrder = allTreeBrushIndexOrders[index0];
                    int brush0NodeOrder  = brush0IndexOrder.nodeOrder;
                    if (brush0NodeOrder == brush1NodeOrder)
                    {
                        continue;
                    }
                    var found = foundBrushes.IsSet(brush0NodeOrder);
                    if (brush0NodeOrder < brush1NodeOrder && found)
                    {
                        continue;
                    }
                    var result = IntersectionUtility.FindIntersection(brush0NodeOrder, brush1NodeOrder,
                                                                      ref brushMeshLookup, ref brushTreeSpaceBounds, ref transformationCache,
                                                                      ref transformedPlanes0, ref transformedPlanes1);
                    if (result == IntersectionType.NoIntersection)
                    {
                        continue;
                    }
                    if (!found)
                    {
                        if (!usedBrushes.IsSet(brush0IndexOrder.nodeOrder))
                        {
                            usedBrushes.Set(brush0IndexOrder.nodeOrder, true);
                            brushesThatNeedIndirectUpdateHashMap.Add(brush0IndexOrder);
                            result = IntersectionUtility.Flip(result);
                            IntersectionUtility.StoreIntersection(brush1Intersections, brush0IndexOrder, result);
                        }
                    }
                    else
                    {
                        if (brush0NodeOrder > brush1NodeOrder)
                        {
                            result = IntersectionUtility.Flip(result);
                            IntersectionUtility.StoreIntersection(brush1Intersections, brush0IndexOrder, result);
                        }
                    }
                }
            }
        }
        void GenerateLoop(IndexOrder brushIndexOrder0,
                          IndexOrder brushIndexOrder1,
                          bool invertedTransform,
                          [NoAlias] NativeArray <SurfaceInfo> surfaceInfos,
                          [NoAlias] int surfaceInfosLength,
                          [NoAlias] ref BrushTreeSpacePlanes brushTreeSpacePlanes0,
                          [NoAlias] NativeArray <PlaneVertexIndexPair> foundIndices0,
                          [NoAlias] ref int foundIndices0Length,
                          [NoAlias] ref HashedVertices hashedTreeSpaceVertices,
                          [NoAlias] NativeList <BrushIntersectionLoop> .ParallelWriter outputSurfaces)
        {
            // Why is the unity NativeSort slower than bubble sort?
            // TODO: revisit this assumption
            //*
            for (int i = 0; i < foundIndices0Length - 1; i++)
            {
                for (int j = i + 1; j < foundIndices0Length; j++)
                {
                    var x = foundIndices0[i];
                    var y = foundIndices0[j];
                    if (x.planeIndex > y.planeIndex)
                    {
                        continue;
                    }
                    if (x.planeIndex == y.planeIndex)
                    {
                        if (x.vertexIndex <= y.vertexIndex)
                        {
                            continue;
                        }
                    }

                    var t = x;
                    foundIndices0[i] = foundIndices0[j];
                    foundIndices0[j] = t;
                }
            }

            /*/
             * foundIndices0.Sort(comparer);
             * //*/

            NativeCollectionHelpers.EnsureMinimumSize(ref planeIndexOffsets, foundIndices0Length);
            NativeCollectionHelpers.EnsureCapacityAndClear(ref uniqueIndices, foundIndices0Length);

            var planeIndexOffsetsLength = 0;
            //var planeIndexOffsets       = stackalloc PlaneIndexOffsetLength[foundIndices0Length];
            //var uniqueIndices           = stackalloc ushort[foundIndices0Length];

            // Now that our indices are sorted by planeIndex, we can segment them by start/end offset
            var previousPlaneIndex  = foundIndices0[0].planeIndex;
            var previousVertexIndex = foundIndices0[0].vertexIndex;

            uniqueIndices.Add(previousVertexIndex);
            var loopStart = 0;

            for (int i = 1; i < foundIndices0Length; i++)
            {
                var indices = foundIndices0[i];

                var planeIndex  = indices.planeIndex;
                var vertexIndex = indices.vertexIndex;

                // TODO: why do we have soooo many duplicates sometimes?
                if (planeIndex == previousPlaneIndex &&
                    vertexIndex == previousVertexIndex)
                {
                    continue;
                }

                if (planeIndex != previousPlaneIndex)
                {
                    var currLength = RemoveDuplicateEdges(ref uniqueIndices, loopStart, uniqueIndices.Length);
                    //var currLength = (uniqueIndices.Length - loopStart);
                    if (currLength > 2)
                    {
                        planeIndexOffsets[planeIndexOffsetsLength] = new PlaneIndexOffsetLength
                        {
                            length     = (ushort)currLength,
                            offset     = (ushort)loopStart,
                            planeIndex = previousPlaneIndex
                        };
                        planeIndexOffsetsLength++;
                    }
                    loopStart = uniqueIndices.Length;
                }

                uniqueIndices.Add(vertexIndex);
                previousVertexIndex = vertexIndex;
                previousPlaneIndex  = planeIndex;
            }
            {
                var currLength = RemoveDuplicateEdges(ref uniqueIndices, loopStart, uniqueIndices.Length);
                //var currLength = (uniqueIndices.Length - loopStart);
                if (currLength > 2)
                {
                    planeIndexOffsets[planeIndexOffsetsLength] = new PlaneIndexOffsetLength
                    {
                        length     = (ushort)currLength,
                        offset     = (ushort)loopStart,
                        planeIndex = previousPlaneIndex
                    };
                    planeIndexOffsetsLength++;
                }
            }

            var maxLength = 0;

            for (int i = 0; i < planeIndexOffsetsLength; i++)
            {
                maxLength = math.max(maxLength, planeIndexOffsets[i].length);
            }

            NativeCollectionHelpers.EnsureMinimumSize(ref sortedStack, maxLength * 2);


            var uniqueIndicesArray = uniqueIndices.AsArray();

            // For each segment, we now sort our vertices within each segment,
            // making the assumption that they are convex
            //var sortedStack = stackalloc int2[maxLength * 2];
            ref var vertices = ref hashedTreeSpaceVertices;//.GetUnsafeReadOnlyPtr();
        void FindIntersectionVertices(ref NativeArray <float4> intersectingPlanes0,
                                      int intersectingPlanes0Length,
                                      int intersectingPlanesAndEdges0Length,
                                      ref NativeArray <float4> intersectingPlanes1,
                                      int intersectingPlanes1Length,
                                      int intersectingPlanesAndEdges1Length,
                                      ref NativeArray <PlanePair> usedPlanePairs1,
                                      int usedPlanePairs1Length,
                                      ref NativeArray <int> intersectingPlaneIndices0,
                                      int intersectingPlaneIndices0Length,
                                      float4x4 nodeToTreeSpaceMatrix0,
                                      ref HashedVertices hashedTreeSpaceVertices,
                                      ref HashedVertices snapHashedVertices,
                                      NativeArray <PlaneVertexIndexPair> foundIndices0,
                                      ref int foundIndices0Length,
                                      NativeArray <PlaneVertexIndexPair> foundIndices1,
                                      ref int foundIndices1Length)
        {
            int foundVerticesCount = usedPlanePairs1Length * intersectingPlanes0Length;

            NativeCollectionHelpers.EnsureMinimumSize(ref foundVertices, foundVerticesCount);
            NativeCollectionHelpers.EnsureMinimumSize(ref foundEdges, foundVerticesCount);
            NativeCollectionHelpers.EnsureMinimumSize(ref foundIntersections, foundVerticesCount);

            var n = 0;

            for (int i = 0; i < usedPlanePairs1Length; i++)
            {
                for (int j = 0; j < intersectingPlanes0Length; j++)
                {
                    var plane0 = usedPlanePairs1[i].plane0;
                    var plane1 = usedPlanePairs1[i].plane1;
                    var plane2 = intersectingPlanes0[j];

                    foundIntersections[n] = new IntersectionPlanes
                    {
                        //plane0    = plane0,
                        //plane1    = plane1,
                        plane2      = plane2,
                        planeIndex0 = usedPlanePairs1[i].planeIndex0,
                        planeIndex1 = usedPlanePairs1[i].planeIndex1,
                        planeIndex2 = intersectingPlaneIndices0[j]
                    };

                    foundEdges[n] = new IntersectionEdge
                    {
                        edgeVertex0 = usedPlanePairs1[i].edgeVertex0,
                        edgeVertex1 = usedPlanePairs1[i].edgeVertex1
                    };

                    if (math.abs(math.dot(plane2.xyz, plane0.xyz)) >= CSGConstants.kNormalDotAlignEpsilon ||
                        math.abs(math.dot(plane2.xyz, plane1.xyz)) >= CSGConstants.kNormalDotAlignEpsilon ||
                        math.abs(math.dot(plane0.xyz, plane1.xyz)) >= CSGConstants.kNormalDotAlignEpsilon)
                    {
                        continue;
                    }

                    var localVertex = PlaneExtensions.Intersection(plane2, plane0, plane1);
                    if (double.IsNaN(localVertex.x))
                    {
                        continue;
                    }

                    foundVertices[n] = new float4((float3)localVertex, 1);
                    n++;
                }
            }

            for (int k = n - 1; k >= 0; k--)
            {
                var edgeVertex0 = foundEdges[k].edgeVertex0;
                var edgeVertex1 = foundEdges[k].edgeVertex1;
                var plane2      = foundIntersections[k].plane2;

                if (math.abs(math.dot(plane2, edgeVertex0)) <= kFatPlaneWidthEpsilon &&
                    math.abs(math.dot(plane2, edgeVertex1)) <= kFatPlaneWidthEpsilon)
                {
                    if (k < n - 1)
                    {
                        foundIntersections[k] = foundIntersections[n - 1];
                        foundVertices[k]      = foundVertices[n - 1];
                    }
                    n--;
                }
            }

            // TODO: since we're using a pair in the outer loop, we could also determine which
            //       2 planes it intersects at both ends and just check those two planes ..

            // NOTE: for brush2, the intersection will always be only on two planes
            //       UNLESS it's a corner vertex along that edge (we can compare to the two vertices)
            //       in which case we could use a pre-calculated list of planes ..
            //       OR when the intersection is outside of the edge ..

            for (int k = n - 1; k >= 0; k--)
            {
                if (IsOutsidePlanes(intersectingPlanes0, intersectingPlanesAndEdges0Length, foundVertices[k]) ||
                    IsOutsidePlanes(intersectingPlanes1, intersectingPlanesAndEdges1Length, foundVertices[k]))
                {
                    if (k < n - 1)
                    {
                        foundIntersections[k] = foundIntersections[n - 1];
                        foundVertices[k]      = foundVertices[n - 1];
                    }
                    n--;
                }
            }

            for (int k = 0; k < n; k++)
            {
                var planeIndex0 = (ushort)foundIntersections[k].planeIndex0;
                var planeIndex1 = (ushort)foundIntersections[k].planeIndex1;
                var planeIndex2 = (ushort)foundIntersections[k].planeIndex2;

                var localVertex = foundVertices[k];

                // TODO: should be having a Loop for each plane that intersects this vertex, and add that vertex
                //       to ensure they are identical
                var treeSpaceVertex = math.mul(nodeToTreeSpaceMatrix0, localVertex).xyz;
                treeSpaceVertex = snapHashedVertices[snapHashedVertices.AddNoResize(treeSpaceVertex)];
                var treeSpaceVertexIndex = hashedTreeSpaceVertices.AddNoResize(treeSpaceVertex);

                {
                    // TODO: optimize
                    for (int f = 0; f < foundIndices0Length; f++)
                    {
                        if (foundIndices0[f].vertexIndex == treeSpaceVertexIndex &&
                            foundIndices0[f].planeIndex == planeIndex2)
                        {
                            goto skip0;
                        }
                    }

                    foundIndices0[foundIndices0Length] = new PlaneVertexIndexPair {
                        planeIndex = planeIndex2, vertexIndex = treeSpaceVertexIndex
                    };
                    foundIndices0Length++;
                    skip0 :;
                }

                {
                    // TODO: optimize
                    for (int f = 0; f < foundIndices1Length; f++)
                    {
                        if (foundIndices1[f].vertexIndex == treeSpaceVertexIndex &&
                            foundIndices1[f].planeIndex == planeIndex0)
                        {
                            goto skip1;
                        }
                    }

                    foundIndices1[foundIndices1Length] = new PlaneVertexIndexPair {
                        planeIndex = planeIndex0, vertexIndex = treeSpaceVertexIndex
                    };
                    foundIndices1Length++;
                    skip1 :;
                }

                {
                    // TODO: optimize
                    for (int f = 0; f < foundIndices1Length; f++)
                    {
                        if (foundIndices1[f].vertexIndex == treeSpaceVertexIndex &&
                            foundIndices1[f].planeIndex == planeIndex1)
                        {
                            goto skip2;
                        }
                    }

                    foundIndices1[foundIndices1Length] = new PlaneVertexIndexPair {
                        planeIndex = planeIndex1, vertexIndex = treeSpaceVertexIndex
                    };
                    foundIndices1Length++;
                    skip2 :;
                }
            }
        }
        //[MethodImpl(MethodImplOptions.NoInlining)]
        void FindInsideVertices([NoAlias] NativeArray <float3> usedVertices0,
                                int usedVertices0Length,
                                [NoAlias] NativeArray <ushort> vertexIntersectionPlanes,
                                int vertexIntersectionPlanesLength,
                                [NoAlias] NativeArray <int2> vertexIntersectionSegments,
                                int vertexIntersectionSegmentsLength,
                                [NoAlias] NativeArray <float4> intersectingPlanes1,
                                int intersectingPlanes1Length,
                                int intersectingPlanesAndEdges1Length,
                                float4x4 nodeToTreeSpaceMatrix1,
                                float4x4 vertexToLocal0,
                                [NoAlias] ref HashedVertices hashedTreeSpaceVertices,
                                [NoAlias] ref HashedVertices snapHashedVertices,
                                [NoAlias] NativeArray <PlaneVertexIndexPair> foundIndices0,
                                ref int foundIndices0Length)
        {
            NativeCollectionHelpers.EnsureMinimumSize(ref localVertices, usedVertices0Length);
            NativeCollectionHelpers.EnsureMinimumSize(ref usedVertexIndices, usedVertices0Length);

            for (int j = 0; j < usedVertices0Length; j++)
            {
                var brushVertex1 = new float4(usedVertices0[j], 1);
                localVertices[j]     = math.mul(vertexToLocal0, brushVertex1);
                usedVertexIndices[j] = (ushort)j;
            }

            var foundVertexCount = usedVertices0Length;

            for (int j = foundVertexCount - 1; j >= 0; j--)
            {
                if (IsOutsidePlanes(intersectingPlanes1, intersectingPlanesAndEdges1Length, localVertices[j]))
                {
                    if (j < foundVertexCount - 1)
                    {
                        localVertices[j]     = localVertices[foundVertexCount - 1];
                        usedVertexIndices[j] = usedVertexIndices[foundVertexCount - 1];
                    }
                    foundVertexCount--;
                }
            }

            for (int j = 0; j < foundVertexCount; j++)
            {
                var usedVertexIndex = usedVertexIndices[j];
                var segment         = vertexIntersectionSegments[usedVertexIndex];
                if (segment.y == 0)
                {
                    continue;
                }

                var treeSpaceVertex = math.mul(nodeToTreeSpaceMatrix1, localVertices[j]).xyz;
                treeSpaceVertex = snapHashedVertices[snapHashedVertices.AddNoResize(treeSpaceVertex)];
                var treeSpaceVertexIndex = hashedTreeSpaceVertices.AddNoResize(treeSpaceVertex);
                for (int i = segment.x; i < segment.x + segment.y; i++)
                {
                    var planeIndex = vertexIntersectionPlanes[i];

                    // TODO: optimize
                    for (int k = 0; k < foundIndices0Length; k++)
                    {
                        if (foundIndices0[k].planeIndex == planeIndex &&
                            foundIndices0[k].vertexIndex == treeSpaceVertexIndex)
                        {
                            goto skipMe;
                        }
                    }

                    foundIndices0[foundIndices0Length] = new PlaneVertexIndexPair {
                        planeIndex = (ushort)planeIndex, vertexIndex = (ushort)treeSpaceVertexIndex
                    };
                    foundIndices0Length++;
skipMe:
                    ;
                }
            }
        }
        public void Execute(int index)
        {
            var count = input.BeginForEachIndex(index);

            if (count == 0)
            {
                return;
            }

            var brushIndexOrder = input.Read <IndexOrder>();
            var brushNodeOrder  = brushIndexOrder.nodeOrder;
            var vertexCount     = input.Read <int>();

            NativeCollectionHelpers.EnsureCapacityAndClear(ref brushVertices, vertexCount);
            for (int v = 0; v < vertexCount; v++)
            {
                var vertex = input.Read <float3>();
                brushVertices.AddNoResize(vertex);
            }


            var surfaceOuterCount = input.Read <int>();

            NativeCollectionHelpers.EnsureSizeAndClear(ref surfaceLoopIndices, surfaceOuterCount);
            for (int o = 0; o < surfaceOuterCount; o++)
            {
                UnsafeList <int> inner = default;
                var surfaceInnerCount  = input.Read <int>();
                if (surfaceInnerCount > 0)
                {
                    inner = new UnsafeList <int>(surfaceInnerCount, Allocator.Temp);
                    //inner.ResizeUninitialized(surfaceInnerCount);
                    for (int i = 0; i < surfaceInnerCount; i++)
                    {
                        inner.AddNoResize(input.Read <int>());
                    }
                }
                surfaceLoopIndices[o] = inner;
            }

            var surfaceLoopCount = input.Read <int>();

            NativeCollectionHelpers.EnsureMinimumSizeAndClear(ref surfaceLoopAllInfos, surfaceLoopCount);
            NativeCollectionHelpers.EnsureSizeAndClear(ref surfaceLoopAllEdges, surfaceLoopCount);
            for (int l = 0; l < surfaceLoopCount; l++)
            {
                surfaceLoopAllInfos[l] = input.Read <SurfaceInfo>();
                var edgeCount = input.Read <int>();
                if (edgeCount > 0)
                {
                    var edgesInner = new UnsafeList <Edge>(edgeCount, Allocator.Temp);
                    //edgesInner.ResizeUninitialized(edgeCount);
                    for (int e = 0; e < edgeCount; e++)
                    {
                        edgesInner.AddNoResize(input.Read <Edge>());
                    }
                    surfaceLoopAllEdges[l] = edgesInner;
                }
            }
            input.EndForEachIndex();



            if (!basePolygonCache[brushNodeOrder].IsCreated)
            {
                return;
            }

            var maxLoops   = 0;
            var maxIndices = 0;

            for (int s = 0; s < surfaceLoopIndices.Length; s++)
            {
                if (!surfaceLoopIndices[s].IsCreated)
                {
                    continue;
                }
                var length = surfaceLoopIndices[s].Length;
                maxIndices += length;
                maxLoops    = math.max(maxLoops, length);
            }


            ref var baseSurfaces                = ref basePolygonCache[brushNodeOrder].Value.surfaces;
Beispiel #12
0
        // TODO: turn into job
        static void GetIntersectingPlanes(IntersectionType type,
                                          [NoAlias] ref ChiselBlobArray <float4> localPlanes,
                                          int localPlaneCount,
                                          [NoAlias] ref ChiselBlobArray <float3> vertices,
                                          ChiselAABB selfBounds,
                                          float4x4 treeToNodeSpaceInverseTransposed,
                                          [NoAlias] ref NativeArray <int> intersectingPlaneIndices,
                                          [NoAlias] out int intersectingPlaneLength,
                                          [NoAlias] out int intersectingPlanesAndEdgesLength)
        {
            NativeCollectionHelpers.EnsureMinimumSize(ref intersectingPlaneIndices, localPlanes.Length);
            if (type != IntersectionType.Intersection)
            {
                intersectingPlaneLength          = localPlaneCount;
                intersectingPlanesAndEdgesLength = localPlanes.Length;
                for (int i = 0; i < intersectingPlaneLength; i++)
                {
                    intersectingPlaneIndices[i] = i;
                }
                return;
            }

            var min = selfBounds.Min;
            var max = selfBounds.Max;

            //Debug.Log($"{localPlanes.Length}");

            intersectingPlaneLength          = 0;
            intersectingPlanesAndEdgesLength = 0;
            var verticesLength = vertices.Length;

            for (int i = 0; i < localPlanes.Length; i++)
            {
                // bring plane into local space of mesh, the same space as the bounds of the mesh

                var localPlane = localPlanes[i];

                // note: a transpose is part of this transformation
                var transformedPlane = math.mul(treeToNodeSpaceInverseTransposed, localPlane);
                //var normal            = transformedPlane.xyz; // only need the signs, so don't care about normalization
                //transformedPlane /= math.length(normal);      // we don't have to normalize the plane

                var corner = new float4((transformedPlane.x < 0) ? max.x : min.x,
                                        (transformedPlane.y < 0) ? max.y : min.y,
                                        (transformedPlane.z < 0) ? max.z : min.z,
                                        1.0f);
                float forward = math.dot(transformedPlane, corner);
                if (forward > kFatPlaneWidthEpsilon) // closest point is outside
                {
                    intersectingPlaneLength          = 0;
                    intersectingPlanesAndEdgesLength = 0;
                    return;
                }

                // do a bounds check
                corner = new float4((transformedPlane.x >= 0) ? max.x : min.x,
                                    (transformedPlane.y >= 0) ? max.y : min.y,
                                    (transformedPlane.z >= 0) ? max.z : min.z,
                                    1.0f);
                float backward = math.dot(transformedPlane, corner);
                if (backward < -kFatPlaneWidthEpsilon) // closest point is inside
                {
                    continue;
                }

                float minDistance = float.PositiveInfinity;
                float maxDistance = float.NegativeInfinity;
                int   onCount     = 0;
                for (int v = 0; v < verticesLength; v++)
                {
                    float distance = math.dot(transformedPlane, new float4(vertices[v], 1));
                    minDistance = math.min(distance, minDistance);
                    maxDistance = math.max(distance, maxDistance);
                    onCount    += (distance >= -kFatPlaneWidthEpsilon && distance <= kFatPlaneWidthEpsilon) ? 1 : 0;
                }

                // if all vertices are 'inside' this plane, then we're not truly intersecting with it
                if ((minDistance > kFatPlaneWidthEpsilon || maxDistance < -kFatPlaneWidthEpsilon))
                {
                    continue;
                }

                if (i < localPlaneCount)
                {
                    intersectingPlaneIndices[intersectingPlaneLength] = i;
                    intersectingPlaneLength++;
                    intersectingPlanesAndEdgesLength++;
                }
                else
                {
                    intersectingPlaneIndices[intersectingPlanesAndEdgesLength] = i;
                    intersectingPlanesAndEdgesLength++;
                }
            }
        }
Beispiel #13
0
        void GenerateLoop(IndexOrder brushIndexOrder0,
                          IndexOrder brushIndexOrder1,
                          bool invertedTransform,
                          [NoAlias] NativeArray <SurfaceInfo> surfaceInfos,
                          [NoAlias] int surfaceInfosLength,
                          [NoAlias] ref BrushTreeSpacePlanes brushTreeSpacePlanes0,
                          [NoAlias] NativeArray <PlaneVertexIndexPair> foundIndices0,
                          [NoAlias] ref int foundIndices0Length,
                          [NoAlias] ref HashedVertices hashedTreeSpaceVertices,
                          [NoAlias] NativeList <BrushIntersectionLoop> .ParallelWriter outputSurfaces)
        {
            // Why is the unity NativeSort slower than bubble sort?
            for (int i = 0; i < foundIndices0Length - 1; i++)
            {
                for (int j = i + 1; j < foundIndices0Length; j++)
                {
                    var x = foundIndices0[i];
                    var y = foundIndices0[j];
                    if (x.planeIndex > y.planeIndex)
                    {
                        continue;
                    }
                    if (x.planeIndex == y.planeIndex)
                    {
                        if (x.vertexIndex <= y.vertexIndex)
                        {
                            continue;
                        }
                    }

                    var t = x;
                    foundIndices0[i] = foundIndices0[j];
                    foundIndices0[j] = t;
                }
            }


            NativeCollectionHelpers.EnsureMinimumSize(ref planeIndexOffsets, foundIndices0Length);
            NativeCollectionHelpers.EnsureMinimumSize(ref uniqueIndices, foundIndices0Length);

            var planeIndexOffsetsLength = 0;
            //var planeIndexOffsets       = stackalloc PlaneIndexOffsetLength[foundIndices0Length];
            var uniqueIndicesLength = 0;
            //var uniqueIndices           = stackalloc ushort[foundIndices0Length];

            // Now that our indices are sorted by planeIndex, we can segment them by start/end offset
            var previousPlaneIndex  = foundIndices0[0].planeIndex;
            var previousVertexIndex = foundIndices0[0].vertexIndex;

            uniqueIndices[uniqueIndicesLength] = previousVertexIndex;
            uniqueIndicesLength++;
            var loopStart = 0;

            for (int i = 1; i < foundIndices0Length; i++)
            {
                var indices = foundIndices0[i];

                var planeIndex  = indices.planeIndex;
                var vertexIndex = indices.vertexIndex;

                // TODO: why do we have soooo many duplicates sometimes?
                if (planeIndex == previousPlaneIndex &&
                    vertexIndex == previousVertexIndex)
                {
                    continue;
                }

                if (planeIndex != previousPlaneIndex)
                {
                    var currLength = (uniqueIndicesLength - loopStart);
                    if (currLength > 2)
                    {
                        planeIndexOffsets[planeIndexOffsetsLength] = new PlaneIndexOffsetLength
                        {
                            length     = (ushort)currLength,
                            offset     = (ushort)loopStart,
                            planeIndex = previousPlaneIndex
                        };
                        planeIndexOffsetsLength++;
                    }
                    loopStart = uniqueIndicesLength;
                }

                uniqueIndices[uniqueIndicesLength] = vertexIndex;
                uniqueIndicesLength++;
                previousVertexIndex = vertexIndex;
                previousPlaneIndex  = planeIndex;
            }
            {
                var currLength = (uniqueIndicesLength - loopStart);
                if (currLength > 2)
                {
                    planeIndexOffsets[planeIndexOffsetsLength] = new PlaneIndexOffsetLength
                    {
                        length     = (ushort)currLength,
                        offset     = (ushort)loopStart,
                        planeIndex = previousPlaneIndex
                    };
                    planeIndexOffsetsLength++;
                }
            }

            var maxLength = 0;

            for (int i = 0; i < planeIndexOffsetsLength; i++)
            {
                maxLength = math.max(maxLength, planeIndexOffsets[i].length);
            }

            NativeCollectionHelpers.EnsureMinimumSize(ref sortedStack, maxLength * 2);

            // For each segment, we now sort our vertices within each segment,
            // making the assumption that they are convex
            //var sortedStack = stackalloc int2[maxLength * 2];
            var vertices = hashedTreeSpaceVertices;//.GetUnsafeReadOnlyPtr();

            for (int n = planeIndexOffsetsLength - 1; n >= 0; n--)
            {
                var planeIndexOffset = planeIndexOffsets[n];
                var length           = planeIndexOffset.length;
                var offset           = planeIndexOffset.offset;
                var planeIndex       = planeIndexOffset.planeIndex;

                float3 normal = brushTreeSpacePlanes0.treeSpacePlanes[planeIndex].xyz * (invertedTransform ? 1 : -1);

                // TODO: use plane information instead
                SortIndices(vertices, sortedStack, uniqueIndices, offset, length, normal);
            }


            var totalLoopsSize = 16 + (planeIndexOffsetsLength * UnsafeUtility.SizeOf <BrushIntersectionLoop>());
            var totalSize      = totalLoopsSize;

            for (int j = 0; j < planeIndexOffsetsLength; j++)
            {
                var planeIndexLength = planeIndexOffsets[j];
                var loopLength       = planeIndexLength.length;
                totalSize += (loopLength * UnsafeUtility.SizeOf <float3>());
            }

            var srcVertices = hashedTreeSpaceVertices;

            for (int j = 0; j < planeIndexOffsetsLength; j++)
            {
                var planeIndexLength = planeIndexOffsets[j];
                var offset           = planeIndexLength.offset;
                var loopLength       = planeIndexLength.length;
                var basePlaneIndex   = planeIndexLength.planeIndex;
                var surfaceInfo      = surfaceInfos[basePlaneIndex];

                NativeCollectionHelpers.EnsureMinimumSize(ref temporaryVertices, loopLength);
                for (int d = 0; d < loopLength; d++)
                {
                    temporaryVertices[d] = srcVertices[uniqueIndices[offset + d]];
                }

                outputSurfaces.AddNoResize(new BrushIntersectionLoop
                {
                    indexOrder0     = brushIndexOrder0,
                    indexOrder1     = brushIndexOrder1,
                    surfaceInfo     = surfaceInfo,
                    loopVertexIndex = outputSurfaceVertices.AddRangeNoResize(temporaryVertices.GetUnsafePtr(), loopLength),
                    loopVertexCount = loopLength
                });
            }
        }