mixedreality/com.microsoft.mixedreality..../Core/Utilities/SceneContent/MixedRealitySceneContent.cs

160 lines
6.4 KiB
C#

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Microsoft.MixedReality.Toolkit.Utilities;
using System.Collections;
using UnityEngine;
using UnityEngine.XR;
namespace Microsoft.MixedReality.Toolkit
{
/// <summary>
/// Use this script on GameObjects you wish to be aligned in certain ways depending on the application space type.
/// For example, if you want to place an object at the height of the user's head in a room scale application, check alignWithHeadHeight.
/// In a stationary scale application, this is equivalent to placing the object at a height of 0.
/// You can also specify specific locations to place the object based on space type.
///
/// This script runs once, on GameObject creation.
/// </summary>
public class MixedRealitySceneContent : MonoBehaviour
{
private enum AlignmentType
{
AlignWithExperienceScale,
AlignWithHeadHeight,
AlignWithHeadPose
}
[SerializeField]
[Tooltip("Select this if the container should be placed in front of the head on app launch in a room scale app.")]
private AlignmentType alignmentType = AlignmentType.AlignWithExperienceScale;
[SerializeField]
[Tooltip("Optional container object reference. If null, this script will move the object it's attached to.")]
private Transform containerObject = null;
private Vector3 contentPosition = Vector3.zero;
private Quaternion contentOrientation = Quaternion.identity;
private const uint MaxEditorFrameWaitCount = 15;
private Coroutine initializeSceneContentWithDelay;
private void Awake()
{
if (containerObject == null)
{
containerObject = transform;
}
// Init the content height on non-XR platforms
initializeSceneContentWithDelay = StartCoroutine(InitializeSceneContentWithDelay());
}
private void OnDestroy()
{
if (initializeSceneContentWithDelay != null)
{
StopCoroutine(initializeSceneContentWithDelay);
}
}
// Not waiting often caused the camera's position to be incorrect at this point. This seems like a Unity bug.
// Editor takes a little longer to init.
private IEnumerator InitializeSceneContentWithDelay()
{
if (Application.isEditor)
{
for (int i = 0; i < MaxEditorFrameWaitCount; i++)
{
yield return null;
}
}
else
{
yield return null;
}
InitializeSceneContent();
initializeSceneContentWithDelay = null;
}
// <summary>
// bool used to track whether this content has been initialized yet.
// </summary>
private bool contentInitialized = false;
/// <summary>
/// Initializes the scene content based on the experience settings
/// Should only be called once.
/// </summary>
public void InitializeSceneContent()
{
if (contentInitialized || containerObject == null)
{
return;
}
MixedRealityExperienceSettingsProfile experienceSettingsProfile = MixedRealityToolkit.Instance.ActiveProfile.ExperienceSettingsProfile;
switch (alignmentType)
{
case AlignmentType.AlignWithExperienceScale:
bool experienceAdjustedByXRDevice =
#if UNITY_2020_1_OR_NEWER
XRSubsystemHelpers.InputSubsystem != null && XRSubsystemHelpers.InputSubsystem.GetTrackingOriginMode().HasFlag(TrackingOriginModeFlags.Floor);
#elif UNITY_2019_1_OR_NEWER
(XRSubsystemHelpers.InputSubsystem != null && XRSubsystemHelpers.InputSubsystem.GetTrackingOriginMode().HasFlag(TrackingOriginModeFlags.Floor)) ||
#pragma warning disable 0618
(XRDevice.isPresent && XRDevice.GetTrackingSpaceType() == TrackingSpaceType.RoomScale);
#pragma warning restore 0618
#else
XRDevice.isPresent && XRDevice.GetTrackingSpaceType() == TrackingSpaceType.RoomScale;
#endif // UNITY_2020_1_OR_NEWER
// The scene content will be adjusted upwards if the target experience scale is set to room or world scale
// AND if we are either in editor (!XRDevicePresent) or we are on an XR device that will adjust the camera's height
if ((experienceSettingsProfile.TargetExperienceScale == ExperienceScale.Room ||
experienceSettingsProfile.TargetExperienceScale == ExperienceScale.World) &&
(!DeviceUtility.IsPresent || experienceAdjustedByXRDevice))
{
contentPosition.x = containerObject.position.x;
contentPosition.y = containerObject.position.y + experienceSettingsProfile.ContentOffset;
contentPosition.z = containerObject.position.z;
containerObject.position = contentPosition;
}
break;
case AlignmentType.AlignWithHeadHeight:
contentPosition.x = containerObject.position.x;
contentPosition.y = containerObject.position.y + CameraCache.Main.transform.position.y;
contentPosition.z = containerObject.position.z;
containerObject.position = contentPosition;
break;
case AlignmentType.AlignWithHeadPose:
ReorientContent();
break;
}
contentInitialized = true;
}
/// <summary>
/// Reorients the scene content based on the camera direction
/// </summary>
public void ReorientContent()
{
contentPosition.x = CameraCache.Main.transform.localPosition.x;
contentPosition.y = CameraCache.Main.transform.localPosition.y;
contentPosition.z = CameraCache.Main.transform.localPosition.z;
contentOrientation.y = CameraCache.Main.transform.rotation.y;
contentOrientation.w = CameraCache.Main.transform.rotation.w;
containerObject.localPosition = contentPosition;
containerObject.localRotation = contentOrientation;
}
}
}