Exemple #1
0
    public void ProcessAnimation(UnityEngine.Animations.AnimationStream stream)
    {
        if (!settings.enabled || AnimGraph_Stand.useFootIk.IntValue < 1)
        {
            return;
        }

        ikWeight = Mathf.Clamp01(ikWeight + (1 - settings.enterStateEaseIn));

        if (stream.isHumanStream)
        {
            var human = stream.AsHuman();

            var leftToePos  = leftToe.GetPosition(stream);
            var rightToePos = rightToe.GetPosition(stream);

            var leftIkOffset  = ikOffset.x * ikWeight;
            var rightIkOffset = ikOffset.y * ikWeight;

            leftToePos  += new Vector3(0f, leftIkOffset, 0f);
            rightToePos += new Vector3(0f, rightIkOffset, 0f);


            var leftAnklePos    = human.GetGoalPosition(AvatarIKGoal.LeftFoot);
            var rightAnklePos   = human.GetGoalPosition(AvatarIKGoal.RightFoot);
            var leftAnkleRot    = human.GetGoalRotation(AvatarIKGoal.LeftFoot);
            var rightAnkleRot   = human.GetGoalRotation(AvatarIKGoal.RightFoot);
            var leftAnkleIkPos  = new Vector3(leftAnklePos.x, leftAnklePos.y + leftIkOffset, leftAnklePos.z);
            var rightAnkleIkPos = new Vector3(rightAnklePos.x, rightAnklePos.y + rightIkOffset, rightAnklePos.z);

            var hipHeightOffset = (leftIkOffset + rightIkOffset) * 0.5f;
            var forwardBackBias = (leftIkOffset - rightIkOffset) * settings.weightShiftHorizontal;

            // TODO: (sunek) Rework weight shift to move towards actual lower foot?
            hipHeightOffset += Mathf.Abs(leftIkOffset - rightIkOffset) * settings.weightShiftVertical;
            var standAngle = Quaternion.AngleAxis(settings.weightShiftAngle, Vector3.up) * Vector3.forward;
            human.bodyLocalPosition += new Vector3(standAngle.x * forwardBackBias, hipHeightOffset, standAngle.z * forwardBackBias);

            // Figure out the normal rotation
            var leftNormalRot  = Quaternion.LookRotation(Vector3.forward, normalLeftFoot);
            var rightNormalRot = Quaternion.LookRotation(Vector3.forward, normalRightFoot);

            // Clamp normal rotation
            var leftAngle  = Quaternion.Angle(Quaternion.identity, leftNormalRot);
            var rightAngle = Quaternion.Angle(Quaternion.identity, rightNormalRot);

            if (leftAngle > settings.maxFootRotationOffset && settings.maxFootRotationOffset > 0f)
            {
                var fraction = settings.maxFootRotationOffset / leftAngle;
                leftNormalRot = Quaternion.Lerp(Quaternion.identity, leftNormalRot, fraction);
            }

            if (rightAngle > settings.maxFootRotationOffset && settings.maxFootRotationOffset > 0f)
            {
                var fraction = settings.maxFootRotationOffset / rightAngle;
                rightNormalRot = Quaternion.Lerp(Quaternion.identity, rightNormalRot, fraction);
            }

            // Apply rotation to ankle
            var leftToesMatrix  = Matrix4x4.TRS(leftToePos, Quaternion.identity, Vector3.one);
            var rightToesMatrix = Matrix4x4.TRS(rightToePos, Quaternion.identity, Vector3.one);

            var leftToesNormalDeltaMatrix  = Matrix4x4.TRS(leftToePos, leftNormalRot, Vector3.one) * leftToesMatrix.inverse;
            var rightToesNormalDeltaMatrix = Matrix4x4.TRS(rightToePos, rightNormalRot, Vector3.one) * rightToesMatrix.inverse;

            var leftAnkleMatrix  = Matrix4x4.TRS(leftAnkleIkPos, leftAnkleRot, Vector3.one) * leftToesMatrix.inverse;
            var rightAnkleMatrix = Matrix4x4.TRS(rightAnkleIkPos, rightAnkleRot, Vector3.one) * rightToesMatrix.inverse;

            leftAnkleMatrix  = leftToesNormalDeltaMatrix * leftAnkleMatrix * leftToesMatrix;
            rightAnkleMatrix = rightToesNormalDeltaMatrix * rightAnkleMatrix * rightToesMatrix;

            leftAnkleIkPos  = leftAnkleMatrix.GetColumn(3);
            rightAnkleIkPos = rightAnkleMatrix.GetColumn(3);

            leftAnkleRot  = Quaternion.Lerp(leftAnkleRot, leftAnkleMatrix.rotation, ikWeight);
            rightAnkleRot = Quaternion.Lerp(rightAnkleRot, rightAnkleMatrix.rotation, ikWeight);

            // Update ik position
            // TODO: (sunek) Consider combating leg overstretch
            var leftPosition  = Vector3.Lerp(leftAnklePos, leftAnkleIkPos, ikWeight);
            var rightPosition = Vector3.Lerp(rightAnklePos, rightAnkleIkPos, ikWeight);

            human.SetGoalPosition(AvatarIKGoal.LeftFoot, leftPosition);
            human.SetGoalPosition(AvatarIKGoal.RightFoot, rightPosition);
            human.SetGoalRotation(AvatarIKGoal.LeftFoot, leftAnkleRot);
            human.SetGoalRotation(AvatarIKGoal.RightFoot, rightAnkleRot);

            human.SetGoalWeightPosition(AvatarIKGoal.LeftFoot, 1f);
            human.SetGoalWeightPosition(AvatarIKGoal.RightFoot, 1f);
            human.SetGoalWeightRotation(AvatarIKGoal.LeftFoot, 1f);
            human.SetGoalWeightRotation(AvatarIKGoal.RightFoot, 1f);
        }
    }
        private void Update(UnityEngine.Animations.AnimationStream s)
        {
            if (!_target.IsValid(s))
            {
                return;
            }
            if (!_poleTarget.IsValid(s))
            {
                return;
            }
            if (!_transform.IsValid(s))
            {
                return;
            }

            Vector3 axis     = new Vector3(_axisX.GetFloat(s), _axisY.GetFloat(s), _axisZ.GetFloat(s));
            Vector3 poleAxis = new Vector3(_poleAxisX.GetFloat(s), _poleAxisY.GetFloat(s), _poleAxisZ.GetFloat(s));

            float poleWeight = _poleWeight.GetFloat(s);

            poleWeight = Mathf.Clamp(poleWeight, 0f, 1f);

            if (axis == Vector3.zero)
            {
                return;
            }
            if (poleAxis == Vector3.zero && poleWeight > 0f)
            {
                return;
            }

            float IKPositionWeight = _IKPositionWeight.GetFloat(s);

            if (IKPositionWeight <= 0)
            {
                return;
            }
            IKPositionWeight = Mathf.Min(IKPositionWeight, 1f);

            bool  XY                = _XY.GetBool(s);
            float maxIterations     = _maxIterations.GetInt(s);
            float tolerance         = _tolerance.GetFloat(s);
            bool  useRotationLimits = _useRotationLimits.GetBool(s);

            Vector3 IKPosition = _target.GetPosition(s);

            if (XY)
            {
                IKPosition.z = bones[0].GetPosition(s).z;
            }

            Vector3 polePosition = _poleTarget.GetPosition(s);

            if (XY)
            {
                polePosition.z = IKPosition.z;
            }

            float clampWeight = _clampWeight.GetFloat(s);

            clampWeight = Mathf.Clamp(clampWeight, 0f, 1f);
            int clampSmoothing = _clampSmoothing.GetInt(s);

            clampSmoothing = Mathf.Clamp(clampSmoothing, 0, 2);

            Vector3    transformPosition = _transform.GetPosition(s);
            Quaternion transformRotation = _transform.GetRotation(s);
            Vector3    transformAxis     = transformRotation * axis;

            Vector3 clampedIKPosition = GetClampedIKPosition(s, clampWeight, clampSmoothing, IKPosition, transformPosition, transformAxis);

            Vector3 dir = clampedIKPosition - transformPosition;

            dir = Vector3.Slerp(transformAxis * dir.magnitude, dir, IKPositionWeight);
            clampedIKPosition = transformPosition + dir;

            // Iterating the solver
            for (int i = 0; i < maxIterations; i++)
            {
                // Optimizations
                if (i >= 0 && tolerance > 0 && GetAngle(s, axis, IKPosition) < tolerance)
                {
                    break;
                }
                lastLocalDirection = GetLocalDirection(s, _transform.GetRotation(s) * axis);

                for (int n = 0; n < bones.Length - 1; n++)
                {
                    RotateToTarget(s, clampedIKPosition, polePosition, n, step * (n + 1) * IKPositionWeight * boneWeights[n].GetFloat(s), poleWeight, XY, useRotationLimits, axis, poleAxis);
                }

                RotateToTarget(s, clampedIKPosition, polePosition, bones.Length - 1, IKPositionWeight * boneWeights[bones.Length - 1].GetFloat(s), poleWeight, XY, useRotationLimits, axis, poleAxis);
            }

            lastLocalDirection = GetLocalDirection(s, _transform.GetRotation(s) * axis);
        }