Exemple #1
0
        /**
         * Recalculates the shape used as reference for transform position/orientation when there are no fixed particles.
         * Should be called manually when changing the amount of fixed particles and/or active particles.
         */
        public void RecalculateCenterShape()
        {
            centerShape = -1;

            for (int i = 0; i < invMasses.Length; ++i)
            {
                if (invMasses[i] <= 0)
                {
                    return;
                }
            }

            ObiShapeMatchingConstraintBatch batch = ShapeMatchingConstraints.GetFirstBatch();
            IList <int> activeShapes = batch.ActiveConstraints;

            float minDistance = float.MaxValue;

            for (int i = 0; i < activeShapes.Count; ++i)
            {
                float dist = positions[batch.GetParticleIndex(activeShapes[i])].sqrMagnitude;

                if (dist < minDistance)
                {
                    minDistance = dist;
                    centerShape = i;
                }
            }
        }
 public void AddBatch(ObiShapeMatchingConstraintBatch batch)
 {
     if (batch != null && batch.GetConstraintType() == GetConstraintType())
     {
         batches.Add(batch);
     }
 }
Exemple #3
0
        /**
         * Deactivates all fixed particles that are attached to fixed particles only, and all the constraints
         * affecting them.
         */
        public IEnumerator Optimize()
        {
            ObiShapeMatchingConstraintBatch shapeBatch = ShapeMatchingConstraints.GetFirstBatch();

            // Iterate over all particles and get those fixed ones that are only linked to fixed particles.
            for (int i = 0; i < shapeBatch.ConstraintCount; ++i)
            {
                if (invMasses[shapeBatch.GetParticleIndex(i)] > 0)
                {
                    continue;
                }

                active[i] = false;
                for (int j = shapeBatch.firstIndex[i]; j < shapeBatch.firstIndex[i] + shapeBatch.numIndices[i]; ++j)
                {
                    // If at least one neighbour particle is not fixed, then the particle we are considering for optimization should not be removed.
                    if (invMasses[shapeBatch.shapeIndices[j]] > 0)
                    {
                        active[i] = true;
                        break;
                    }
                }

                // Deactivate all constraints involving this inactive particle:
                if (!active[i])
                {
                    // for each constraint type:
                    foreach (ObiBatchedConstraints constraint in constraints)
                    {
                        // for each constraint batch (usually only one)
                        if (constraint != null)
                        {
                            foreach (ObiConstraintBatch batch in constraint.GetBatches())
                            {
                                // deactivate constraints that affect the particle:
                                List <int> affectedConstraints = batch.GetConstraintsInvolvingParticle(i);
                                foreach (int j in affectedConstraints)
                                {
                                    batch.DeactivateConstraint(j);
                                }
                                batch.SetActiveConstraints();
                            }
                        }
                    }
                }

                yield return(new CoroutineJob.ProgressInfo("ObiSoftbody: optimizing constraints...", i / (float)shapeBatch.ConstraintCount));
            }

            PushDataToSolver(ParticleData.ACTIVE_STATUS);

            // Perform skinning:

            /*IEnumerator bind = BindSkin();
             * while(bind.MoveNext()){
             *      yield return bind.Current;
             * }*/
        }
        private void CopyBoneTransforms(ObiShapeMatchingConstraintBatch batch)
        {
            IList <int> activeShapes = batch.ActiveConstraints;

            bones = new Transform[activeShapes.Count];
            for (int i = target.bones.Length - bones.Length, j = 0; i < target.bones.Length && j < bones.Length; ++i, ++j)
            {
                bones[j] = target.bones[i];
            }
        }
Exemple #5
0
        public override void OnSolverStepEnd(float deltaTime)
        {
            ObiShapeMatchingConstraintBatch batch = ShapeMatchingConstraints.GetFirstBatch();
            IList <int> shapes = batch.ActiveConstraints;

            if (Application.isPlaying && isActiveAndEnabled && centerShape > -1 && centerShape < shapes.Count)
            {
                int shape = shapes[centerShape];

                transform.position = (Vector3)batch.coms[shape] - batch.orientations[shape] * batch.restComs[shape];
                transform.rotation = batch.orientations[shape];
            }
        }
 private void UpdateBones(object sender, EventArgs e)
 {
     if (bones.Length > 0 && source.InSolver)
     {
         ObiShapeMatchingConstraintBatch batch = source.ShapeMatchingConstraints.GetFirstBatch();
         IList <int> activeShapes = batch.ActiveConstraints;
         int         particleIndex;
         for (int i = 0; i < activeShapes.Count; ++i)
         {
             particleIndex     = source.particleIndices[batch.GetParticleIndex(activeShapes[i])];
             bones[i].position = source.Solver.renderablePositions   [particleIndex];
             bones[i].rotation = source.Solver.renderableOrientations[particleIndex];
         }
     }
 }
        public IEnumerator BindSkin()
        {
            bound = false;

            if (source == null || !source.Initialized || target.sharedMesh == null)
            {
                yield break;
            }

            ObiShapeMatchingConstraintBatch batch = source.ShapeMatchingConstraints.GetFirstBatch();
            IList <int> activeShapes = batch.ActiveConstraints;

            Vector3[]    clusterCenters      = new Vector3[activeShapes.Count];
            Quaternion[] clusterOrientations = new Quaternion[activeShapes.Count];

            Vector3[] vertices = target.sharedMesh.vertices;
            m_bindposes   = new Matrix4x4[activeShapes.Count];
            m_boneWeights = new BoneWeight[vertices.Length];

            // Calculate softbody local to world matrix, and target to world matrix.
            Matrix4x4 source2w = source.transform.localToWorldMatrix * source.InitialScaleMatrix.inverse;
            Matrix4x4 target2w = transform.localToWorldMatrix;

            // Create bind pose matrices, one per shape matching cluster:
            for (int i = 0; i < clusterCenters.Length; ++i)
            {
                // world space bone center/orientation:
                clusterCenters[i]      = source2w.MultiplyPoint3x4(source.restPositions[batch.GetParticleIndex(activeShapes[i])]);
                clusterOrientations[i] = source2w.rotation * source.restOrientations[batch.GetParticleIndex(activeShapes[i])];

                // world space bone transform * object local to world.
                m_bindposes[i] = Matrix4x4.TRS(clusterCenters[i], clusterOrientations[i], Vector3.one).inverse *target2w;

                yield return(new CoroutineJob.ProgressInfo("ObiSoftbody: calculating bind poses...", i / (float)clusterCenters.Length));
            }

            // Calculate skin weights and bone indices:
            for (int j = 0; j < m_boneWeights.Length; ++j)
            {
                // transform each vertex to world space:
                m_boneWeights[j] = CalculateBoneWeights(target2w.MultiplyPoint3x4(vertices[j]), clusterCenters);
                yield return(new CoroutineJob.ProgressInfo("ObiSoftbody: calculating bone weights...", j / (float)m_boneWeights.Length));
            }

            bound = true;
        }
        private void AppendBoneTransforms(ObiShapeMatchingConstraintBatch batch)
        {
            IList <int> activeShapes = batch.ActiveConstraints;

            // Calculate softbody local to world matrix, and target to world matrix.
            Matrix4x4  source2w    = source.transform.localToWorldMatrix * source.InitialScaleMatrix.inverse;
            Quaternion source2wRot = source2w.rotation;

            bones = new Transform[activeShapes.Count];
            for (int i = 0; i < bones.Length; ++i)
            {
                GameObject bone = new GameObject("Cluster" + i);
                bone.transform.parent   = transform;
                bone.transform.position = source2w.MultiplyPoint3x4(source.restPositions[batch.GetParticleIndex(activeShapes[i])]);
                bone.transform.rotation = source2wRot * source.restOrientations[batch.GetParticleIndex(activeShapes[i])];
                bone.hideFlags          = HideFlags.DontSave | HideFlags.HideInHierarchy;
                bones[i] = bone.transform;
            }

            List <Transform> originalBones = new List <Transform>(target.bones);

            originalBones.AddRange(bones);
            target.bones = originalBones.ToArray();
        }
 public void RemoveBatch(ObiShapeMatchingConstraintBatch batch)
 {
     batches.Remove(batch);
 }
Exemple #10
0
        protected override IEnumerator Initialize()
        {
            initialized  = false;
            initializing = false;

            RemoveFromSolver(null);

            if (inputMesh == null)
            {
                Debug.LogError("No input mesh provided. Cannot initialize physical representation.");
                yield break;
            }

            initializing = true;

            initialScaleMatrix.SetTRS(Vector3.zero, Quaternion.identity, transform.lossyScale);

            Vector3[]      vertices  = inputMesh.vertices;
            Vector3[]      normals   = inputMesh.normals;
            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 = initialScaleMatrix * 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);
            }

            active              = new bool[particles.Count];
            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];

            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 = initialScaleMatrix * 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);

                active[i] = true;
                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] = Oni.MakePhase(1, (selfCollisions?Oni.ParticlePhase.SelfCollide:0) | (oneSided?Oni.ParticlePhase.OneSided:0));
            }

            //Create shape matching clusters:
            ShapeMatchingConstraints.Clear();

            ObiShapeMatchingConstraintBatch shapeBatch = new ObiShapeMatchingConstraintBatch(false, false);

            ShapeMatchingConstraints.AddBatch(shapeBatch);

            List <int> indices = new List <int>();

            // Generate soft clusters:
            //if (makeSoftClusters){
            for (int i = 0; i < particles.Count; ++i)
            {
                indices.Clear();
                indices.Add(i);
                for (int j = 0; j < particles.Count; ++j)
                {
                    if (i != j && Vector3.Distance(particles[j], particles[i]) < softClusterRadius)
                    {
                        indices.Add(j);
                    }
                }

                shapeBatch.AddConstraint(indices.ToArray(), 1, 0, 0, false);

                if (i % 500 == 0)
                {
                    yield return(new CoroutineJob.ProgressInfo("ObiSoftbody: generating shape matching constraints...", 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);*/
            //}

            // Initialize pin constraints:
            PinConstraints.Clear();
            ObiPinConstraintBatch pinBatch = new ObiPinConstraintBatch(false, false);

            PinConstraints.AddBatch(pinBatch);

            initializing = false;
            initialized  = true;
        }