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; } } } }