protected virtual IEnumerator CreateBendingConstraints() { bendConstraintsData = new ObiBendConstraintsData(); // Add three batches: bendConstraintsData.AddBatch(new ObiBendConstraintsBatch()); bendConstraintsData.AddBatch(new ObiBendConstraintsBatch()); bendConstraintsData.AddBatch(new ObiBendConstraintsBatch()); for (int i = 0; i < totalParticles - 2; i++) { var batch = bendConstraintsData.batches[i % 3] as ObiBendConstraintsBatch; Vector3Int indices = new Vector3Int(i, i + 2, i + 1); float restBend = ObiUtils.RestBendingConstraint(restPositions[indices[0]], restPositions[indices[1]], restPositions[indices[2]]); batch.AddConstraint(indices, restBend); if (i < m_ActiveParticleCount - 2) { batch.activeConstraintCount++; } if (i % 500 == 0) { yield return(new CoroutineJob.ProgressInfo("ObiRope: generating structural constraints...", i / (float)(totalParticles - 2))); } } // if the path is closed, add the last, loop closing constraints to a new batch to avoid sharing particles. if (path.Closed) { var loopClosingBatch = new ObiBendConstraintsBatch(); bendConstraintsData.AddBatch(loopClosingBatch); Vector3Int indices = new Vector3Int(m_ActiveParticleCount - 2, 0, m_ActiveParticleCount - 1); loopClosingBatch.AddConstraint(indices, 0); loopClosingBatch.activeConstraintCount++; var loopClosingBatch2 = new ObiBendConstraintsBatch(); bendConstraintsData.AddBatch(loopClosingBatch2); indices = new Vector3Int(m_ActiveParticleCount - 1, 1, 0); loopClosingBatch2.AddConstraint(indices, 0); loopClosingBatch2.activeConstraintCount++; } }
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; } }