123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303 |
- // Copyright (c) Microsoft Corporation. All rights reserved.
- // Licensed under the MIT License. See LICENSE in the project root for license information.
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using UnityEngine;
- using UnityEngine.Serialization;
- using Microsoft.MixedReality.Toolkit.Utilities.Solvers;
- using XRTool.Util;
- namespace Microsoft.MixedReality.Toolkit.Utilities.Solvers
- {
- /// <summary>
- /// This class handles the solver components that are attached to this <see href="https://docs.unity3d.com/ScriptReference/GameObject.html">GameObject</see>
- /// </summary>
- public class SolverHandler : MonoBehaviour
- {
- [SerializeField]
- [Tooltip("Manual override for when TrackedTargetType is set to CustomOverride")]
- private Transform transformOverride;
- /// <summary>
- /// Manual override for when TrackedTargetType is set to CustomOverride
- /// </summary>
- public Transform TransformOverride
- {
- set
- {
- if (value != null && transformOverride != value)
- {
- transformOverride = value;
- RefreshTrackedObject();
- }
- }
- }
- [SerializeField]
- [Tooltip("Add an additional offset of the tracked object to base the solver on. Useful for tracking something like a halo position above your head or off the side of a controller.")]
- private Vector3 additionalOffset;
- /// <summary>
- /// Add an additional offset of the tracked object to base the solver on. Useful for tracking something like a halo position above your head or off the side of a controller.
- /// </summary>
- public Vector3 AdditionalOffset
- {
- get => additionalOffset;
- set
- {
- if (additionalOffset != value)
- {
- additionalOffset = value;
- RefreshTrackedObject();
- }
- }
- }
- [SerializeField]
- [Tooltip("Add an additional rotation on top of the tracked object. Useful for tracking what is essentially the up or right/left vectors.")]
- private Vector3 additionalRotation;
- /// <summary>
- /// Add an additional rotation on top of the tracked object. Useful for tracking what is essentially the up or right/left vectors.
- /// </summary>
- public Vector3 AdditionalRotation
- {
- get => additionalRotation;
- set
- {
- if (additionalRotation != value)
- {
- additionalRotation = value;
- RefreshTrackedObject();
- }
- }
- }
- [SerializeField]
- [Tooltip("Whether or not this SolverHandler calls SolverUpdate() every frame. Only one SolverHandler should manage SolverUpdate(). This setting does not affect whether the Target Transform of this SolverHandler gets updated or not.")]
- private bool updateSolvers = true;
- /// <summary>
- /// Whether or not this SolverHandler calls SolverUpdate() every frame. Only one SolverHandler should manage SolverUpdate(). This setting does not affect whether the Target Transform of this SolverHandler gets updated or not.
- /// </summary>
- public bool UpdateSolvers
- {
- get => updateSolvers;
- set => updateSolvers = value;
- }
- protected readonly List<Solver> solvers = new List<Solver>();
- private bool updateSolversList = false;
- /// <summary>
- /// List of solvers that this handler will manage and update
- /// </summary>
- public IReadOnlyCollection<Solver> Solvers
- {
- get => solvers.AsReadOnly();
- set
- {
- if (value != null)
- {
- solvers.Clear();
- solvers.AddRange(value);
- }
- }
- }
- /// <summary>
- /// The position the solver is trying to move to.
- /// </summary>
- public Vector3 GoalPosition { get; set; }
- /// <summary>
- /// The rotation the solver is trying to rotate to.
- /// </summary>
- public Quaternion GoalRotation { get; set; }
- /// <summary>
- /// The scale the solver is trying to scale to.
- /// </summary>
- public Vector3 GoalScale { get; set; }
- /// <summary>
- /// Alternate scale.
- /// </summary>
- public Vector3Smoothed AltScale { get; set; }
- /// <summary>
- /// The timestamp the solvers will use to calculate with.
- /// </summary>
- public float DeltaTime { get; set; }
- /// <summary>
- /// The target transform that the solvers will act upon.
- /// </summary>
- public Transform TransformTarget
- {
- get
- {
- if (IsInvalidTracking())
- {
- RefreshTrackedObject();
- }
- return trackingTarget != null ? trackingTarget.transform : null;
- }
- }
- // Hidden GameObject managed by this component and attached as a child to the tracked target type (i.e head, hand etc)
- private GameObject trackingTarget;
- private float lastUpdateTime;
- #region MonoBehaviour Implementation
- private void Awake()
- {
- GoalScale = Vector3.one;
- AltScale = new Vector3Smoothed(Vector3.one, 0.1f);
- DeltaTime = Time.deltaTime;
- lastUpdateTime = Time.realtimeSinceStartup;
- }
- protected virtual void Start()
- {
- RefreshTrackedObject();
- }
- protected virtual void Update()
- {
- if (IsInvalidTracking())
- {
- RefreshTrackedObject();
- }
- DeltaTime = Time.realtimeSinceStartup - lastUpdateTime;
- lastUpdateTime = Time.realtimeSinceStartup;
- }
- private void LateUpdate()
- {
- if (updateSolversList)
- {
- IEnumerable<Solver> inspectorOrderedSolvers = GetComponents<Solver>().Intersect(solvers);
- //Solvers = inspectorOrderedSolvers.Union(Solvers).ToReadOnlyCollection();
- updateSolversList = false;
- }
- if (UpdateSolvers)
- {
- // Before calling solvers, update goal to be the transform so that working and transform will match
- GoalPosition = transform.position;
- GoalRotation = transform.rotation;
- GoalScale = transform.localScale;
- for (int i = 0; i < solvers.Count; ++i)
- {
- Solver solver = solvers[i];
- if (solver != null && solver.enabled)
- {
- solver.SolverUpdateEntry();
- }
- }
- }
- }
- protected void OnDestroy()
- {
- DetachFromCurrentTrackedObject();
- }
- #endregion MonoBehaviour Implementation
- /// <summary>
- /// Clears the transform target and attaches to the current <see cref="TrackedTargetType"/>.
- /// </summary>
- public void RefreshTrackedObject()
- {
- DetachFromCurrentTrackedObject();
- AttachToNewTrackedObject();
- }
- /// <summary>
- /// Adds <paramref name="solver"/> to the list of <see cref="Solvers"/> guaranteeing inspector ordering.
- /// </summary>
- public void RegisterSolver(Solver solver)
- {
- if (!solvers.Contains(solver))
- {
- solvers.Add(solver);
- updateSolversList = true;
- }
- }
- /// <summary>
- /// Removes <paramref name="solver"/> from the list of <see cref="Solvers"/>.
- /// </summary>
- public void UnregisterSolver(Solver solver)
- {
- solvers.Remove(solver);
- }
- protected virtual void DetachFromCurrentTrackedObject()
- {
- if (trackingTarget != null)
- {
- Destroy(trackingTarget);
- trackingTarget = null;
- }
- }
- protected virtual void AttachToNewTrackedObject()
- {
- if (!transformOverride&& GameSession.Instance&& GameSession.Instance.mainCamera)
- {
- transformOverride = GameSession.Instance.mainCamera.transform;
- }
- if (transformOverride)
- {
- TrackTransform(transformOverride);
- }
- }
- private void TrackTransform(Transform target)
- {
- if (trackingTarget != null || target == null) return;
- string name = string.Format("SolverHandler Target on {0} with offset {1}, {2}", target.gameObject.name, AdditionalOffset, AdditionalRotation);
- trackingTarget = new GameObject(name);
- trackingTarget.hideFlags = HideFlags.HideInHierarchy;
- trackingTarget.transform.parent = target;
- trackingTarget.transform.localPosition = Vector3.Scale(AdditionalOffset, trackingTarget.transform.localScale);
- trackingTarget.transform.localRotation = Quaternion.Euler(AdditionalRotation);
- }
- /// <summary>
- /// Returns true if the solver handler's transform target is not valid
- /// </summary>
- /// <returns>true if not tracking valid hands and/or target, false otherwise</returns>
- private bool IsInvalidTracking()
- {
- if (trackingTarget == null)
- {
- return true;
- }
- return false;
- }
- }
- }
|