private IEnumerator CreateInitialDistanceConstraints(List <int> edges)
        {
            List <int> particleIndices   = new List <int>();
            List <int> constraintIndices = new List <int>();

            for (int i = 0; i < edges.Count; i++)
            {
                HalfEdgeMesh.HalfEdge hedge = topology.halfEdges[edges[i]];

                // ignore borders:
                if (hedge.face < 0)
                {
                    continue;
                }

                particleIndices.Add(topology.GetHalfEdgeStartVertex(hedge));
                particleIndices.Add(hedge.endVertex);
                constraintIndices.Add(constraintIndices.Count * 2);

                if (i % 500 == 0)
                {
                    yield return(new CoroutineJob.ProgressInfo("ObiCloth: generating structural constraints...", i / (float)topology.halfEdges.Count));
                }
            }
            constraintIndices.Add(constraintIndices.Count * 2);

            int[] constraintColors = GraphColoring.Colorize(particleIndices.ToArray(), constraintIndices.ToArray());

            for (int i = 0; i < constraintColors.Length; ++i)
            {
                int color  = constraintColors[i];
                int cIndex = constraintIndices[i];

                // Add a new batch if needed:
                if (color >= distanceConstraintsData.GetBatchCount())
                {
                    distanceConstraintsData.AddBatch(new ObiDistanceConstraintsBatch());
                }

                HalfEdgeMesh.HalfEdge hedge       = topology.halfEdges[edges[i]];
                HalfEdgeMesh.Vertex   startVertex = topology.vertices[topology.GetHalfEdgeStartVertex(hedge)];
                HalfEdgeMesh.Vertex   endVertex   = topology.vertices[hedge.endVertex];

                distanceConstraintsData.batches[color].AddConstraint(new Vector2Int(particleIndices[cIndex], particleIndices[cIndex + 1]),
                                                                     Vector3.Distance(Vector3.Scale(scale, startVertex.position), Vector3.Scale(scale, endVertex.position)));


                distanceConstraintMap[hedge.index] = new Vector2Int(color, distanceConstraintsData.batches[color].constraintCount - 1);
            }

            // Set initial amount of active constraints:
            for (int i = 0; i < distanceConstraintsData.batches.Count; ++i)
            {
                distanceConstraintsData.batches[i].activeConstraintCount = distanceConstraintsData.batches[i].constraintCount;
            }
        }
Beispiel #2
0
        protected virtual IEnumerator CreateShapeMatchingConstraints(List <Vector3> particles)
        {
            //Create shape matching clusters:
            shapeMatchingConstraintsData = new ObiShapeMatchingConstraintsData();

            List <int> indices = new List <int>();

            List <int> particleIndices   = new List <int>();
            List <int> constraintIndices = new List <int>();

            for (int i = 0; i < particles.Count; ++i)
            {
                constraintIndices.Add(particleIndices.Count);
                particleIndices.Add(i);

                for (int j = 0; j < particles.Count; ++j)
                {
                    if (i != j && Vector3.Distance(particles[j], particles[i]) < softClusterRadius)
                    {
                        particleIndices.Add(j);
                    }
                }

                if (i % 500 == 0)
                {
                    yield return(new CoroutineJob.ProgressInfo("ObiSoftbody: generating shape matching constraints...", i / (float)particles.Count));
                }
            }

            constraintIndices.Add(particleIndices.Count);

            // pass a copy of the particleIndices array, as we need to preserve particle order (first particle in each constraint is the center particle)
            int[] constraintColors = GraphColoring.Colorize(particleIndices.ToArray(), constraintIndices.ToArray());

            for (int i = 0; i < constraintColors.Length; ++i)
            {
                int color  = constraintColors[i];
                int cIndex = constraintIndices[i];

                // Add a new batch if needed:
                if (color >= shapeMatchingConstraintsData.GetBatchCount())
                {
                    shapeMatchingConstraintsData.AddBatch(new ObiShapeMatchingConstraintsBatch());
                }

                int   amount         = constraintIndices[i + 1] - cIndex;
                int[] clusterIndices = new int[amount];
                for (int j = 0; j < amount; ++j)
                {
                    clusterIndices[j] = particleIndices[cIndex + j];
                }

                shapeMatchingConstraintsData.batches[color].AddConstraint(clusterIndices, false);
            }

            // Set initial amount of active constraints:
            for (int i = 0; i < shapeMatchingConstraintsData.batches.Count; ++i)
            {
                shapeMatchingConstraintsData.batches[i].activeConstraintCount = shapeMatchingConstraintsData.batches[i].constraintCount;
            }
        }
        protected virtual IEnumerator CreateBendingConstraints()
        {
            bendConstraintsData = new ObiBendConstraintsData();

            List <int> particleIndices   = new List <int>();
            List <int> constraintIndices = new List <int>();

            Dictionary <int, int> cons = new Dictionary <int, int>();

            for (int i = 0; i < topology.vertices.Count; i++)
            {
                HalfEdgeMesh.Vertex vertex = topology.vertices[i];

                foreach (HalfEdgeMesh.Vertex n1 in topology.GetNeighbourVerticesEnumerator(vertex))
                {
                    float cosBest             = 0;
                    HalfEdgeMesh.Vertex vBest = n1;

                    foreach (HalfEdgeMesh.Vertex n2 in topology.GetNeighbourVerticesEnumerator(vertex))
                    {
                        float cos = Vector3.Dot((n1.position - vertex.position).normalized,
                                                (n2.position - vertex.position).normalized);
                        if (cos < cosBest)
                        {
                            cosBest = cos;
                            vBest   = n2;
                        }
                    }

                    if (!cons.ContainsKey(vBest.index) || cons[vBest.index] != n1.index)
                    {
                        cons[n1.index] = vBest.index;

                        particleIndices.Add(n1.index);
                        particleIndices.Add(vBest.index);
                        particleIndices.Add(vertex.index);
                        constraintIndices.Add(constraintIndices.Count * 3);
                    }
                }

                if (i % 500 == 0)
                {
                    yield return(new CoroutineJob.ProgressInfo("ObiCloth: adding bend constraints...", i / (float)topology.vertices.Count));
                }
            }
            constraintIndices.Add(constraintIndices.Count * 3);

            int[] constraintColors = GraphColoring.Colorize(particleIndices.ToArray(), constraintIndices.ToArray());

            for (int i = 0; i < constraintColors.Length; ++i)
            {
                int color  = constraintColors[i];
                int cIndex = constraintIndices[i];

                // Add a new batch if needed:
                if (color >= bendConstraintsData.GetBatchCount())
                {
                    bendConstraintsData.AddBatch(new ObiBendConstraintsBatch());
                }

                HalfEdgeMesh.Vertex n1     = topology.vertices[particleIndices[cIndex]];
                HalfEdgeMesh.Vertex vBest  = topology.vertices[particleIndices[cIndex + 1]];
                HalfEdgeMesh.Vertex vertex = topology.vertices[particleIndices[cIndex + 2]];

                Vector3 n1Pos     = Vector3.Scale(scale, n1.position);
                Vector3 bestPos   = Vector3.Scale(scale, vBest.position);
                Vector3 vertexPos = Vector3.Scale(scale, vertex.position);

                float restBend = ObiUtils.RestBendingConstraint(n1Pos, bestPos, vertexPos);
                bendConstraintsData.batches[color].AddConstraint(new Vector3Int(particleIndices[cIndex], particleIndices[cIndex + 1], particleIndices[cIndex + 2]), restBend);
            }

            // Set initial amount of active constraints:
            for (int i = 0; i < bendConstraintsData.batches.Count; ++i)
            {
                bendConstraintsData.batches[i].activeConstraintCount = bendConstraintsData.batches[i].constraintCount;
            }
        }