示例#1
0
        /**
         * This function generates tethers for a given set of particles, all belonging a connected graph.
         * This is use ful when the cloth mesh is composed of several
         * disjoint islands, and we dont want tethers in one island to anchor particles to fixed particles in a different island.
         *
         * Inside each island, fixed particles are partitioned again into "islands", then generates up to maxTethers constraints for each
         * particle linking it to the closest point in each fixed island.
         */
        private void GenerateTethersForIsland(HashSet <int> particles, int maxTethers)
        {
            if (maxTethers > 0)
            {
                ObiTetherConstraintBatch tetherBatch = new ObiTetherConstraintBatch(true, false);
                TetherConstraints.AddBatch(tetherBatch);

                List <HashSet <int> > fixedIslands = GenerateIslands(particles, true);

                // Generate tether constraints:
                foreach (int i in particles)
                {
                    if (invMasses[i] == 0 || !active[i])
                    {
                        continue;
                    }

                    List <KeyValuePair <float, int> > tethers = new List <KeyValuePair <float, int> >(fixedIslands.Count * maxTethers);

                    // Find the closest particle in each island, and add it to tethers.
                    foreach (HashSet <int> island in fixedIslands)
                    {
                        int   closest     = -1;
                        float minDistance = Mathf.Infinity;
                        foreach (int j in island)
                        {
                            float distance = (topology.heVertices[i].position - topology.heVertices[j].position).sqrMagnitude;
                            if (distance < minDistance)
                            {
                                minDistance = distance;
                                closest     = j;
                            }
                        }
                        if (closest >= 0)
                        {
                            tethers.Add(new KeyValuePair <float, int>(minDistance, closest));
                        }
                    }

                    // Sort tether indices by distance:
                    tethers.Sort(
                        delegate(KeyValuePair <float, int> x, KeyValuePair <float, int> y)
                    {
                        return(x.Key.CompareTo(y.Key));
                    }
                        );

                    // Create constraints for "maxTethers" closest anchor particles:
                    for (int k = 0; k < Mathf.Min(maxTethers, tethers.Count); ++k)
                    {
                        tetherBatch.AddConstraint(i, tethers[k].Value, Mathf.Sqrt(tethers[k].Key),
                                                  TetherConstraints.tetherScale,
                                                  TetherConstraints.stiffness);
                    }
                }

                tetherBatch.Cook();
            }
        }
示例#2
0
        private void GenerateHierarchicalTethers(int maxLevels)
        {
            ObiTetherConstraintBatch tetherBatch = new ObiTetherConstraintBatch(true, false, MIN_YOUNG_MODULUS, MAX_YOUNG_MODULUS);

            TetherConstraints.AddBatch(tetherBatch);

            // for each level:
            for (int i = 1; i <= maxLevels; ++i)
            {
                int stride = i * 2;

                // for each particle:
                for (int j = 0; j < usedParticles - stride; ++j)
                {
                    int nextParticle = j + stride;

                    tetherBatch.AddConstraint(j, nextParticle % usedParticles, interParticleDistance * stride, 1, 1);
                }
            }

            tetherBatch.Cook();
        }
示例#3
0
        private void GenerateFixedTethers(int maxTethers)
        {
            ObiTetherConstraintBatch tetherBatch = new ObiTetherConstraintBatch(true, false, MIN_YOUNG_MODULUS, MAX_YOUNG_MODULUS);

            TetherConstraints.AddBatch(tetherBatch);

            List <HashSet <int> > islands = new List <HashSet <int> >();

            // Partition fixed particles into islands:
            for (int i = 0; i < usedParticles; i++)
            {
                if (invMasses[i] > 0 || !active[i])
                {
                    continue;
                }

                int assignedIsland = -1;

                // keep a list of islands to merge with ours:
                List <int> mergeableIslands = new List <int>();

                // See if any of our neighbors is part of an island:
                int prev = Mathf.Max(i - 1, 0);
                int next = Mathf.Min(i + 1, usedParticles - 1);

                for (int k = 0; k < islands.Count; ++k)
                {
                    if ((active[prev] && islands[k].Contains(prev)) ||
                        (active[next] && islands[k].Contains(next)))
                    {
                        // if we are not in an island yet, pick this one:
                        if (assignedIsland < 0)
                        {
                            assignedIsland = k;
                            islands[k].Add(i);
                        }
                        // if we already are in an island, we will merge this newfound island with ours:
                        else if (assignedIsland != k && !mergeableIslands.Contains(k))
                        {
                            mergeableIslands.Add(k);
                        }
                    }
                }

                // merge islands with the assigned one:
                foreach (int merge in mergeableIslands)
                {
                    islands[assignedIsland].UnionWith(islands[merge]);
                }

                // remove merged islands:
                mergeableIslands.Sort();
                mergeableIslands.Reverse();
                foreach (int merge in mergeableIslands)
                {
                    islands.RemoveAt(merge);
                }

                // If no adjacent particle is in an island, create a new one:
                if (assignedIsland < 0)
                {
                    islands.Add(new HashSet <int>()
                    {
                        i
                    });
                }
            }

            // Generate tether constraints:
            for (int i = 0; i < usedParticles; ++i)
            {
                if (invMasses[i] == 0)
                {
                    continue;
                }

                List <KeyValuePair <float, int> > tethers = new List <KeyValuePair <float, int> >(islands.Count);

                // Find the closest particle in each island, and add it to tethers.
                foreach (HashSet <int> island in islands)
                {
                    int   closest     = -1;
                    float minDistance = Mathf.Infinity;
                    foreach (int j in island)
                    {
                        // TODO: Use linear distance along the rope in a more efficient way. precalculate it on generation!
                        int   min      = Mathf.Min(i, j);
                        int   max      = Mathf.Max(i, j);
                        float distance = 0;
                        for (int k = min; k < max; ++k)
                        {
                            distance += Vector3.Distance(positions[k],
                                                         positions[k + 1]);
                        }

                        if (distance < minDistance)
                        {
                            minDistance = distance;
                            closest     = j;
                        }
                    }
                    if (closest >= 0)
                    {
                        tethers.Add(new KeyValuePair <float, int>(minDistance, closest));
                    }
                }

                // Sort tether indices by distance:
                tethers.Sort(
                    delegate(KeyValuePair <float, int> x, KeyValuePair <float, int> y)
                {
                    return(x.Key.CompareTo(y.Key));
                }
                    );

                // Create constraints for "maxTethers" closest anchor particles:
                for (int k = 0; k < Mathf.Min(maxTethers, tethers.Count); ++k)
                {
                    tetherBatch.AddConstraint(i, tethers[k].Value, tethers[k].Key, 1, 1);
                }
            }

            tetherBatch.Cook();
        }
示例#4
0
        /**
         * Automatically generates tether constraints for the cloth.
         * Partitions fixed particles into "islands", then generates up to maxTethers constraints for each
         * particle, linking it to the closest point in each island.
         */
        public override bool GenerateTethers(int maxTethers)
        {
            if (!Initialized)
            {
                return(false);
            }

            TetherConstraints.Clear();

            if (maxTethers > 0)
            {
                ObiTetherConstraintBatch tetherBatch = new ObiTetherConstraintBatch(true, false);
                TetherConstraints.AddBatch(tetherBatch);

                List <HashSet <int> > islands = new List <HashSet <int> >();

                // Partition fixed particles into islands:
                for (int i = 0; i < topology.heVertices.Length; i++)
                {
                    Oni.Vertex vertex = topology.heVertices[i];
                    if (invMasses[i] > 0 || !active[i])
                    {
                        continue;
                    }

                    int assignedIsland = -1;

                    // keep a list of islands to merge with ours:
                    List <int> mergeableIslands = new List <int>();

                    // See if any of our neighbors is part of an island:
                    foreach (Oni.Vertex n in topology.GetNeighbourVerticesEnumerator(vertex))
                    {
                        if (!active[n.index])
                        {
                            continue;
                        }

                        for (int k = 0; k < islands.Count; ++k)
                        {
                            if (islands[k].Contains(n.index))
                            {
                                // if we are not in an island yet, pick this one:
                                if (assignedIsland < 0)
                                {
                                    assignedIsland = k;
                                    islands[k].Add(i);
                                }
                                // if we already are in an island, we will merge this newfound island with ours:
                                else if (assignedIsland != k && !mergeableIslands.Contains(k))
                                {
                                    mergeableIslands.Add(k);
                                }
                            }
                        }
                    }

                    // merge islands with the assigned one:
                    foreach (int merge in mergeableIslands)
                    {
                        islands[assignedIsland].UnionWith(islands[merge]);
                    }

                    // remove merged islands:
                    mergeableIslands.Sort();
                    mergeableIslands.Reverse();
                    foreach (int merge in mergeableIslands)
                    {
                        islands.RemoveAt(merge);
                    }

                    // If no adjacent particle is in an island, create a new one:
                    if (assignedIsland < 0)
                    {
                        islands.Add(new HashSet <int>()
                        {
                            i
                        });
                    }
                }

                // Generate tether constraints:
                for (int i = 0; i < invMasses.Length; ++i)
                {
                    if (invMasses[i] == 0 || !active[i])
                    {
                        continue;
                    }

                    List <KeyValuePair <float, int> > tethers = new List <KeyValuePair <float, int> >(islands.Count * maxTethers);

                    // Find the closest particle in each island, and add it to tethers.
                    foreach (HashSet <int> island in islands)
                    {
                        int   closest     = -1;
                        float minDistance = Mathf.Infinity;
                        foreach (int j in island)
                        {
                            float distance = (topology.heVertices[i].position - topology.heVertices[j].position).sqrMagnitude;
                            if (distance < minDistance)
                            {
                                minDistance = distance;
                                closest     = j;
                            }
                        }
                        if (closest >= 0)
                        {
                            tethers.Add(new KeyValuePair <float, int>(minDistance, closest));
                        }
                    }

                    // Sort tether indices by distance:
                    tethers.Sort(
                        delegate(KeyValuePair <float, int> x, KeyValuePair <float, int> y)
                    {
                        return(x.Key.CompareTo(y.Key));
                    }
                        );

                    // Create constraints for "maxTethers" closest anchor particles:
                    for (int k = 0; k < Mathf.Min(maxTethers, tethers.Count); ++k)
                    {
                        tetherBatch.AddConstraint(i, tethers[k].Value, Mathf.Sqrt(tethers[k].Key),
                                                  TetherConstraints.tetherScale,
                                                  TetherConstraints.stiffness);
                    }
                }

                tetherBatch.Cook();
            }

            return(true);
        }