private void ClassifyFaces(HalfEdgeMesh.Vertex vertex, Plane plane, List <HalfEdgeMesh.Face> side1, List <HalfEdgeMesh.Face> side2) { foreach (HalfEdgeMesh.Face face in topology.GetNeighbourFacesEnumerator(vertex)) { HalfEdgeMesh.HalfEdge e1 = topology.halfEdges[face.halfEdge]; HalfEdgeMesh.HalfEdge e2 = topology.halfEdges[e1.nextHalfEdge]; HalfEdgeMesh.HalfEdge e3 = topology.halfEdges[e2.nextHalfEdge]; // Skip this face if it doesn't contain the vertex being split. // This can happen because edge pair links are not updated in a vertex split operation, // so split vertices still "see" faces at the other side of the cut as adjacent. if (e1.endVertex != vertex.index && e2.endVertex != vertex.index && e3.endVertex != vertex.index) { continue; } // calculate actual face center from deformed vertex positions: Vector3 faceCenter = (m_Solver.positions[solverIndices[e1.endVertex]] + m_Solver.positions[solverIndices[e2.endVertex]] + m_Solver.positions[solverIndices[e3.endVertex]]) * 0.33f; if (plane.GetSide(faceCenter)) { side1.Add(face); } else { side2.Add(face); } } }
protected override IEnumerator Initialize() { if (inputMesh == null || !inputMesh.isReadable) { // TODO: return an error in the coroutine. Debug.LogError("The input mesh is null, or not readable."); yield break; } ClearParticleGroups(); topology = new HalfEdgeMesh(); topology.inputMesh = inputMesh; topology.Generate(); positions = new Vector3[topology.vertices.Count]; restPositions = new Vector4[topology.vertices.Count]; velocities = new Vector3[topology.vertices.Count]; invMasses = new float[topology.vertices.Count]; principalRadii = new Vector3[topology.vertices.Count]; phases = new int[topology.vertices.Count]; colors = new Color[topology.vertices.Count]; areaContribution = new float[topology.vertices.Count]; // Create a particle for each vertex: m_ActiveParticleCount = topology.vertices.Count; for (int i = 0; i < topology.vertices.Count; i++) { HalfEdgeMesh.Vertex vertex = topology.vertices[i]; // Get the particle's area contribution. areaContribution[i] = 0; foreach (HalfEdgeMesh.Face face in topology.GetNeighbourFacesEnumerator(vertex)) { areaContribution[i] += topology.GetFaceArea(face) / 3; } // Get the shortest neighbour edge, particle radius will be half of its length. float minEdgeLength = Single.MaxValue; foreach (HalfEdgeMesh.HalfEdge edge in topology.GetNeighbourEdgesEnumerator(vertex)) { // vertices at each end of the edge: Vector3 v1 = Vector3.Scale(scale, topology.vertices[topology.GetHalfEdgeStartVertex(edge)].position); Vector3 v2 = Vector3.Scale(scale, topology.vertices[edge.endVertex].position); minEdgeLength = Mathf.Min(minEdgeLength, Vector3.Distance(v1, v2)); } invMasses[i] = (/*skinnedMeshRenderer == null &&*/ areaContribution[i] > 0) ? (1.0f / (DEFAULT_PARTICLE_MASS * areaContribution[i])) : 0; positions[i] = Vector3.Scale(scale, vertex.position); restPositions[i] = positions[i]; restPositions[i][3] = 1; // activate rest position. principalRadii[i] = Vector3.one * minEdgeLength * 0.5f; phases[i] = ObiUtils.MakePhase(1, /*selfCollisions ? Oni.ParticlePhase.SelfCollide : 0*/ 0); colors[i] = Color.white; if (i % 500 == 0) { yield return(new CoroutineJob.ProgressInfo("ObiCloth: generating particles...", i / (float)topology.vertices.Count)); } } // Deformable triangles: IEnumerator dt = GenerateDeformableTriangles(); while (dt.MoveNext()) { yield return(dt.Current); } // Create distance constraints: IEnumerator dc = CreateDistanceConstraints(); while (dc.MoveNext()) { yield return(dc.Current); } // Create aerodynamic constraints: IEnumerator ac = CreateAerodynamicConstraints(); while (ac.MoveNext()) { yield return(ac.Current); } // Create bending constraints: IEnumerator bc = CreateBendingConstraints(); while (bc.MoveNext()) { yield return(bc.Current); } // Create volume constraints: IEnumerator vc = CreateVolumeConstraints(); while (vc.MoveNext()) { yield return(vc.Current); } }