// -------------------------------------------------------------------------------------------------------------------- // // Copyright (c) VRMADA, All rights reserved. // // -------------------------------------------------------------------------------------------------------------------- using System; using UltimateXR.Core; using UnityEngine; namespace UltimateXR.Avatar { /// /// Contains information about an that has moved/rotated. Avatars are moved/rotated /// through functionality such as: /// /// /// /// UxrManager.Instance.MoveAvatarTo /// /// /// /// UxrManager.Instance.RotateAvatar /// /// /// /// UxrManager.Instance.TeleportLocalAvatar /// /// /// /// These methods will move/rotate the root transform of the avatar. If a user moves or rotates in the real-world, the /// camera transform will be updated but the root avatar transform will remain fixed. Only moving or teleporting the /// avatar will generate events. /// public class UxrAvatarMoveEventArgs : EventArgs { #region Public Types & Data /// /// Gets the old position. /// public Vector3 OldPosition { get; } /// /// Gets the old rotation. /// public Quaternion OldRotation { get; } /// /// Gets the new position. /// public Vector3 NewPosition { get; } /// /// Gets the new rotation. /// public Quaternion NewRotation { get; } /// /// Gets the old forward vector. /// public Vector3 OldForward { get; private set; } /// /// Gets the new forward vector. /// public Vector3 NewForward { get; private set; } /// /// Gets the old local to world matrix. /// public Matrix4x4 OldWorldMatrix { get; private set; } /// /// Gets the new local to world matrix. /// public Matrix4x4 NewWorldMatrix { get; private set; } /// /// Gets whether the avatar has changed its position. /// public bool HasTranslation { get; private set; } /// /// Gets whether the avatar has changed its rotation. /// public bool HasRotation { get; private set; } #endregion #region Constructors & Finalizer /// /// Constructor. /// /// Old position /// Old rotation /// New position /// New rotation public UxrAvatarMoveEventArgs(Vector3 oldPosition, Quaternion oldRotation, Vector3 newPosition, Quaternion newRotation) { OldPosition = oldPosition; OldRotation = oldRotation; NewPosition = newPosition; NewRotation = newRotation; ComputeInternalData(); } #endregion #region Public Overrides object /// public override string ToString() { if (HasTranslation && HasRotation) { return $"Avatar moved (OldPosition={OldPosition}, OldRotation={OldRotation}, NewPosition={NewPosition}, NewRotation={NewRotation})"; } if (HasTranslation) { return $"Avatar moved (OldPosition={OldPosition}, NewPosition={NewPosition})"; } return $"Avatar moved (OldRotation={OldPosition}, NewRotation={NewPosition})"; } #endregion #region Public Methods /// /// Reorients and repositions a transform so that it keeps the relative position/orientation to the avatar after the /// position changed event. /// /// Transform to reorient/reposition public void ReorientRelativeToAvatar(Transform transform) { GetKeepRelativeOrientationToAvatar(transform, out Vector3 position, out Quaternion rotation); transform.SetPositionAndRotation(position, rotation); } /// /// Gets the new position and rotation an object would need to have to keep the same relative position/rotation to /// the avatar after moving. /// /// The transform to get the new position/rotation of /// The new position /// The new rotation public void GetKeepRelativeOrientationToAvatar(Transform transform, out Vector3 position, out Quaternion rotation) { Vector3 relativePos = _oldWorldMatrixInverse.MultiplyPoint(transform.position); Quaternion relativeRot = _oldRotationInverse * transform.rotation; position = NewWorldMatrix.MultiplyPoint(relativePos); rotation = NewRotation * relativeRot; } #endregion #region Private Methods /// /// Computes the helper properties and internal variables. /// private void ComputeInternalData() { OldForward = OldRotation * Vector3.forward; NewForward = NewRotation * Vector3.forward; OldWorldMatrix = Matrix4x4.TRS(OldPosition, OldRotation, Vector3.one); NewWorldMatrix = Matrix4x4.TRS(NewPosition, NewRotation, Vector3.one); _oldWorldMatrixInverse = OldWorldMatrix.inverse; _oldRotationInverse = Quaternion.Inverse(OldRotation); HasTranslation = OldPosition != NewPosition; HasRotation = OldRotation != NewRotation; } #endregion #region Private Types & Data private Matrix4x4 _oldWorldMatrixInverse; private Quaternion _oldRotationInverse; #endregion } }