Пример #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;
                }
            }
        }
Пример #2
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;
             * }*/
        }
Пример #3
0
 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];
         }
     }
 }
Пример #4
0
        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;
        }
Пример #5
0
        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();
        }