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 FindIntersectionVertices(ref BlobArray <float4> intersectingPlanes0,
                                      ref BlobArray <float4> intersectingPlanes1,
                                      ref BlobArray <PlanePair> usedPlanePairs1,
                                      ref BlobArray <int> intersectingPlaneIndices0,
                                      float4x4 nodeToTreeSpaceMatrix0,
                                      //ref HashedVertices              hashedVertices,
                                      NativeArray <PlaneVertexIndexPair> foundIndices0,
                                      ref int foundIndices0Length,
                                      NativeArray <PlaneVertexIndexPair> foundIndices1,
                                      ref int foundIndices1Length)
        {
            var foundVertices      = new NativeArray <float4>(usedPlanePairs1.Length * intersectingPlanes0.Length, Allocator.Temp);
            var foundEdges         = new NativeArray <IntersectionEdge>(usedPlanePairs1.Length * intersectingPlanes0.Length, Allocator.Temp);
            var foundIntersections = new NativeArray <IntersectionPlanes>(usedPlanePairs1.Length * intersectingPlanes0.Length, Allocator.Temp);
            var n = 0;

            for (int i = 0; i < usedPlanePairs1.Length; i++)
            {
                for (int j = 0; j < intersectingPlanes0.Length; j++)
                {
                    foundIntersections[n] = new IntersectionPlanes
                    {
                        plane0      = usedPlanePairs1[i].plane0,
                        plane1      = usedPlanePairs1[i].plane1,
                        plane2      = intersectingPlanes0[j],
                        planeIndex0 = usedPlanePairs1[i].planeIndex0,
                        planeIndex1 = usedPlanePairs1[i].planeIndex1,
                        planeIndex2 = intersectingPlaneIndices0[j]
                    };

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

                    var plane0 = usedPlanePairs1[i].plane0;
                    var plane1 = usedPlanePairs1[i].plane1;
                    var plane2 = intersectingPlanes0[j];

                    foundVertices[n] = new float4(PlaneExtensions.Intersection(plane2, plane0, plane1), 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)) <= kDistanceEpsilon &&
                    math.abs(math.dot(plane2, edgeVertex1)) <= kDistanceEpsilon)
                {
                    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(ref intersectingPlanes0, foundVertices[k]) ||
                    IsOutsidePlanes(ref intersectingPlanes1, 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;
                var vertexIndex     = hashedVertices.AddNoResize(treeSpaceVertex);

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

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

                foundIndices1[foundIndices1Length] = new PlaneVertexIndexPair {
                    planeIndex = planeIndex1, vertexIndex = vertexIndex
                };
                foundIndices1Length++;
            }
        }