Exemple #1
0
        private void UpdateTornDistanceConstraints(HashSet <int> updatedHalfEdges)
        {
            var distanceConstraints = GetConstraintsByType(Oni.ConstraintType.Distance) as ObiConstraints <ObiDistanceConstraintsBatch>;

            foreach (int halfEdgeIndex in updatedHalfEdges)
            {
                HalfEdgeMesh.HalfEdge e = m_TearableBlueprintInstance.topology.halfEdges[halfEdgeIndex];
                Vector2Int            constraintDescriptor = m_TearableClothBlueprint.distanceConstraintMap[halfEdgeIndex];

                // skip edges with no associated constraint (border half-edges)
                if (constraintDescriptor.x > -1)
                {
                    // get batch and index of the constraint:
                    var batch = distanceConstraints.batches[constraintDescriptor.x] as ObiDistanceConstraintsBatch;
                    int index = batch.GetConstraintIndex(constraintDescriptor.y);

                    // update constraint particle indices:
                    batch.particleIndices[index * 2]     = m_TearableBlueprintInstance.topology.GetHalfEdgeStartVertex(e);
                    batch.particleIndices[index * 2 + 1] = e.endVertex;

                    // make sure the constraint is active, in case it is a newly added one.
                    batch.ActivateConstraint(index);
                }

                // update deformable triangles:
                if (e.indexInFace > -1)
                {
                    m_TearableBlueprintInstance.deformableTriangles[e.face * 3 + e.indexInFace] = e.endVertex;
                }
            }
        }
        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;
            }
        }
        public void SwapVertices(int index1, int index2)
        {
            vertices.Swap(index1, index2);
            restNormals.Swap(index1, index2);
            restOrientations.Swap(index1, index2);

            for (int i = 0; i < halfEdges.Count; ++i)
            {
                HalfEdgeMesh.HalfEdge halfEdge = halfEdges[i];
                if (halfEdge.endVertex == index1)
                {
                    halfEdge.endVertex = index2;
                    halfEdges[i]       = halfEdge;
                }
                else if (halfEdge.endVertex == index2)
                {
                    halfEdge.endVertex = index1;
                    halfEdges[i]       = halfEdge;
                }
            }

            for (int i = 0; i < borderEdges.Count; ++i)
            {
                HalfEdgeMesh.HalfEdge halfEdge = borderEdges[i];
                if (halfEdge.endVertex == index1)
                {
                    halfEdge.endVertex = index2;
                    borderEdges[i]     = halfEdge;
                }
                else if (halfEdge.endVertex == index2)
                {
                    halfEdge.endVertex = index1;
                    borderEdges[i]     = halfEdge;
                }
            }

            for (int i = 0; i < rawToWelded.Count; ++i)
            {
                if (rawToWelded[i] == index1)
                {
                    rawToWelded[i] = index2;
                }
                else if (rawToWelded[i] == index2)
                {
                    rawToWelded[i] = index1;
                }
            }
        }
Exemple #4
0
        protected virtual IEnumerator CreateVolumeConstraints()
        {
            //Create pressure constraints if the mesh is closed:
            if (topology.closed)
            {
                volumeConstraintsData = new ObiVolumeConstraintsData();

                ObiVolumeConstraintsBatch volumeBatch = new ObiVolumeConstraintsBatch();
                volumeConstraintsData.AddBatch(volumeBatch);

                float avgInitialScale = (scale.x + scale.y + scale.z) * 0.33f;

                int[] triangleIndices = new int[topology.faces.Count * 3];
                for (int i = 0; i < topology.faces.Count; i++)
                {
                    HalfEdgeMesh.Face face = topology.faces[i];

                    HalfEdgeMesh.HalfEdge e1 = topology.halfEdges[face.halfEdge];
                    HalfEdgeMesh.HalfEdge e2 = topology.halfEdges[e1.nextHalfEdge];
                    HalfEdgeMesh.HalfEdge e3 = topology.halfEdges[e2.nextHalfEdge];

                    triangleIndices[i * 3]     = e1.endVertex;
                    triangleIndices[i * 3 + 1] = e2.endVertex;
                    triangleIndices[i * 3 + 2] = e3.endVertex;

                    if (i % 500 == 0)
                    {
                        yield return(new CoroutineJob.ProgressInfo("ObiCloth: generating volume constraints...", i / (float)topology.faces.Count));
                    }
                }

                volumeBatch.AddConstraint(triangleIndices, topology.volume * avgInitialScale);

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

                // last triangle is the triangle count:
                volumeBatch.firstTriangle.Add(volumeBatch.particleIndices.count / 3);
            }
        }
Exemple #5
0
        protected virtual IEnumerator CreateSimplices()
        {
            triangles   = new int[topology.faces.Count * 3];
            restNormals = new Vector3[topology.vertices.Count];

            // Generate deformable triangles:
            for (int i = 0; i < topology.faces.Count; i++)
            {
                HalfEdgeMesh.Face face = topology.faces[i];

                HalfEdgeMesh.HalfEdge e1 = topology.halfEdges[face.halfEdge];
                HalfEdgeMesh.HalfEdge e2 = topology.halfEdges[e1.nextHalfEdge];
                HalfEdgeMesh.HalfEdge e3 = topology.halfEdges[e2.nextHalfEdge];

                triangles[i * 3]     = e1.endVertex;
                triangles[i * 3 + 1] = e2.endVertex;
                triangles[i * 3 + 2] = e3.endVertex;

                Vector3 v1 = positions[e1.endVertex];
                Vector3 v2 = positions[e2.endVertex];
                Vector3 v3 = positions[e3.endVertex];

                Vector3 n = Vector3.Cross(v2 - v1, v3 - v1);

                restNormals[e1.endVertex] += n;
                restNormals[e2.endVertex] += n;
                restNormals[e3.endVertex] += n;

                if (i % 500 == 0)
                {
                    yield return(new CoroutineJob.ProgressInfo("ObiCloth: generating deformable geometry...", i / (float)topology.faces.Count));
                }
            }

            for (int i = 0; i < restNormals.Length; ++i)
            {
                restNormals[i].Normalize();
            }
        }
Exemple #6
0
        private void ClassifyFaces(HalfEdgeMesh.Vertex vertex,
                                   Plane plane,
                                   List <HalfEdgeMesh.Face> side1,
                                   List <HalfEdgeMesh.Face> side2)
        {
            foreach (HalfEdgeMesh.Face face in m_TearableBlueprintInstance.topology.GetNeighbourFacesEnumerator(vertex))
            {
                HalfEdgeMesh.HalfEdge e1 = m_TearableBlueprintInstance.topology.halfEdges[face.halfEdge];
                HalfEdgeMesh.HalfEdge e2 = m_TearableBlueprintInstance.topology.halfEdges[e1.nextHalfEdge];
                HalfEdgeMesh.HalfEdge e3 = m_TearableBlueprintInstance.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);
                }
            }
        }
Exemple #7
0
        private bool SplitTopologyAtVertex(int vertexIndex,
                                           Plane plane,
                                           List <HalfEdgeMesh.Face> updatedFaces,
                                           HashSet <int> updatedEdgeIndices)
        {
            if (vertexIndex < 0 || vertexIndex >= m_TearableBlueprintInstance.topology.vertices.Count)
            {
                return(false);
            }

            updatedFaces.Clear();
            updatedEdgeIndices.Clear();
            HalfEdgeMesh.Vertex vertex = m_TearableBlueprintInstance.topology.vertices[vertexIndex];

            // classify adjacent faces depending on which side of the plane they're at:
            var otherSide = new List <HalfEdgeMesh.Face>();

            ClassifyFaces(vertex, plane, updatedFaces, otherSide);

            // guard against pathological case in which all particles are in one side of the plane:
            if (otherSide.Count == 0 || updatedFaces.Count == 0)
            {
                return(false);
            }

            // create a new vertex:
            var newVertex = new HalfEdgeMesh.Vertex();

            newVertex.position = vertex.position;
            newVertex.index    = m_TearableBlueprintInstance.topology.vertices.Count;
            newVertex.halfEdge = vertex.halfEdge;

            // rearrange edges at the updated side:
            foreach (HalfEdgeMesh.Face face in updatedFaces)
            {
                // find half edges that start and end at the split vertex:
                HalfEdgeMesh.HalfEdge e1 = m_TearableBlueprintInstance.topology.halfEdges[face.halfEdge];
                HalfEdgeMesh.HalfEdge e2 = m_TearableBlueprintInstance.topology.halfEdges[e1.nextHalfEdge];
                HalfEdgeMesh.HalfEdge e3 = m_TearableBlueprintInstance.topology.halfEdges[e2.nextHalfEdge];

                var in_  = e1;
                var out_ = e2;

                if (e1.endVertex == vertex.index)
                {
                    in_ = e1;
                }
                else if (m_TearableBlueprintInstance.topology.GetHalfEdgeStartVertex(e1) == vertex.index)
                {
                    out_ = e1;
                }

                if (e2.endVertex == vertex.index)
                {
                    in_ = e2;
                }
                else if (m_TearableBlueprintInstance.topology.GetHalfEdgeStartVertex(e2) == vertex.index)
                {
                    out_ = e2;
                }

                if (e3.endVertex == vertex.index)
                {
                    in_ = e3;
                }
                else if (m_TearableBlueprintInstance.topology.GetHalfEdgeStartVertex(e3) == vertex.index)
                {
                    out_ = e3;
                }

                // stitch edges to new vertex:
                in_.endVertex = newVertex.index;
                m_TearableBlueprintInstance.topology.halfEdges[in_.index] = in_;
                newVertex.halfEdge = out_.index;

                // store edges to be updated:
                updatedEdgeIndices.UnionWith(new int[]
                {
                    in_.index, in_.pair, out_.index, out_.pair
                });
            }

            // add new vertex:
            m_TearableBlueprintInstance.topology.vertices.Add(newVertex);
            m_TearableBlueprintInstance.topology.restNormals.Add(m_TearableBlueprintInstance.topology.restNormals[vertexIndex]);
            m_TearableBlueprintInstance.topology.restOrientations.Add(m_TearableBlueprintInstance.topology.restOrientations[vertexIndex]);

            //TODO: update mesh info. (mesh cannot be closed now)

            return(true);
        }