Exemple #1
0
        protected override void OnUpdate()
        {
            var surface = surfaceOutputSlot.GetAsset <SphericalSurface>();

            if (surface == null)
            {
                surface = surfaceOutputSlot.SetAsset(CreateInstance <SphericalSurface>(), false);
            }
            surface.Reset(Vector3.up, Vector3.right, 1f, false);
        }
        public override IEnumerator BeginGeneration()
        {
            var topology      = topologyInputSlot.GetAsset <Topology>();
            var vertexNormals = Vector3VertexAttribute.Create(new Vector3[topology.vertices.Count]).SetName("Vertex Normals");

            yield return(executive.GenerateConcurrently(() =>
            {
                switch (calculationMethod)
                {
                case CalculationMethod.FromSurfaceNormal:
                    VertexAttributeUtility.CalculateVertexNormalsFromSurface(topology.vertices, surfaceInputSlot.GetAsset <Surface>(), vertexPositionsInputSlot.GetAsset <IVertexAttribute <Vector3> >(), vertexNormals);
                    break;

                case CalculationMethod.FromVertexPositions:
                    VertexAttributeUtility.CalculateVertexNormalsFromVertexPositions(topology.vertices, vertexPositionsInputSlot.GetAsset <IVertexAttribute <Vector3> >(), vertexNormals);
                    break;

                case CalculationMethod.FromFacePositions:
                    VertexAttributeUtility.CalculateVertexNormalsFromFacePositions(topology.vertices, facePositionsInputSlot.GetAsset <IFaceAttribute <Vector3> >(), vertexNormals);
                    break;

                case CalculationMethod.FromFaceNormals:
                    VertexAttributeUtility.CalculateVertexNormalsFromFaceNormals(topology.vertices, faceNormalsInputSlot.GetAsset <IFaceAttribute <Vector3> >(), vertexNormals);
                    break;

                default:
                    throw new System.NotImplementedException();
                }
            }));

            vertexNormalsOutputSlot.SetAsset(vertexNormals);

            yield break;
        }
Exemple #3
0
        public override IEnumerator BeginGeneration()
        {
            var surface         = surfaceInputSlot.GetAsset <Surface>();
            var topology        = topologyInputSlot.GetAsset <Topology>();
            var vertexPositions = vertexPositionsInputSlot.GetAsset <IVertexAttribute <Vector3> >();
            var faceCentroids   = PositionalFaceAttribute.Create(surface, new Vector3[topology.internalFaces.Count]).SetName("Face Centroids");

            yield return(executive.GenerateConcurrently(() =>
            {
                if (flatten || surface is QuadrilateralSurface)
                {
                    FaceAttributeUtility.CalculateFaceCentroidsFromVertexPositions(topology.internalFaces, vertexPositions, faceCentroids);
                }
                else if (surface is SphericalSurface)
                {
                    var sphericalSurface = (SphericalSurface)surface;
                    FaceAttributeUtility.CalculateSphericalFaceCentroidsFromVertexPositions(topology.internalFaces, sphericalSurface, vertexPositions, faceCentroids);
                }
                else
                {
                    throw new System.NotImplementedException();
                }
            }));

            faceCentroidsOutputSlot.SetAsset(faceCentroids);

            yield break;
        }
Exemple #4
0
        public override IEnumerator BeginGeneration()
        {
            var partitioning = UniversalFaceSpatialPartitioning.Create(
                surfaceInputSlot.GetAsset <Surface>(),
                topologyInputSlot.GetAsset <Topology>(),
                vertexPositionsInputSlot.GetAsset <IVertexAttribute <Vector3> >());

            partitioningOutputSlot.SetAsset(partitioning);
            yield break;
        }
Exemple #5
0
        public override IEnumerator BeginGeneration()
        {
            var surface         = surfaceInputSlot.GetAsset <Surface>();
            var topology        = topologyInputSlot.GetAsset <Topology>();
            var vertexPositions = vertexPositionsInputSlot.GetAsset <IEdgeAttribute <Vector3> >();
            var facePositions   = facePositionsInputSlot.GetAsset <IFaceAttribute <Vector3> >();
            var bisectors       = Vector3EdgeAttribute.Create(topology.faceEdges.Count);

            EdgeAttributeUtility.CalculateFaceEdgeBisectorsFromVertexPositions(topology.internalFaces, surface, vertexPositions, facePositions, bisectors);
            bisectorsOutputSlot.SetAsset(bisectors);

            yield break;
        }
        private void CreateQuadGridManifold(bool generate = true)
        {
            var surface = surfaceOutputSlot.GetAsset <RectangularQuadGrid>();

            if (surface == null || !generate && ReferenceEquals(surface, surfaceOutputSlot.persistedAsset))
            {
                surface = surfaceOutputSlot.SetAsset(CreateInstance <RectangularQuadGrid>(), false);
            }

            ResetSurface(surface, origin, Quaternion.Euler(rotation), false, size);

            if (generate)
            {
                Vector3[] vertexPositionsArray;

                var topology = surface.CreateManifold(out vertexPositionsArray);
                topologyOutputSlot.SetAsset(topology);

                surface.topology = topologyOutputSlot.GetAsset <Topology>();
                surfaceOutputSlot.Persist();

                vertexPositionsOutputSlot.SetAsset(PositionalVertexAttribute.Create(surfaceOutputSlot.GetAsset <Surface>(), vertexPositionsArray));
            }
        }
Exemple #7
0
        public override IEnumerator BeginGeneration()
        {
            var topology        = topologyInputSlot.GetAsset <Topology>();
            var vertexPositions = vertexPositionsInputSlot.GetAsset <IEdgeAttribute <Vector3> >();
            var offsets         = offsetsInputSlot.GetAsset <IEdgeAttribute <Vector3> >();
            var offsetPositions = Vector3EdgeAttribute.Create(topology.faceEdges.Count);

            foreach (var edge in topology.faceEdges)
            {
                offsetPositions[edge] = vertexPositions[edge] + offsets[edge] * scale;
            }
            offsetVertexPositionsOutputSlot.SetAsset(offsetPositions);

            yield break;
        }
Exemple #8
0
        private void GenerateRandomPerGroup()
        {
            var faceGroupCollection  = faceGroupCollectionInputSlot.GetAsset <FaceGroupCollection>();
            var faceGroups           = faceGroupCollection.faceGroups;
            var faceGroupColorsArray = new Color[faceGroups.Length];

            var random = randomness.GetRandom();

            for (int i = 0; i < faceGroups.Length; ++i)
            {
#if MAKEIT_COLORFUL_2_0_OR_NEWER
                faceGroupColorsArray[i] = random.ColorRGB();
#else
                faceGroupColorsArray[i] = new Color(random.FloatCC(), random.FloatCC(), random.FloatCC());
#endif
            }

            faceGroupColorsOutputSlot.SetAsset(ColorFaceGroupAttribute.Create(faceGroupColorsArray).SetName((faceGroupCollection.name + " Colors").TrimStart()));
            faceColorsOutputSlot.SetAsset(ColorFaceGroupLookupFaceAttribute.Create(
                                              faceGroupIndicesInputSlot.GetAsset <IntFaceAttribute>(),
                                              faceGroupColorsOutputSlot.GetAsset <ColorFaceGroupAttribute>()).SetName("Face Colors"));
        }
Exemple #9
0
        public override IEnumerator BeginGeneration()
        {
            var topology = topologyInputSlot.GetAsset <Topology>();

            var vertexAttributeSources = new VertexAttributeSources();

            vertexAttributeSources.ringPositions   = VertexAttributeSources.GetRingAttributes <Vector3>(topology, ringVertexPositionsInputSlots);
            vertexAttributeSources.ringNormals     = VertexAttributeSources.GetRingAttributes <Vector3>(topology, ringVertexNormalsInputSlots);
            vertexAttributeSources.ringColors      = VertexAttributeSources.GetRingAttributes <Color>(topology, ringVertexColorsInputSlots);
            vertexAttributeSources.ringColor32s    = VertexAttributeSources.GetRingAttributes <Color32>(topology, ringVertexColor32sInputSlots);
            vertexAttributeSources.ringUV1s        = VertexAttributeSources.GetRingAttributes <Vector2>(topology, ringVertexUV1sInputSlots);
            vertexAttributeSources.ringUV2s        = VertexAttributeSources.GetRingAttributes <Vector2>(topology, ringVertexUV2sInputSlots);
            vertexAttributeSources.ringUV3s        = VertexAttributeSources.GetRingAttributes <Vector2>(topology, ringVertexUV3sInputSlots);
            vertexAttributeSources.ringUV4s        = VertexAttributeSources.GetRingAttributes <Vector2>(topology, ringVertexUV4sInputSlots);
            vertexAttributeSources.ringTangents    = VertexAttributeSources.GetRingAttributes <Vector4>(topology, ringVertexTangentsInputSlots);
            vertexAttributeSources.centerPositions = VertexAttributeSources.GetCenterAttributes <Vector3>(centerVertexPositionsInputSlots);
            vertexAttributeSources.centerNormals   = VertexAttributeSources.GetCenterAttributes <Vector3>(centerVertexNormalsInputSlots);
            vertexAttributeSources.centerColors    = VertexAttributeSources.GetCenterAttributes <Color>(centerVertexColorsInputSlots);
            vertexAttributeSources.centerColor32s  = VertexAttributeSources.GetCenterAttributes <Color32>(centerVertexColor32sInputSlots);
            vertexAttributeSources.centerUV1s      = VertexAttributeSources.GetCenterAttributes <Vector2>(centerVertexUV1sInputSlots);
            vertexAttributeSources.centerUV2s      = VertexAttributeSources.GetCenterAttributes <Vector2>(centerVertexUV2sInputSlots);
            vertexAttributeSources.centerUV3s      = VertexAttributeSources.GetCenterAttributes <Vector2>(centerVertexUV3sInputSlots);
            vertexAttributeSources.centerUV4s      = VertexAttributeSources.GetCenterAttributes <Vector2>(centerVertexUV4sInputSlots);
            vertexAttributeSources.centerTangents  = VertexAttributeSources.GetCenterAttributes <Vector4>(centerVertexTangentsInputSlots);

            System.Action <Topology.FaceEdge, DynamicMesh.IIndexedVertexAttributes> setRingVertexAttributes =
                (Topology.FaceEdge edge, DynamicMesh.IIndexedVertexAttributes va) =>
            {
                for (int i = 0; i < ringDepth; ++i)
                {
                    if (vertexAttributeSources.ringPositions != null)
                    {
                        va.position = vertexAttributeSources.ringPositions[i][edge];
                    }
                    if (vertexAttributeSources.ringNormals != null)
                    {
                        va.normal = vertexAttributeSources.ringNormals[i][edge];
                    }
                    if (vertexAttributeSources.ringColors != null)
                    {
                        va.color = vertexAttributeSources.ringColors[i][edge];
                    }
                    if (vertexAttributeSources.ringColor32s != null)
                    {
                        va.color32 = vertexAttributeSources.ringColor32s[i][edge];
                    }
                    if (vertexAttributeSources.ringUV1s != null)
                    {
                        va.uv1 = vertexAttributeSources.ringUV1s[i][edge];
                    }
                    if (vertexAttributeSources.ringUV2s != null)
                    {
                        va.uv2 = vertexAttributeSources.ringUV2s[i][edge];
                    }
                    if (vertexAttributeSources.ringUV3s != null)
                    {
                        va.uv3 = vertexAttributeSources.ringUV3s[i][edge];
                    }
                    if (vertexAttributeSources.ringUV4s != null)
                    {
                        va.uv4 = vertexAttributeSources.ringUV4s[i][edge];
                    }
                    if (vertexAttributeSources.ringTangents != null)
                    {
                        va.tangent = vertexAttributeSources.ringTangents[i][edge];
                    }
                    va.Advance();
                }
            };

            System.Action <Topology.Face, DynamicMesh.IIndexedVertexAttributes> setCenterVertexAttributes =
                (Topology.Face face, DynamicMesh.IIndexedVertexAttributes va) =>
            {
                if (vertexAttributeSources.centerPositions != null)
                {
                    va.position = vertexAttributeSources.centerPositions[face];
                }
                if (vertexAttributeSources.centerNormals != null)
                {
                    va.normal = vertexAttributeSources.centerNormals[face];
                }
                if (vertexAttributeSources.centerColors != null)
                {
                    va.color = vertexAttributeSources.centerColors[face];
                }
                if (vertexAttributeSources.centerColor32s != null)
                {
                    va.color32 = vertexAttributeSources.centerColor32s[face];
                }
                if (vertexAttributeSources.centerUV1s != null)
                {
                    va.uv1 = vertexAttributeSources.centerUV1s[face];
                }
                if (vertexAttributeSources.centerUV2s != null)
                {
                    va.uv2 = vertexAttributeSources.centerUV2s[face];
                }
                if (vertexAttributeSources.centerUV3s != null)
                {
                    va.uv3 = vertexAttributeSources.centerUV3s[face];
                }
                if (vertexAttributeSources.centerUV4s != null)
                {
                    va.uv4 = vertexAttributeSources.centerUV4s[face];
                }
                if (vertexAttributeSources.centerTangents != null)
                {
                    va.tangent = vertexAttributeSources.centerTangents[face];
                }
                va.Advance();
            };

            DynamicMesh.ITriangulation triangulationInstance = null;

            switch (triangulation)
            {
            case Triangulation.Strip:
                triangulationInstance = new SeparatedFacesStripTriangulation(ringDepth, setRingVertexAttributes);
                break;

            case Triangulation.Fan:
                triangulationInstance = new SeparatedFacesFanTriangulation(ringDepth, setRingVertexAttributes);
                break;

            case Triangulation.Umbrella:
                triangulationInstance = new SeparatedFacesUmbrellaTriangulation(ringDepth, setRingVertexAttributes, setCenterVertexAttributes);
                break;

            default:
                throw new System.NotImplementedException();
            }

            DynamicMesh dynamicMesh;

            switch (sourceType)
            {
            case SourceType.InternalFaces:
                dynamicMesh = DynamicMesh.Create(topology.enumerableInternalFaces, vertexAttributes, triangulationInstance, maxVerticesPerSubmesh);
                break;

            case SourceType.FaceGroupCollection:
                dynamicMesh = DynamicMesh.Create(faceGroupCollectionInputSlot.GetAsset <FaceGroupCollection>(), vertexAttributes, triangulationInstance, maxVerticesPerSubmesh);
                break;

            case SourceType.FaceGroup:
                dynamicMesh = DynamicMesh.Create(faceGroupInputSlot.GetAsset <FaceGroup>(), vertexAttributes, triangulationInstance, maxVerticesPerSubmesh);
                break;

            default:
                throw new System.NotImplementedException();
            }

            if (meshOutputSlots.Length != dynamicMesh.submeshCount)
            {
                var newMeshes = new OutputSlot[dynamicMesh.submeshCount];

                System.Array.Copy(meshOutputSlots, newMeshes, Mathf.Min(meshOutputSlots.Length, newMeshes.Length));
                for (var i = meshOutputSlots.Length; i < newMeshes.Length; ++i)
                {
                    newMeshes[i] = OutputSlot.CreateGrouped <Mesh>(this, "Mesh", "Meshes");
                }

                meshOutputSlots = newMeshes;
            }

            if (meshOutputSlots.Length == 1)
            {
                meshOutputSlots[0].name = "Mesh";
            }
            else if (meshOutputSlots.Length > 1)
            {
                for (int i = 0; i < meshOutputSlots.Length; ++i)
                {
                    meshOutputSlots[i].name = string.Format("Submesh {0}", i);
                }
            }

            for (int i = 0; i < meshOutputSlots.Length; ++i)
            {
                meshOutputSlots[i].SetAsset(dynamicMesh.GetSubmesh(i));
                dynamicMesh.ReplaceSubmesh(i, meshOutputSlots[i].GetAsset <Mesh>());
            }

            dynamicMeshOutputSlot.SetAsset(dynamicMesh);

            yield break;
        }
Exemple #10
0
 private void GenerateConstant()
 {
     faceColorsOutputSlot.SetAsset(ConstantColorFaceAttribute.Create(constantColor));
 }
Exemple #11
0
        public override IEnumerator BeginGeneration()
        {
            var surface = surfaceOutputSlot.GetAsset <SphericalSurface>();

            if (surface == null)
            {
                surface = surfaceOutputSlot.SetAsset(CreateInstance <SphericalSurface>(), false);
            }
            surface.Reset(primaryPole, equatorialPole, radius, isInverted);

            Topology topology;

            Vector3[] vertexPositions;

            switch (sphericalPolyhedron)
            {
            case SphericalPolyhedrons.Tetrahedron:
                SphericalManifoldUtility.CreateTetrahedron(surface, out topology, out vertexPositions);
                break;

            case SphericalPolyhedrons.Cube:
                SphericalManifoldUtility.CreateCube(surface, out topology, out vertexPositions);
                break;

            case SphericalPolyhedrons.Octahedron:
                SphericalManifoldUtility.CreateOctahedron(surface, out topology, out vertexPositions);
                break;

            case SphericalPolyhedrons.Dodecahedron:
                if (subdivisionDegree == 0)
                {
                    SphericalManifoldUtility.CreateDodecahedron(surface, out topology, out vertexPositions);
                }
                else
                {
                    SphericalManifoldUtility.CreateIcosahedron(surface, out topology, out vertexPositions);
                }
                break;

            case SphericalPolyhedrons.Icosahedron:
                SphericalManifoldUtility.CreateIcosahedron(surface, out topology, out vertexPositions);
                break;

            default:
                throw new System.NotImplementedException();
            }

            SphericalManifoldUtility.Subdivide(surface, topology, vertexPositions.AsVertexAttribute(), subdivisionDegree, out topology, out vertexPositions);

            var alreadyDual = sphericalPolyhedron == SphericalPolyhedrons.Dodecahedron && subdivisionDegree != 0;

            if (useDualPolyhedron != alreadyDual)
            {
                SphericalManifoldUtility.MakeDual(surface, topology, ref vertexPositions);
            }

            surfaceOutputSlot.Persist();
            topologyOutputSlot.SetAsset(topology);
            vertexPositionsOutputSlot.SetAsset(Vector3VertexAttribute.Create(vertexPositions).SetName("Vertex Positions"));

            yield break;
        }
Exemple #12
0
        public override IEnumerator BeginGeneration()
        {
            GameObject prefab;

            var dynamicMesh = dynamicMeshInputSlot.GetAsset <DynamicMesh>();

            if (dynamicMesh.submeshCount == 0)
            {
                if (meshPrefab == null)
                {
                    prefab = new GameObject();
                    prefab.AddComponent <MeshFilter>();
                    prefab.AddComponent <MeshRenderer>();
                }
                else
                {
                    prefab = Instantiate(meshPrefab).gameObject;
                }
            }
            else if (dynamicMesh.submeshCount == 1)
            {
                if (meshPrefab == null)
                {
                    prefab = new GameObject();
                    prefab.AddComponent <MeshFilter>().mesh = dynamicMesh.GetSubmesh(0);
                    prefab.AddComponent <MeshRenderer>();
                }
                else
                {
                    var meshFilter = Instantiate(meshPrefab);
                    meshFilter.mesh = dynamicMesh.GetSubmesh(0);
                    prefab          = meshFilter.gameObject;
                }
            }
            else
            {
                prefab = new GameObject();
                if (meshPrefab == null)
                {
                    for (int i = 0; i < dynamicMesh.submeshCount; ++i)
                    {
                        var submeshInstance = new GameObject();
                        submeshInstance.name = string.Format("Mesh {0}", i);
                        submeshInstance.AddComponent <MeshFilter>().mesh = dynamicMesh.GetSubmesh(i);
                        submeshInstance.AddComponent <MeshRenderer>();
                        submeshInstance.transform.SetParent(prefab.transform, false);
                    }
                }
                else
                {
                    for (int i = 0; i < dynamicMesh.submeshCount; ++i)
                    {
                        var meshFilter = Instantiate(meshPrefab);
                        meshFilter.name = string.Format("Mesh {0}", i);
                        meshFilter.mesh = dynamicMesh.GetSubmesh(i);
                        meshFilter.transform.SetParent(prefab.transform, false);
                    }
                }
            }

            prefab.name = name;

            prefabOutputSlot.SetAsset(prefab);

            yield break;
        }
        public override IEnumerator BeginGeneration()
        {
            var topology         = topologyInputSlot.GetAsset <Topology>();
            var faceGroupIndices = new int[topology.internalFaces.Count].AsFaceAttribute();

            List <int>[] faceGroupFaceIndices;

            var random = randomness.GetRandom();

            var clampedRootCount = Mathf.Clamp(groupCount, 1, topology.internalFaces.Count);

            faceGroupFaceIndices = new List <int> [clampedRootCount];

            var waitHandle = executive.GenerateConcurrently(() =>
            {
                var rootFaces     = new List <Topology.Face>();
                var rootFaceEdges = new List <Topology.FaceEdge>();

                for (int faceGroupIndex = 0; faceGroupIndex < clampedRootCount; ++faceGroupIndex)
                {
                    faceGroupFaceIndices[faceGroupIndex] = new List <int>();

                    Topology.Face face;
                    do
                    {
                        face = topology.internalFaces[random.Index(topology.internalFaces.Count)];
                    } while (rootFaces.Contains(face));
                    rootFaces.Add(face);
                    foreach (var edge in face.edges)
                    {
                        if (edge.face.isInternal)
                        {
                            rootFaceEdges.Add(edge);
                        }
                    }
                    faceGroupIndices[face] = faceGroupIndex;
                    faceGroupFaceIndices[faceGroupIndex].Add(face.index);
                }

                TopologyVisitor.VisitFacesInRandomOrder(
                    rootFaceEdges,
                    (FaceEdgeVisitor visitor) =>
                {
                    var faceGroupIndex             = faceGroupIndices[visitor.edge.nearFace];
                    faceGroupIndices[visitor.edge] = faceGroupIndex;
                    faceGroupFaceIndices[faceGroupIndex].Add(visitor.edge.face.index);

                    visitor.VisitInternalNeighborsExceptSource();
                },
                    random);
            });

            while (waitHandle.WaitOne(10) == false)
            {
                yield return(null);
            }

            faceGroupOutputSlots = GeneratorUtility.ResizeArray(faceGroupOutputSlots, faceGroupFaceIndices.Length,
                                                                (int index) =>
            {
                return(OutputSlot.CreateGrouped <FaceGroup>(this, string.Format("Face Group {0}", index), faceGroupCollectionOutputSlot.name, true, OutputSlot.Availability.DuringGeneration));
            },
                                                                (OutputSlot output, int index) =>
            {
                output.DisconnectAll();
                output.path = faceGroupCollectionOutputSlot.name;
                return(output);
            });

            var faceGroupCollection = FaceGroupCollection.Create(faceGroupFaceIndices.Length);

            for (int faceGroupIndex = 0; faceGroupIndex < faceGroupFaceIndices.Length; ++faceGroupIndex)
            {
                var faceGroup = ArrayFaceGroup.Create(topology, faceGroupFaceIndices[faceGroupIndex].ToArray()).SetName(faceGroupOutputSlots[faceGroupIndex].name);
                faceGroupCollection.faceGroups[faceGroupIndex] = faceGroupOutputSlots[faceGroupIndex].SetAsset(faceGroup);
            }

            faceGroupCollectionOutputSlot.SetAsset(faceGroupCollection);
            faceGroupIndicesOutputSlot.SetAsset(IntFaceAttribute.Create(faceGroupIndices.array));

            yield break;
        }
Exemple #14
0
        public override IEnumerator BeginGeneration()
        {
            var surface       = surfaceInputSlot.GetAsset <QuadrilateralSurface>();
            var topology      = topologyInputSlot.GetAsset <Topology>();
            var facePositions = facePositionsInputSlot.GetAsset <IFaceAttribute <Vector3> >();

            int groupCount           = 0;
            var faceGroupFaceIndices = new List <int> [axisDivisions.x * axisDivisions.y];

            var waitHandle = executive.GenerateConcurrently(() =>
            {
                var axis0Vector        = surface.axis0.vector;
                var axis1Vector        = surface.axis1.vector;
                var surfaceNormal      = Vector3.Cross(axis0Vector, axis1Vector).normalized;
                var axis0Normal        = Vector3.Cross(axis0Vector, surfaceNormal).normalized;
                var axis1Normal        = Vector3.Cross(axis1Vector, surfaceNormal).normalized;
                var axis0DividedVector = axis0Vector / axisDivisions.x;
                var axis1DividedVector = axis1Vector / axisDivisions.y;
                var axis0Dot           = Vector3.Dot(axis1Normal, axis0DividedVector);
                var axis1Dot           = Vector3.Dot(axis0Normal, axis1DividedVector);
                var origin             = surface.origin;

                for (int i = 0; i < faceGroupFaceIndices.Length; ++i)
                {
                    faceGroupFaceIndices[i] = new List <int>();
                }

                foreach (var face in topology.internalFaces)
                {
                    var facePosition = facePositions[face];

                    var axis0Offset = Vector3.Dot(axis1Normal, facePosition - origin) / axis0Dot;
                    var axis1Offset = Vector3.Dot(axis0Normal, facePosition - origin) / axis1Dot;

                    var axis0Index = Mathf.Clamp(Mathf.FloorToInt(axis0Offset), 0, axisDivisions.x - 1);
                    var axis1Index = Mathf.Clamp(Mathf.FloorToInt(axis1Offset), 0, axisDivisions.y - 1);

                    faceGroupFaceIndices[axis0Index + axis1Index * axisDivisions.x].Add(face.index);
                }

                foreach (var group in faceGroupFaceIndices)
                {
                    if (group.Count > 0)
                    {
                        ++groupCount;
                    }
                }
            });

            while (waitHandle.WaitOne(10) == false)
            {
                yield return(null);
            }

            faceGroupOutputSlots = GeneratorUtility.ResizeArray(faceGroupOutputSlots, groupCount,
                                                                (int index) =>
            {
                return(null);
            },
                                                                (OutputSlot output, int index) =>
            {
                output.DisconnectAll();
                return(output);
            });

            var faceGroupCollection = FaceGroupCollection.Create(groupCount);

            var faceGroupIndices = new int[topology.internalFaces.Count];

            var groupIndex = 0;

            for (int axis1Index = 0; axis1Index < axisDivisions.y; ++axis1Index)
            {
                for (int axis0Index = 0; axis0Index < axisDivisions.x; ++axis0Index)
                {
                    var group = faceGroupFaceIndices[axis0Index + axis1Index * axisDivisions.x];
                    if (group.Count > 0)
                    {
                        var faceGroupName = string.Format("Face Group [{0}, {1}]", axis0Index, axis1Index);
                        var faceGroup     = ArrayFaceGroup.Create(topology, group.ToArray()).SetName(faceGroupName);

                        if (faceGroupOutputSlots[groupIndex] == null)
                        {
                            faceGroupOutputSlots[groupIndex] = OutputSlot.CreateGrouped <FaceGroup>(this, faceGroupName, faceGroupCollectionOutputSlot.name, true, OutputSlot.Availability.DuringGeneration);
                        }
                        else
                        {
                            faceGroupOutputSlots[groupIndex].name = faceGroupName;
                            faceGroupOutputSlots[groupIndex].path = faceGroupCollectionOutputSlot.name;
                        }

                        faceGroupCollection.faceGroups[groupIndex] = faceGroupOutputSlots[groupIndex].SetAsset(faceGroup);

                        foreach (var faceIndex in group)
                        {
                            faceGroupIndices[faceIndex] = groupIndex;
                        }

                        ++groupIndex;
                    }
                }
            }

            faceGroupCollectionOutputSlot.SetAsset(faceGroupCollection);
            faceGroupIndicesOutputSlot.SetAsset(IntFaceAttribute.Create(faceGroupIndices));

            yield break;
        }