using System;
using System.Collections.Generic;
using System.ComponentModel;
using UnityEngine;
using UnityEngine.XR.ARSubsystems;
using Object = UnityEngine.Object;
namespace UnityEngine.XR.ARFoundation
{
///
/// This class creates, maintains, and destroys environment probe GameObject components as the
/// XREnvironmentProbeSubsystem provides updates from environment probes as they are detected in the
/// environment.
///
[DisallowMultipleComponent]
[DefaultExecutionOrder(ARUpdateOrder.k_EnvironmentProbeManager)]
[HelpURL(HelpUrls.ApiWithNamespace + nameof(AREnvironmentProbeManager) + ".html")]
public sealed class AREnvironmentProbeManager : ARTrackableManager<
XREnvironmentProbeSubsystem,
XREnvironmentProbeSubsystemDescriptor,
XREnvironmentProbeSubsystem.Provider,
XREnvironmentProbe,
AREnvironmentProbe>
{
///
/// A property of the environment probe subsystem that, if enabled, automatically generates environment probes
/// for the scene.
/// This method is obsolete.
/// Use or instead.
///
///
/// true if automatic environment probe placement is enabled. Otherwise, false.
///
[Obsolete("Use automaticPlacementRequested or automaticPlacementEnabled instead. (2020-01-16)")]
public bool automaticPlacement
{
get => m_AutomaticPlacement;
set => automaticPlacementRequested = value;
}
bool supportsAutomaticPlacement => descriptor?.supportsAutomaticPlacement == true;
///
/// If enabled, requests automatic generation of environment probes for the scene.
///
///
/// true if automatic environment probe placement is requested. Otherwise, false.
///
public bool automaticPlacementRequested
{
get => supportsAutomaticPlacement ? subsystem.automaticPlacementRequested : m_AutomaticPlacement;
set
{
m_AutomaticPlacement = value;
SetAutomaticPlacementStateOnSubsystem();
}
}
///
/// true if automatic placement is enabled on the subsystem.
///
public bool automaticPlacementEnabled => supportsAutomaticPlacement ? subsystem.automaticPlacementEnabled : false;
[SerializeField]
[Tooltip("Whether environment probes should be automatically placed in the environment (if supported).")]
bool m_AutomaticPlacement = true;
///
/// Specifies the texture filter mode to be used with the environment texture.
///
///
/// The texture filter mode to be used with the environment texture.
///
public FilterMode environmentTextureFilterMode
{
get => m_EnvironmentTextureFilterMode;
set => m_EnvironmentTextureFilterMode = value;
}
[SerializeField]
[Tooltip("The texture filter mode to be used with the reflection probe environment texture.")]
FilterMode m_EnvironmentTextureFilterMode = FilterMode.Trilinear;
///
/// Specifies whether the environment textures should be returned as HDR textures.
///
///
/// true if the environment textures should be returned as HDR textures. Otherwise, false.
///
[Obsolete("Use environmentTextureHDRRequested or environmentTextureHDREnabled instead. (2020-01-16)")]
public bool environmentTextureHDR
{
get => m_EnvironmentTextureHDR;
set => environmentTextureHDRRequested = value;
}
[SerializeField]
[Tooltip("Whether the environment textures should be returned as HDR textures.")]
bool m_EnvironmentTextureHDR = true;
bool supportsEnvironmentTextureHDR => descriptor?.supportsEnvironmentTextureHDR == true;
///
/// Get or set whether high dynamic range environment textures are requested.
///
///
public bool environmentTextureHDRRequested
{
get => supportsEnvironmentTextureHDR ? subsystem.environmentTextureHDRRequested : m_EnvironmentTextureHDR;
set
{
m_EnvironmentTextureHDR = value;
SetEnvironmentTextureHDRStateOnSubsystem();
}
}
///
/// Queries whether environment textures will be provided with high dynamic range.
///
public bool environmentTextureHDREnabled => supportsEnvironmentTextureHDR ? subsystem.environmentTextureHDREnabled : false;
///
/// Specifies a debug Prefab that will be attached to all environment probes.
///
///
/// A debug Prefab that will be attached to all environment probes.
///
///
/// Setting a debug Prefab allows for these environment probes to be more readily visualized but is not
/// required for normal operation of this manager. This script will automatically create reflection probes for
/// all environment probes reported by the XREnvironmentProbeSubsystem.
///
public GameObject debugPrefab
{
get => m_DebugPrefab;
set => m_DebugPrefab = value;
}
[SerializeField]
[Tooltip("A debug prefab that allows for these environment probes to be more readily visualized.")]
GameObject m_DebugPrefab;
///
/// Invoked once per frame with lists of environment probes that have been added, updated, and removed since the last frame.
///
public event Action environmentProbesChanged;
///
/// Attempts to find the environment probe matching the trackable ID currently in the scene.
///
/// The trackable ID of an environment probe to search for.
///
/// Environment probe in the scene matching the , or null if no matching
/// environment probe is found.
///
public AREnvironmentProbe GetEnvironmentProbe(TrackableId trackableId)
{
if (m_Trackables.TryGetValue(trackableId, out var environmentProbe))
return environmentProbe;
return null;
}
///
/// Creates a new environment probe at with and
/// if supported by the subsystem. Use the 's
/// `supportsManualPlacement` property to determine support for this feature. If successful, a new
/// GameObject with an is created
/// immediately; however, the provider might not report the environment probe as added until a future frame. Check the
/// status of the probe by inspecting its
/// property.
///
/// The position and rotation at which to create the new environment probe.
/// The scale of the new environment probe.
/// The size (dimensions) of the new environment probe.
/// A new if successful, otherwise null.
/// Thrown if this manager is not enabled
/// Thrown if this manager has no subsystem.
/// Thrown if manual placement is not supported by this subsystem.
/// Check for support on the 's
/// `supportsManualPlacement` property.
[Obsolete("Add an environment probe using AddComponent<" + nameof(AREnvironmentProbe) + ">(). (2020-10-06)")]
public AREnvironmentProbe AddEnvironmentProbe(Pose pose, Vector3 scale, Vector3 size)
{
if (!enabled)
throw new InvalidOperationException("Cannot create an environment probe from a disabled environment probe manager.");
if (subsystem == null)
throw new InvalidOperationException("Environment probe manager has no subsystem. Enable the manager first.");
if (!descriptor.supportsManualPlacement)
throw new NotSupportedException("Manual environment probe placement is not supported by this subsystem.");
var sessionRelativePose = sessionOrigin.trackablesParent.InverseTransformPose(pose);
if (subsystem.TryAddEnvironmentProbe(sessionRelativePose, scale, size, out var sessionRelativeData))
{
var probe = CreateTrackableImmediate(sessionRelativeData);
probe.placementType = AREnvironmentProbePlacementType.Manual;
return probe;
}
return null;
}
internal bool TryAddEnvironmentProbe(AREnvironmentProbe probe)
{
if (!CanBeAddedToSubsystem(probe))
return false;
var reflectionProbe = probe.GetComponent();
if (reflectionProbe == null)
throw new InvalidOperationException($"Each {nameof(AREnvironmentProbe)} requires a {nameof(ReflectionProbe)} component.");
if (!descriptor.supportsManualPlacement)
throw new NotSupportedException("Manual environment probe placement is not supported by this subsystem.");
var probeTransform = probe.transform;
var trackablesParent = sessionOrigin.trackablesParent;
var poseInSessionSpace = trackablesParent.InverseTransformPose(new Pose(probeTransform.position, probeTransform.rotation));
var worldToLocalSession = trackablesParent.worldToLocalMatrix;
var localToWorldProbe = probeTransform.localToWorldMatrix;
// We want to calculate the "local-to-parent" of the probe if the session origin were its parent.
// LTW_session * LTP_probe = LTW_probe
// => LTP_probe = inverse(LTW_session) * LTW_probe
var localToParentProbe = worldToLocalSession * localToWorldProbe;
var sessionSpaceScale = localToParentProbe.lossyScale;
if (subsystem.TryAddEnvironmentProbe(poseInSessionSpace, sessionSpaceScale, reflectionProbe.size, out var sessionRelativeData))
{
CreateTrackableFromExisting(probe, sessionRelativeData);
probe.placementType = AREnvironmentProbePlacementType.Manual;
return probe;
}
return false;
}
///
/// Remove an existing environment probe. Support for this feature is provider-specific. Check for support with
/// the 's
/// `supportsRemovalOfManual` and `supportsRemovalOfAutomatic` properties.
///
/// The environment probe to remove
/// true if the environment probe was removed, otherwise false.
/// Thrown if this manager is not enabled.
/// Thrown if
/// is `null`.
/// Thrown if is `null`.
///
/// Thrown if the environment probe was manually placed, but removal of manually placed probes is not supported.
/// You can check for this case with and the
/// 's
/// 'supportsRemovalOfManual` property.
///
///
/// Thrown if the environment probe was automatically placed, but removal of automatically placed probes is not supported.
/// You can check for this case with and the
/// 's
/// `supportsRemovalOfAutomatic` property.
///
[Obsolete("Call Destroy() on the " + nameof(AREnvironmentProbe) + " component to remove it. (2020-10-06)")]
public bool RemoveEnvironmentProbe(AREnvironmentProbe probe)
{
if (!enabled)
throw new InvalidOperationException("Cannot remove an environment probe from a disabled environment probe manager.");
if (subsystem == null)
throw new InvalidOperationException("Environment probe manager has no subsystem. Enable the manager first.");
if (probe == null)
throw new ArgumentNullException(nameof(probe));
var desc = descriptor;
if ((probe.placementType == AREnvironmentProbePlacementType.Manual) && !desc.supportsRemovalOfManual)
throw new InvalidOperationException("Removal of manually placed environment probes is not supported by this subsystem.");
if ((probe.placementType == AREnvironmentProbePlacementType.Automatic) && !desc.supportsRemovalOfAutomatic)
throw new InvalidOperationException("Removal of automatically placed environment probes is not supported by this subsystem.");
if (subsystem.RemoveEnvironmentProbe(probe.trackableId))
{
DestroyPendingTrackable(probe.trackableId);
return true;
}
return false;
}
internal bool TryRemoveEnvironmentProbe(AREnvironmentProbe probe)
{
if (probe == null)
throw new ArgumentNullException(nameof(probe));
if (subsystem == null)
return false;
var desc = descriptor;
if ((probe.placementType == AREnvironmentProbePlacementType.Manual) && !desc.supportsRemovalOfManual)
throw new InvalidOperationException("Removal of manually placed environment probes is not supported by this subsystem.");
if ((probe.placementType == AREnvironmentProbePlacementType.Automatic) && !desc.supportsRemovalOfAutomatic)
throw new InvalidOperationException("Removal of automatically placed environment probes is not supported by this subsystem.");
if (subsystem.RemoveEnvironmentProbe(probe.trackableId))
{
m_Trackables.Remove(probe.trackableId);
m_PendingAdds.Remove(probe.trackableId);
probe.pending = false;
return true;
}
return false;
}
///
/// The name of the `GameObject` for each instantiated .
///
protected override string gameObjectName => nameof(AREnvironmentProbe);
///
/// Gets the prefab that should be instantiated for each . May be `null`.
///
/// The prefab that should be instantiated for each .
protected override GameObject GetPrefab() => m_DebugPrefab;
///
/// Enables the environment probe functionality by registering listeners for the environment probe events, if
/// the XREnvironmentProbeSubsystem exists, and enabling environment probes in the AR subsystem manager.
///
protected override void OnBeforeStart()
{
SetAutomaticPlacementStateOnSubsystem();
SetEnvironmentTextureHDRStateOnSubsystem();
}
///
/// Destroys any game objects created by this environment probe manager for each environment probe, and clears
/// the mapping of environment probes.
///
protected override void OnDestroy()
{
base.OnDestroy();
foreach (var kvp in m_Trackables)
{
var environmentProbe = kvp.Value;
if (environmentProbe != null)
Destroy(environmentProbe.gameObject);
}
}
///
/// Invoked when the base class detects trackable changes.
///
/// The list of added .
/// The list of updated .
/// The list of removed .
protected override void OnTrackablesChanged(
List added,
List updated,
List removed)
{
if (environmentProbesChanged != null)
{
using (new ScopedProfiler("OnEnvironmentProbesChanged"))
{
environmentProbesChanged(new AREnvironmentProbesChangedEvent(added, updated, removed));
}
}
}
///
/// Invoked when an is created.
///
/// The that was just created.
protected override void OnCreateTrackable(AREnvironmentProbe probe)
{
probe.environmentTextureFilterMode = m_EnvironmentTextureFilterMode;
}
///
/// Sets the current state of the property to the
/// XREnvironmentProbeSubsystem, if the subsystem exists and supports automatic placement.
///
void SetAutomaticPlacementStateOnSubsystem()
{
if (enabled && supportsAutomaticPlacement)
{
subsystem.automaticPlacementRequested = m_AutomaticPlacement;
}
}
///
/// Sets the current state of the property to the
/// XREnvironmentProbeSubsystem, if the subsystem exists and supports HDR environment textures.
///
void SetEnvironmentTextureHDRStateOnSubsystem()
{
if (enabled && supportsEnvironmentTextureHDR)
{
subsystem.environmentTextureHDRRequested = m_EnvironmentTextureHDR;
}
}
}
}