Пример #1
0
 protected virtual void OnDestroy()
 {
     if (this.ik != null)
     {
         IKSolverVR solver = this.ik.solver;
         solver.OnPreUpdate = (IKSolver.UpdateDelegate)Delegate.Remove(solver.OnPreUpdate, new IKSolver.UpdateDelegate(this.ModifyOffset));
     }
 }
Пример #2
0
        Transform GetRootTransform(ref RootMotion.FinalIK.IKSolverVR solver)
        {
            Transform l_result = null;

            l_result = solver.spine?.headTarget?.transform?.parent;
            if (l_result == null)
            {
                l_result = VRCPlayer.field_Internal_Static_VRCPlayer_0.transform;
            }
            return(l_result);
        }
Пример #3
0
        private IEnumerator Initiate()
        {
            while (this.ik == null)
            {
                yield return(null);
            }
            IKSolverVR solver = this.ik.solver;

            solver.OnPreUpdate = (IKSolver.UpdateDelegate)Delegate.Combine(solver.OnPreUpdate, new IKSolver.UpdateDelegate(this.ModifyOffset));
            this.lastTime      = Time.time;
            yield break;
        }
Пример #4
0
        /// <summary>
        /// Reinitializes the IK and Solver.
        /// </summary>
        public void ReInitialize()
        {
            Debug.Log($"Reinit CustomVRIK");
            solver.initiated   = false;
            componentInitiated = false;
            FindAnimatorRecursive(transform, true);

            //We only call the base solver because on reinit we will want to assume
            //that the avatar has been replaced, and we'll need to find the data component that can be used to retreieve it.
            IAvatarIKReferenceContainer <CustomVRIKReferences> referenceContainer = this.GetComponentInChildren <IAvatarIKReferenceContainer <CustomVRIKReferences> >();

            //If we contain no reference data
            //then we should just autodetect and wish for the best
            //though this could cost performance issues on failure maybe?
            if (referenceContainer == null)
            {
                Debug.LogWarning($"Failed to find IK reference container.");
                AutoDetectReferences();
            }
            else
            {
                //Set the references in the IK controller
                this.references = referenceContainer.references;

                //We should do nothing if the references are empty.
                if (references.isEmpty)
                {
                    return;
                }

                var oldSolver = solver;
                solver = new IKSolverVR
                {
                    spine    = { headTarget = oldSolver.spine.headTarget },
                    leftArm  = { target = oldSolver.leftArm.target },
                    rightArm = { target = oldSolver.rightArm.target }
                };

                //First let's set the trackers to the appropriate local rotation
                //These compute from precomputed EULER angles from the SDK.
                solver.leftArm.target.localEulerAngles   = references.LocalLeftHandRotation;
                solver.rightArm.target.localEulerAngles  = references.LocalRightHandRotation;
                solver.spine.headTarget.localEulerAngles = references.LocalHeadRotation;

                solver.SetToReferences(references);
            }

            base.InitiateSolver();
            componentInitiated = true;
        }
            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;
            }