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; } }
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; } }