示例#1
0
        protected void Awake()
        {
            solverBatchOffsets = new List <int> [Oni.ConstraintTypeCount];
            for (int i = 0; i < solverBatchOffsets.Length; ++i)
            {
                solverBatchOffsets[i] = new List <int>();
            }

            m_PinConstraints = new ObiPinConstraintsData();

#if UNITY_EDITOR
            // Check if this script's GameObject is in a PrefabStage
            var prefabStage = UnityEditor.Experimental.SceneManagement.PrefabStageUtility.GetPrefabStage(gameObject);

            if (prefabStage != null)
            {
                // Only create a solver if there's not one up our hierarchy.
                if (GetComponentInParent <ObiSolver>() == null)
                {
                    // Add our own environment root and move it to the PrefabStage scene
                    var newParent = new GameObject("ObiSolver (Environment)", typeof(ObiSolver), typeof(ObiLateFixedUpdater));
                    newParent.GetComponent <ObiLateFixedUpdater>().solvers.Add(newParent.GetComponent <ObiSolver>());
                    UnityEngine.SceneManagement.SceneManager.MoveGameObjectToScene(newParent, gameObject.scene);
                    transform.root.parent = newParent.transform;
                }
            }
#endif
        }
示例#2
0
        public IEnumerator Generate()
        {
            m_Empty = true;

            m_ActiveParticleCount        = 0;
            distanceConstraintsData      = null;
            bendConstraintsData          = null;
            pinConstraintsData           = null;
            skinConstraintsData          = null;
            tetherConstraintsData        = null;
            bendTwistConstraintsData     = null;
            stretchShearConstraintsData  = null;
            shapeMatchingConstraintsData = null;
            aerodynamicConstraintsData   = null;
            chainConstraintsData         = null;
            volumeConstraintsData        = null;

            IEnumerator g = Initialize();

            while (g.MoveNext())
            {
                yield return(g.Current);
            }

            RecalculateBounds();

            m_Empty = false;
            m_InitialActiveParticleCount = m_ActiveParticleCount;

            foreach (IObiConstraints constraints in GetConstraints())
            {
                foreach (IObiConstraintsBatch batch in constraints.GetBatchInterfaces())
                {
                    batch.initialActiveConstraintCount = batch.activeConstraintCount;
                }
            }

#if UNITY_EDITOR
            EditorUtility.SetDirty(this);
#endif

            if (OnBlueprintGenerate != null)
            {
                OnBlueprintGenerate(this);
            }
        }
示例#3
0
 public ObiPinConstraintsBatch(ObiPinConstraintsData constraints = null, ObiPinConstraintsBatch source = null) : base(source)
 {
     m_Constraints = constraints;
 }
示例#4
0
        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();

            Vector3[] vertices = inputMesh.vertices;
            Vector3[] normals  = inputMesh.normals;
            vertexToParticle = new int[vertices.Length];
            List <Vector3> particles = new List <Vector3>();

            // Add particles to every vertex, as long as they are not too close to the already added ones:
            for (int i = 0; i < vertices.Length; ++i)
            {
                bool    intersects   = false;
                Vector3 vertexScaled = Vector3.Scale(scale, vertices[i]);

                for (int j = 0; j < particles.Count; ++j)
                {
                    if (Vector3.Distance(vertexScaled, particles[j]) < particleRadius * 2 * (1 - particleOverlap))
                    {
                        intersects = true;
                        break;
                    }
                }
                if (intersects)
                {
                    continue;
                }

                particles.Add(vertexScaled);

                if (i % 100 == 0)
                {
                    yield return(new CoroutineJob.ProgressInfo("ObiSoftbody: sampling mesh...", i / (float)vertices.Length));
                }
            }

            // Find out the closes particle to each vertex:
            for (int i = 0; i < vertices.Length; ++i)
            {
                Vector3 vertexScaled = Vector3.Scale(scale, vertices[i]);
                float   minDistance  = float.MaxValue;
                vertexToParticle[i] = 0;

                for (int j = 0; j < particles.Count; ++j)
                {
                    float distance = Vector3.SqrMagnitude(vertexScaled - particles[j]);
                    if (distance < minDistance)
                    {
                        minDistance         = distance;
                        vertexToParticle[i] = j;
                    }
                }

                if (i % 100 == 0)
                {
                    yield return(new CoroutineJob.ProgressInfo("ObiSoftbody: mapping vertices to particles...", i / (float)vertices.Length));
                }
            }

            positions           = new Vector3[particles.Count];
            orientations        = new Quaternion[particles.Count];
            restPositions       = new Vector4[particles.Count];
            restOrientations    = new Quaternion[particles.Count];
            velocities          = new Vector3[particles.Count];
            angularVelocities   = new Vector3[particles.Count];
            invMasses           = new float[particles.Count];
            invRotationalMasses = new float[particles.Count];
            principalRadii      = new Vector3[particles.Count];
            phases = new int[particles.Count];
            colors = new Color[particles.Count];

            m_ActiveParticleCount = particles.Count;

            for (int i = 0; i < particles.Count; ++i)
            {
                // Perform ellipsoid fitting:
                Vector3        avgNormal         = Vector3.zero;
                List <Vector3> neighbourVertices = new List <Vector3>();

                for (int j = 0; j < vertices.Length; ++j)
                {
                    Vector3 vertexScaled = Vector3.Scale(scale, vertices[j]);

                    if (Vector3.Distance(vertexScaled, particles[i]) < anisotropyNeighborhood)
                    {
                        neighbourVertices.Add(vertexScaled);
                        avgNormal += normals[j];
                    }
                }
                if (neighbourVertices.Count > 0)
                {
                    avgNormal /= neighbourVertices.Count;
                }

                Vector3    centroid        = particles[i];
                Quaternion orientation     = Quaternion.identity;
                Vector3    principalValues = Vector3.one;
                Oni.GetPointCloudAnisotropy(neighbourVertices.ToArray(), neighbourVertices.Count, maxAnisotropy, particleRadius, ref avgNormal, ref centroid, ref orientation, ref principalValues);

                invRotationalMasses[i] = invMasses[i] = 1.0f;
                positions[i]           = Vector3.Lerp(particles[i], centroid, shapeSmoothing);
                restPositions[i]       = positions[i];
                restPositions[i][3]    = 1; // activate rest position.
                orientations[i]        = orientation;
                restOrientations[i]    = orientation;
                principalRadii[i]      = principalValues;
                phases[i] = Oni.MakePhase(1, oneSided ? Oni.ParticleFlags.OneSided : 0);
                colors[i] = Color.white;

                if (i % 100 == 0)
                {
                    yield return(new CoroutineJob.ProgressInfo("ObiSoftbody: generating particles...", i / (float)particles.Count));
                }
            }


            //if (makeSolidCluster){

            /*indices.Clear();
             * for (int i = 0; i < particles.Count; ++i)
             *  indices.Add(i);
             * shapeBatch.AddConstraint(indices.ToArray(),1,0,0,true);
             * }*/

            IEnumerator sc = CreateShapeMatchingConstraints(particles);

            while (sc.MoveNext())
            {
                yield return(sc.Current);
            }

            // Initialize pin constraints:
            pinConstraintsData = new ObiPinConstraintsData();
            ObiPinConstraintsBatch pinBatch = new ObiPinConstraintsBatch();

            pinConstraintsData.AddBatch(pinBatch);

            generatedMesh = inputMesh;
        }
示例#5
0
 public ObiPinConstraintsData(ObiActor actor = null, ObiPinConstraintsData source = null) : base(actor, source)
 {
 }
        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();

            List <Vector3> particles = new List <Vector3>();
            List <Vector3> normals   = new List <Vector3>();

            // Calculate voxel size so that no more than 32^3 particles are created:
            Vector3 boundsSize = Vector3.Scale(inputMesh.bounds.size, Vector3.one);
            float   voxelSize  = Mathf.Max(boundsSize.x / 32.0f, boundsSize.y / 32.0f, boundsSize.z / 32.0f, particleRadius * 2 * (1 - particleOverlap));

            // Voxelize mesh and calculate discrete distance field:
            MeshVoxelizer      voxelizer = new MeshVoxelizer(inputMesh, voxelSize);
            VoxelDistanceField df        = new VoxelDistanceField(voxelizer);

            voxelizer.Voxelize(scale);
            df.JumpFlood();

            MeshVoxelizer.Voxel[,,] voxels = voxelizer.voxels;

            for (int x = 0; x < voxels.GetLength(0); ++x)
            {
                for (int y = 0; y < voxels.GetLength(1); ++y)
                {
                    for (int z = 0; z < voxels.GetLength(2); ++z)
                    {
                        if (voxels[x, y, z] != MeshVoxelizer.Voxel.Outside)
                        {
                            particles.Add(new Vector3(voxelizer.Origin.x + x + 0.5f, voxelizer.Origin.y + y + 0.5f, voxelizer.Origin.z + z + 0.5f) * voxelSize);
                            normals.Add(df.distanceField[x, y, z] - new Vector3Int(x, y, z));
                        }
                    }
                }
            }

            positions           = new Vector3[particles.Count];
            orientations        = new Quaternion[particles.Count];
            restPositions       = new Vector4[particles.Count];
            restOrientations    = new Quaternion[particles.Count];
            velocities          = new Vector3[particles.Count];
            angularVelocities   = new Vector3[particles.Count];
            invMasses           = new float[particles.Count];
            invRotationalMasses = new float[particles.Count];
            principalRadii      = new Vector3[particles.Count];
            phases = new int[particles.Count];
            colors = new Color[particles.Count];

            m_ActiveParticleCount = particles.Count;

            for (int i = 0; i < particles.Count; ++i)
            {
                // Perform ellipsoid fitting:
                Vector3        avgNormal         = Vector3.zero;
                List <Vector3> neighbourVertices = new List <Vector3>();

                Vector3    centroid        = particles[i];
                Quaternion orientation     = Quaternion.LookRotation(normals[i]);
                Vector3    principalValues = Vector3.one * voxelSize * (0.5f + particleOverlap);

                invRotationalMasses[i] = invMasses[i] = 1.0f;
                positions[i]           = Vector3.Lerp(particles[i], centroid, shapeSmoothing);
                restPositions[i]       = positions[i];
                orientations[i]        = orientation;
                restOrientations[i]    = orientation;
                restPositions[i][3]    = 1;           // activate rest position.
                principalRadii[i]      = principalValues;
                phases[i] = ObiUtils.MakePhase(1, 0); //Oni.MakePhase(1, (selfCollisions ? Oni.ParticlePhase.SelfCollide : 0) | (oneSided ? Oni.ParticlePhase.OneSided : 0));
                colors[i] = Color.white;

                if (i % 100 == 0)
                {
                    yield return(new CoroutineJob.ProgressInfo("ObiSoftbody: generating particles...", i / (float)particles.Count));
                }
            }

            IEnumerator sc = CreateShapeMatchingConstraints(particles);

            while (sc.MoveNext())
            {
                yield return(sc.Current);
            }

            // Initialize pin constraints:
            pinConstraintsData = new ObiPinConstraintsData();
            ObiPinConstraintsBatch pinBatch = new ObiPinConstraintsBatch();

            pinConstraintsData.AddBatch(pinBatch);
        }
        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]           = Oni.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));
                }
            }

            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 skin constraints:
            IEnumerator sc = CreateSkinConstraints();

            while (sc.MoveNext())
            {
                yield return(sc.Current);
            }

            pinConstraintsData = new ObiPinConstraintsData();
            ObiPinConstraintsBatch pinBatch = new ObiPinConstraintsBatch();

            pinConstraintsData.AddBatch(pinBatch);
        }
 public ObiPinConstraintsBatch(ObiPinConstraintsData constraints = null) : base()
 {
 }
示例#9
0
        protected override IEnumerator Initialize()
        {
            path.OnPathChanged.RemoveAllListeners();
            path.OnControlPointAdded.RemoveAllListeners();
            path.OnControlPointRemoved.RemoveAllListeners();
            path.OnControlPointRenamed.RemoveAllListeners();

            path.OnPathChanged.AddListener(GenerateImmediate);
            path.OnControlPointAdded.AddListener(ControlPointAdded);
            path.OnControlPointRemoved.AddListener(ControlPointRemoved);
            path.OnControlPointRenamed.AddListener(ControlPointRenamed);

            if (path.ControlPointCount < 2)
            {
                ClearParticleGroups();
                path.InsertControlPoint(0, Vector3.left, Vector3.left * 0.25f, Vector3.right * 0.25f, Vector3.up, DEFAULT_PARTICLE_MASS, 1, 1, 1, Color.white, "control point");
                path.InsertControlPoint(1, Vector3.right, Vector3.left * 0.25f, Vector3.right * 0.25f, Vector3.up, DEFAULT_PARTICLE_MASS, 1, 1, 1, Color.white, "control point");
            }

            path.RecalculateLenght(Matrix4x4.identity, 0.00001f, 7);

            List <Vector3> particlePositions   = new List <Vector3>();
            List <float>   particleThicknesses = new List <float>();
            List <float>   particleInvMasses   = new List <float>();
            List <int>     particlePhases      = new List <int>();
            List <Color>   particleColors      = new List <Color>();

            // In case the path is open, add a first particle. In closed paths, the last particle is also the first one.
            if (!path.Closed)
            {
                particlePositions.Add(path.points.GetPositionAtMu(path.Closed, 0));
                particleThicknesses.Add(path.thicknesses.GetAtMu(path.Closed, 0));
                particleInvMasses.Add(ObiUtils.MassToInvMass(path.thicknesses.GetAtMu(path.Closed, 0)));
                particlePhases.Add(path.phases.GetAtMu(path.Closed, 0));
                particleColors.Add(path.colors.GetAtMu(path.Closed, 0));
            }

            // Create a particle group for the first control point:
            groups[0].particleIndices.Clear();
            groups[0].particleIndices.Add(0);

            ReadOnlyCollection <float> lengthTable = path.ArcLengthTable;
            int spans = path.GetSpanCount();

            for (int i = 0; i < spans; i++)
            {
                int firstArcLengthSample = i * (path.ArcLengthSamples + 1);
                int lastArcLengthSample  = (i + 1) * (path.ArcLengthSamples + 1);

                float upToSpanLength = lengthTable[firstArcLengthSample];
                float spanLength     = lengthTable[lastArcLengthSample] - upToSpanLength;

                int   particlesInSpan = 1 + Mathf.FloorToInt(spanLength / thickness * resolution);
                float distance        = spanLength / particlesInSpan;

                for (int j = 0; j < particlesInSpan; ++j)
                {
                    float mu = path.GetMuAtLenght(upToSpanLength + distance * (j + 1));
                    particlePositions.Add(path.points.GetPositionAtMu(path.Closed, mu));
                    particleThicknesses.Add(path.thicknesses.GetAtMu(path.Closed, mu));
                    particleInvMasses.Add(ObiUtils.MassToInvMass(path.masses.GetAtMu(path.Closed, mu)));
                    particlePhases.Add(path.phases.GetAtMu(path.Closed, mu));
                    particleColors.Add(path.colors.GetAtMu(path.Closed, mu));
                }

                // Create a particle group for each control point:
                if (!(path.Closed && i == spans - 1))
                {
                    groups[i + 1].particleIndices.Clear();
                    groups[i + 1].particleIndices.Add(particlePositions.Count - 1);
                }

                if (i % 100 == 0)
                {
                    yield return(new CoroutineJob.ProgressInfo("ObiRope: generating particles...", i / (float)spans));
                }
            }

            m_ActiveParticleCount = particlePositions.Count;
            totalParticles        = m_ActiveParticleCount + pooledParticles;

            int numSegments = m_ActiveParticleCount - (path.Closed ? 0 : 1);

            if (numSegments > 0)
            {
                m_InterParticleDistance = path.Length / (float)numSegments;
            }
            else
            {
                m_InterParticleDistance = 0;
            }

            positions      = new Vector3[totalParticles];
            restPositions  = new Vector4[totalParticles];
            velocities     = new Vector3[totalParticles];
            invMasses      = new float[totalParticles];
            principalRadii = new Vector3[totalParticles];
            phases         = new int[totalParticles];
            colors         = new Color[totalParticles];
            restLengths    = new float[totalParticles];

            for (int i = 0; i < m_ActiveParticleCount; i++)
            {
                invMasses[i]        = particleInvMasses[i];
                positions[i]        = particlePositions[i];
                restPositions[i]    = positions[i];
                restPositions[i][3] = 1; // activate rest position.
                principalRadii[i]   = Vector3.one * particleThicknesses[i] * thickness;
                phases[i]           = Oni.MakePhase(particlePhases[i], 0);
                colors[i]           = particleColors[i];

                if (i % 100 == 0)
                {
                    yield return(new CoroutineJob.ProgressInfo("ObiRope: generating particles...", i / (float)m_ActiveParticleCount));
                }
            }

            //Create distance constraints for the total number of particles, but only activate for the used ones.
            IEnumerator dc = CreateDistanceConstraints();

            while (dc.MoveNext())
            {
                yield return(dc.Current);
            }

            //Create bending constraints:
            IEnumerator bc = CreateBendingConstraints();

            while (bc.MoveNext())
            {
                yield return(bc.Current);
            }

            //Create pin constraints:
            pinConstraintsData = new ObiPinConstraintsData();
            ObiPinConstraintsBatch pinBatch = new ObiPinConstraintsBatch();

            pinConstraintsData.AddBatch(pinBatch);

            // Recalculate rest length:
            m_RestLength = 0;
            foreach (float length in restLengths)
            {
                m_RestLength += length;
            }
        }