// Copyright (c) Microsoft Corporation.
// Copyright(c) 2019 Takahiro Miyaura
// Licensed under the MIT License.
using Microsoft.MixedReality.Toolkit.CameraSystem;
using Microsoft.MixedReality.Toolkit.Utilities;
using UnityEngine;
#if ARFOUNDATION_PRESENT
using UnityEngine.SpatialTracking;
using UnityEngine.XR;
using UnityEngine.XR.ARFoundation;
#endif // ARFOUNDATION_PRESENT
namespace Microsoft.MixedReality.Toolkit.Experimental.UnityAR
{
///
/// Camera settings provider for use with the Unity AR Foundation system.
///
[MixedRealityDataProvider(
typeof(IMixedRealityCameraSystem),
SupportedPlatforms.Android | SupportedPlatforms.IOS,
"Unity AR Foundation Camera Settings",
"UnityAR/Profiles/DefaultUnityARCameraSettingsProfile.asset",
"MixedRealityToolkit.Providers")]
public class UnityARCameraSettings : BaseCameraSettingsProvider
{
///
/// Constructor.
///
/// The instance of the camera system which is managing this provider.
/// Friendly name of the provider.
/// Provider priority. Used to determine order of instantiation.
/// The provider's configuration profile.
public UnityARCameraSettings(
IMixedRealityCameraSystem cameraSystem,
string name = null,
uint priority = DefaultPriority,
BaseCameraSettingsProfile profile = null) : base(cameraSystem, name, priority, profile)
{
ReadProfile();
}
private ArTrackedPose poseSource = ArTrackedPose.ColorCamera;
private ArTrackingType trackingType = ArTrackingType.RotationAndPosition;
private ArUpdateType updateType = ArUpdateType.UpdateAndBeforeRender;
private void ReadProfile()
{
if (SettingsProfile == null)
{
Debug.LogWarning("A profile was not specified for the Unity AR Camera Settings provider.\nUsing Microsoft Mixed Reality Toolkit default options.");
return;
}
poseSource = SettingsProfile.PoseSource;
trackingType = SettingsProfile.TrackingType;
updateType = SettingsProfile.UpdateType;
}
#region IMixedRealityCameraSettings
///
public override bool IsOpaque => poseSource != ArTrackedPose.ColorCamera;
#endregion IMixedRealityCameraSettings
///
/// The profile used to configure the camera.
///
public UnityARCameraSettingsProfile SettingsProfile => ConfigurationProfile as UnityARCameraSettingsProfile;
#if ARFOUNDATION_PRESENT
private bool isSupportedArConfiguration = true;
private bool isInitialized = false;
private GameObject arSessionObject = null;
private bool preExistingArSessionObject = false;
private ARSession arSession = null;
private GameObject arSessionOriginObject = null;
private bool preExistingArSessionOriginObject = false;
private ARSessionOrigin arSessionOrigin = null;
private ARCameraManager arCameraManager = null;
private ARCameraBackground arCameraBackground = null;
private ARInputManager arInputManager = null;
private TrackedPoseDriver trackedPoseDriver = null;
///
/// Examines the scene to determine if AR Foundation components are present.
///
private void FindARFoundationComponents()
{
arSessionObject = GameObject.Find("AR Session");
preExistingArSessionObject = (arSessionObject != null);
arSessionOriginObject = GameObject.Find("AR Session Origin");
preExistingArSessionOriginObject = (arSessionOriginObject != null);
}
///
public override void Initialize()
{
base.Initialize();
// Android platforms support both AR Foundation and VR.
// AR Foundation does not use the player's XR Settings.
// If the loaded device name is not an empty string, then a VR
// SDK is in use (not using AR Foundation).
if (Application.platform == RuntimePlatform.Android)
{
isSupportedArConfiguration = string.IsNullOrWhiteSpace(XRSettings.loadedDeviceName);
}
}
///
public override void Enable()
{
base.Enable();
if (!isInitialized)
{
InitializeARFoundation();
}
}
///
public override void Destroy()
{
UninitializeARFoundation();
base.Destroy();
}
///
/// Initialize AR Foundation components.
///
///
/// This method ensures AR Foundation required components (ex: AR Session, Tracked Pose Driver, etc) are
/// exist or are added to the appropriate scene objects. These components are used by AR Foundation to
/// communicate with the underlying AR platform (ex: AR Core), track the device and perform other necessary tasks.
///
private void InitializeARFoundation()
{
if (!isSupportedArConfiguration) { return; }
if (isInitialized) { return; }
FindARFoundationComponents();
if (arSessionObject == null)
{
arSessionObject = new GameObject("AR Session");
arSessionObject.transform.parent = null;
}
arSession = arSessionObject.EnsureComponent();
arInputManager = arSessionObject.EnsureComponent();
if (arSessionOriginObject == null)
{
arSessionOriginObject = MixedRealityPlayspace.Transform.gameObject;
}
CameraCache.Main.transform.parent = arSessionOriginObject.transform;
arSessionOrigin = arSessionOriginObject.EnsureComponent();
arSessionOrigin.camera = CameraCache.Main;
GameObject cameraObject = arSessionOrigin.camera.gameObject;
arCameraManager = cameraObject.EnsureComponent();
arCameraBackground = cameraObject.EnsureComponent();
trackedPoseDriver = cameraObject.EnsureComponent();
trackedPoseDriver.SetPoseSource(
TrackedPoseDriver.DeviceType.GenericXRDevice,
ArEnumConversion.ToUnityTrackedPose(poseSource));
trackedPoseDriver.trackingType = ArEnumConversion.ToUnityTrackingType(trackingType);
trackedPoseDriver.updateType = ArEnumConversion.ToUnityUpdateType(updateType);
trackedPoseDriver.UseRelativeTransform = false;
isInitialized = true;
}
///
/// Uninitialize and clean up AR Foundation components.
///
private void UninitializeARFoundation()
{
if (!isInitialized) { return; }
if (!preExistingArSessionOriginObject &&
(arSessionOriginObject != null))
{
UnityObjectExtensions.DestroyObject(trackedPoseDriver);
trackedPoseDriver = null;
UnityObjectExtensions.DestroyObject(arCameraBackground);
arCameraBackground = null;
UnityObjectExtensions.DestroyObject(arCameraManager);
arCameraManager = null;
UnityObjectExtensions.DestroyObject(arSessionOrigin);
arSessionOrigin = null;
}
if (!preExistingArSessionObject &&
(arSessionObject != null))
{
UnityObjectExtensions.DestroyObject(arInputManager);
arInputManager = null;
UnityObjectExtensions.DestroyObject(arSession);
arSession = null;
UnityObjectExtensions.DestroyObject(arSessionObject);
arSessionObject = null;
}
isInitialized = false;
}
#endif // ARFOUNDATION_PRESENT
}
}