Exemple #1
0
        public override void LoadBlueprint(ObiSolver solver)
        {
            // Grab a copy of the serialized topology reference. This happens when duplicating a cloth.
            if (topology != null && topology.ContainsData)
            {
                topology = new HalfEdgeMesh(topology);
            }
            // Or a copy of the shared topology, if there is no valid reference to a topology.
            else if (m_TearableClothBlueprint != null && m_TearableClothBlueprint.Topology != null)
            {
                topology = new HalfEdgeMesh(m_TearableClothBlueprint.Topology);
            }

            //Copy tear resistance array:
            tearResistance = new float[m_TearableClothBlueprint.tearResistance.Length];
            for (int i = 0; i < tearResistance.Length; ++i)
            {
                tearResistance[i] = m_TearableClothBlueprint.tearResistance[i];
            }

            //Copy deformable triangles array:
            deformableTriangles = new int[m_TearableClothBlueprint.deformableTriangles.Length];
            for (int i = 0; i < deformableTriangles.Length; ++i)
            {
                deformableTriangles[i] = m_TearableClothBlueprint.deformableTriangles[i];
            }

            base.LoadBlueprint(solver);

            SetupRuntimeConstraints();
        }
        public HalfEdgeMesh(HalfEdgeMesh halfEdge)
        {
            this.containsData = halfEdge.containsData;
            this.inputMesh    = halfEdge.inputMesh;
            this.scale        = halfEdge.scale;

            this.vertices         = new List <Vertex>(halfEdge.vertices);
            this.halfEdges        = new List <HalfEdge>(halfEdge.halfEdges);
            this.borderEdges      = new List <HalfEdge>(halfEdge.borderEdges);
            this.faces            = new List <Face>(halfEdge.faces);
            this.restNormals      = new List <Vector3>(halfEdge.restNormals);
            this.restOrientations = new List <Quaternion>(halfEdge.restOrientations);
            this.rawToWelded      = new List <int>(halfEdge.rawToWelded);
        }
        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);
            }
        }