public void Solve_Animated(IKSolverVR solver, float scale, float deltaTime)
            {
                if (animator == null)
                {
                    Debug.LogError("VRIK cannot find Animator on the VRIK root gameobject.", solver.root);
                    return;
                }

                if (deltaTime <= 0f)
                {
                    return;
                }

                if (!animator.enabled)
                {
                    Debug.LogWarning("Trying to use VRIK animated locomotion with a disabled animator!", solver.root);
                    return;
                }

                // Root up vector
                Vector3 rootUp = solver.rootBone.solverRotation * Vector3.up;

                // Substract any motion from parent transforms
                Vector3 externalDelta = solver.rootBone.solverPosition - lastEndRootPos;

                externalDelta -= animator.deltaPosition;

                // Head target position
                Vector3 headTargetPos    = solver.spine.headPosition;
                Vector3 standOffsetWorld = solver.rootBone.solverRotation * new Vector3(standOffset.x, 0f, standOffset.y) * scale;

                headTargetPos += standOffsetWorld;

                if (firstFrame)
                {
                    lastHeadTargetPos = headTargetPos;

                    firstFrame = false;
                }

                // Head target velocity
                Vector3 headTargetVelocity = (headTargetPos - lastHeadTargetPos) / deltaTime;

                lastHeadTargetPos  = headTargetPos;
                headTargetVelocity = V3Tools.Flatten(headTargetVelocity, rootUp);

                // Head target offset
                Vector3 offset = headTargetPos - solver.rootBone.solverPosition;

                offset -= externalDelta;
                offset -= lastCorrection;
                offset  = V3Tools.Flatten(offset, rootUp);

                // Turning
                Vector3 headForward = (solver.spine.IKRotationHead * solver.spine.anchorRelativeToHead) * Vector3.forward;

                headForward.y = 0f;
                Vector3 headForwardLocal = Quaternion.Inverse(solver.rootBone.solverRotation) * headForward;
                float   angle            = Mathf.Atan2(headForwardLocal.x, headForwardLocal.z) * Mathf.Rad2Deg;

                angle += solver.spine.rootHeadingOffset;
                float turnTarget = angle / 90f;
                bool  isTurning  = true;

                if (Mathf.Abs(turnTarget) < 0.2f)
                {
                    turnTarget = 0f;
                    isTurning  = false;
                }

                turn = Mathf.Lerp(turn, turnTarget, Time.deltaTime * 3f);
                animator.SetFloat(VRIK_Turn, turn * 2f);

                // Local Velocity, animation smoothing
                Vector3 velocityLocalTarget = Quaternion.Inverse(solver.readRotations[0]) * (headTargetVelocity + offset);

                velocityLocalTarget *= weight * stepLengthMlp;

                float animationSmoothTimeTarget = isTurning && !isMoving ? 0.2f : animationSmoothTime;

                currentAnimationSmoothTime = Mathf.Lerp(currentAnimationSmoothTime, animationSmoothTimeTarget, deltaTime * 20f);

                velocityLocal = Vector3.SmoothDamp(velocityLocal, velocityLocalTarget, ref velocityLocalV, currentAnimationSmoothTime, Mathf.Infinity, deltaTime);
                float velLocalMag = velocityLocal.magnitude / stepLengthMlp;

                //animator.SetBool("VRIK_StartWithRightFoot", velocityLocal.x >= 0f);
                animator.SetFloat(VRIK_Horizontal, velocityLocal.x / scale);
                animator.SetFloat(VRIK_Vertical, velocityLocal.z / scale);

                // Is Moving
                float m = moveThreshold * scale;

                if (isMoving)
                {
                    m *= 0.9f;
                }
                bool isMovingRaw = velocityLocal.sqrMagnitude > m * m;

                if (isMovingRaw)
                {
                    stopMoveTimer = 0f;
                }
                else
                {
                    stopMoveTimer += deltaTime;
                }
                isMoving = stopMoveTimer < 0.05f;

                // Max root angle
                float maxRootAngleTarget = isMoving ? maxRootAngleMoving : maxRootAngleStanding;

                solver.spine.maxRootAngle = Mathf.SmoothDamp(solver.spine.maxRootAngle, maxRootAngleTarget, ref maxRootAngleV, 0.2f, Mathf.Infinity, deltaTime);

                animator.SetBool(VRIK_IsMoving, isMoving);

                // Animation speed
                Vector3 currentRootPos = solver.rootBone.solverPosition;

                currentRootPos -= externalDelta;
                currentRootPos -= lastCorrection;

                Vector3 rootVelocity = (currentRootPos - lastSpeedRootPos) / deltaTime;

                lastSpeedRootPos = solver.rootBone.solverPosition;
                float rootVelocityMag = rootVelocity.magnitude;

                float animSpeedTarget = minAnimationSpeed;

                if (rootVelocityMag > 0f && isMovingRaw)
                {
                    animSpeedTarget = animSpeed * (velLocalMag / rootVelocityMag);
                }
                animSpeedTarget = Mathf.Clamp(animSpeedTarget, minAnimationSpeed, maxAnimationSpeed);
                animSpeed       = Mathf.SmoothDamp(animSpeed, animSpeedTarget, ref animSpeedV, 0.05f, Mathf.Infinity, deltaTime);
                animSpeed       = Mathf.Lerp(1f, animSpeed, weight);

                animator.SetFloat(VRIK_Speed, animSpeed);

                // Is Stopping
                AnimatorTransitionInfo transInfo = animator.GetAnimatorTransitionInfo(0);
                bool isStopping = transInfo.IsUserName("VRIK_Stop");

                // Root lerp speed
                float rootLerpSpeedTarget = 0;

                if (isMoving)
                {
                    rootLerpSpeedTarget = rootLerpSpeedWhileMoving;
                }
                if (isStopping)
                {
                    rootLerpSpeedTarget = rootLerpSpeedWhileStopping;
                }
                if (isTurning)
                {
                    rootLerpSpeedTarget = rootLerpSpeedWhileTurning;
                }

                rootLerpSpeedTarget *= Mathf.Max(headTargetVelocity.magnitude, 0.2f);
                rootLerpSpeed        = Mathf.Lerp(rootLerpSpeed, rootLerpSpeedTarget, deltaTime * 20f);

                // Root lerp and limits
                headTargetPos += V3Tools.ExtractVertical(solver.rootBone.solverPosition - headTargetPos, rootUp, 1f);

                if (maxRootOffset > 0f)
                {
                    // Lerp towards head target position
                    Vector3 p = solver.rootBone.solverPosition;

                    if (rootLerpSpeed > 0f)
                    {
                        solver.rootBone.solverPosition = Vector3.Lerp(solver.rootBone.solverPosition, headTargetPos, rootLerpSpeed * deltaTime * weight);
                    }

                    lastCorrection = solver.rootBone.solverPosition - p;

                    // Max offset
                    offset = headTargetPos - solver.rootBone.solverPosition;
                    offset = V3Tools.Flatten(offset, rootUp);
                    float offsetMag = offset.magnitude;

                    if (offsetMag > maxRootOffset)
                    {
                        lastCorrection += (offset - (offset / offsetMag) * maxRootOffset) * weight;
                        solver.rootBone.solverPosition += lastCorrection;
                    }
                }
                else
                {
                    // Snap to head target position
                    lastCorrection = (headTargetPos - solver.rootBone.solverPosition) * weight;
                    solver.rootBone.solverPosition += lastCorrection;
                }

                lastEndRootPos = solver.rootBone.solverPosition;
            }