using System; using System.Collections.Generic; using UnityEngine.XR.ARSubsystems; 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. /// /// /// Related information: Environment probes /// [DisallowMultipleComponent] [DefaultExecutionOrder(ARUpdateOrder.k_EnvironmentProbeManager)] [AddComponentMenu("XR/AR Foundation/AR Environment Probe Manager")] [HelpURL("features/environment-probes", "ar-environment-probe-manager-component")] public sealed class AREnvironmentProbeManager : ARTrackableManager< XREnvironmentProbeSubsystem, XREnvironmentProbeSubsystemDescriptor, XREnvironmentProbeSubsystem.Provider, XREnvironmentProbe, AREnvironmentProbe> { bool supportsAutomaticPlacement => descriptor?.supportsAutomaticPlacement == true; /// /// If enabled, requests automatic generation of environment probes for the scene. /// /// /// if automatic environment probe placement is requested. Otherwise, . /// public bool automaticPlacementRequested { get => supportsAutomaticPlacement ? subsystem.automaticPlacementRequested : m_AutomaticPlacement; set { m_AutomaticPlacement = value; SetAutomaticPlacementStateOnSubsystem(); } } /// /// if automatic placement is enabled on the subsystem. /// public bool automaticPlacementEnabled => supportsAutomaticPlacement && subsystem.automaticPlacementEnabled; [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. /// 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; [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. /// /// /// if high dynamic range environment textures are requested. Otherwise, . /// public bool environmentTextureHDRRequested { get => supportsEnvironmentTextureHDR ? subsystem.environmentTextureHDRRequested : m_EnvironmentTextureHDR; set { m_EnvironmentTextureHDR = value; SetEnvironmentTextureHDRStateOnSubsystem(); } } /// /// Queries whether environment textures are provided with high dynamic range (HDR). /// /// /// if environment textures are HDR. Otherwise, . /// public bool environmentTextureHDREnabled => supportsEnvironmentTextureHDR && subsystem.environmentTextureHDREnabled; /// /// Specifies a debug prefab that will be attached to all environment probes. /// /// The debug prefab. /// /// Setting a debug prefab allows for 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 . /// 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. /// [Obsolete("environmentProbesChanged has been deprecated in AR Foundation version 6.0. Use trackablesChanged instead.", false)] 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; } 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 = origin.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 XR 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; } internal bool TryRemoveEnvironmentProbe(AREnvironmentProbe probe) { if (probe == null || subsystem == null) return false; var desc = descriptor; if (probe.placementType == AREnvironmentProbePlacementType.Manual && !desc.supportsRemovalOfManual) return false; if (probe.placementType == AREnvironmentProbePlacementType.Automatic && !desc.supportsRemovalOfAutomatic) return false; if (subsystem.RemoveEnvironmentProbe(probe.trackableId)) { if (m_PendingAdds.ContainsKey(probe.trackableId)) { m_PendingAdds.Remove(probe.trackableId); m_Trackables.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(); } #if UNITY_EDITOR void OnValidate() { SetAutomaticPlacementStateOnSubsystem(); } #endif // UNITY_EDITOR /// /// 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 . [Obsolete("OnTrackablesChanged() has been deprecated in AR Foundation version 6.0.", false)] protected override void OnTrackablesChanged( List added, List updated, List removed) { if (environmentProbesChanged != null) { using (new ScopedProfiler("OnEnvironmentProbesChanged")) { environmentProbesChanged?.Invoke(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; } } } }