using System; using UnityEngine.Rendering; using UnityEngine.XR.ARSubsystems; using Unity.XR.CoreUtils; namespace UnityEngine.XR.ARFoundation { /// /// A GameObject component to manage the reflection probe settings as the environment probe changes are applied. /// [RequireComponent(typeof(ReflectionProbe))] [DisallowMultipleComponent] [DefaultExecutionOrder(ARUpdateOrder.k_EnvironmentProbe)] [HelpURL(typeof(AREnvironmentProbe))] public class AREnvironmentProbe : ARTrackable { /* * Generated Cubemaps from simulated environment probes cause the ReflectionProbe GUI to spam access error messages. * The issue is creating a read-only texture view from an "external" read-only texture. * By default the Unity Editor cannot normally access external textures for display in the Inspector. * The texture can be seen the Inspector, but ownership information isn't * passed along. Thus the GUI texture display code treats it as an external texture. * To work around this, the hideflags are configured to hide the ReflectionProbe component * in Play Mode. The flags are then reverted when the probe is disabled. * This doesn't affect the ability to save or for user code to access the component. * This should only be done to prevent needless log spam until a better solution is determined. */ #if UNITY_EDITOR const HideFlags k_ProbeHideFlags = HideFlags.DontSave | HideFlags.HideInInspector | HideFlags.NotEditable; #endif /// /// The reflection probe component attached to the GameObject. /// /// /// The reflection probe component attached to the GameObject. /// ReflectionProbe m_ReflectionProbe; /// /// The current environment texture data wrapping the reflection probe environment texture. /// /// /// The current environment texture data wrapping the reflection probe environment texture. /// XRTextureDescriptor m_CurrentTextureDescriptor; /// /// The texture info of the custom baked texture from the reflection probe. /// /// /// The texture info of the custom baked texture from the reflection probe. /// IUpdatableTexture m_CustomBakedUpdatableTexture; /// /// 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; if ((m_ReflectionProbe != null) && (m_ReflectionProbe.customBakedTexture != null)) { m_ReflectionProbe.customBakedTexture.filterMode = m_EnvironmentTextureFilterMode; } } } FilterMode m_EnvironmentTextureFilterMode = FilterMode.Trilinear; #if UNITY_EDITOR HideFlags m_PreviousProbeHideFlags = HideFlags.None; #endif /// /// The placement type (for example, manual or automatic) for this `AREnvironmentProbe`. /// If manual, this probe was created by instantiating a with the component /// or by adding an `AREnvironmentProbe` with . /// public AREnvironmentProbePlacementType placementType { get; internal set; } /// /// The size (dimensions) of the environment probe. /// public Vector3 size => sessionRelativeData.size; /// /// The extents of the environment probe. This is always half the . /// public Vector3 extents => size * .5f; /// /// The XRTextureDescriptor associated with this environment probe. This is used to generate the cubemap texture on the reflection probe component. /// public XRTextureDescriptor textureDescriptor => m_CurrentTextureDescriptor; /// /// Initializes the GameObject transform and reflection probe component from the scene. /// void Awake() { m_ReflectionProbe = GetComponent(); // Set the reflection probe mode to use a custom baked texture. m_ReflectionProbe.mode = ReflectionProbeMode.Custom; } Transform GetTrackablesParent() { if (AREnvironmentProbeManager.instance is AREnvironmentProbeManager manager) { return manager.GetComponent().TrackablesParent; } return null; } /// protected internal override void OnAfterSetSessionRelativeData() { var trackablesParent = GetTrackablesParent(); if (trackablesParent && transform.parent != trackablesParent) { var pose = sessionRelativeData.pose; // Compute the desired world space transform matrix for the environment probe var desiredLocalToWorld = trackablesParent.localToWorldMatrix * Matrix4x4.TRS(pose.position, pose.rotation, sessionRelativeData.scale); if (transform.parent) { // If the probe has a parent (i.e., it is not at the root), then we need to compute // its localScale such that its final world-space scale will match what it would be // if it were under the XROrigin. var localToParent = transform.parent.worldToLocalMatrix * desiredLocalToWorld; transform.localScale = localToParent.lossyScale; } else { // Otherwise, it is at the scene root, so just set its localScale is its world-space scale. transform.localScale = desiredLocalToWorld.lossyScale; } } else { transform.localScale = sessionRelativeData.scale; } // Update the environment texture if the environment texture is valid. m_ReflectionProbe.enabled = sessionRelativeData.textureDescriptor.valid; if (sessionRelativeData.textureDescriptor.valid) { UpdateEnvironmentTexture(sessionRelativeData.textureDescriptor); } // Update the reflection probe box. m_ReflectionProbe.center = Vector3.zero; m_ReflectionProbe.size = sessionRelativeData.size; m_ReflectionProbe.boxProjection = !float.IsInfinity(m_ReflectionProbe.size.x); // Manual placement is set by the manager. Unknown means it must have been added automatically. if (placementType == AREnvironmentProbePlacementType.Unknown) { placementType = AREnvironmentProbePlacementType.Automatic; } } /// /// Applies the texture data in the XRTextureDescriptor to the reflection probe settings. /// /// The environment texture data to apply to the reflection probe baked texture. void UpdateEnvironmentTexture(XRTextureDescriptor descriptor) { if (m_ReflectionProbe.customBakedTexture == null) { m_CustomBakedUpdatableTexture = UpdatableTextureFactory.Create(descriptor); } else { // always succeeds for Cubemap m_CustomBakedUpdatableTexture.TryUpdateFromDescriptor(descriptor); } m_CustomBakedUpdatableTexture.texture.filterMode = m_EnvironmentTextureFilterMode; m_ReflectionProbe.customBakedTexture = m_CustomBakedUpdatableTexture.texture as Cubemap; // Update the current environment texture metadata. m_CurrentTextureDescriptor = descriptor; } /// /// Generates a string representation of this . /// /// A string representation of this . public override string ToString() => $"{name} [trackableId:{trackableId.ToString()}]"; void OnEnable() { #if UNITY_EDITOR m_PreviousProbeHideFlags = m_ReflectionProbe.hideFlags; m_ReflectionProbe.hideFlags = k_ProbeHideFlags; #endif if (AREnvironmentProbeManager.instance is AREnvironmentProbeManager manager) { manager.TryAddEnvironmentProbe(this); } else { pending = true; } } void Update() { if (trackableId.Equals(TrackableId.invalidId) && AREnvironmentProbeManager.instance is AREnvironmentProbeManager manager) { manager.TryAddEnvironmentProbe(this); } } void OnDisable() { #if UNITY_EDITOR m_ReflectionProbe.hideFlags = m_PreviousProbeHideFlags; m_PreviousProbeHideFlags = HideFlags.None; #endif if (AREnvironmentProbeManager.instance is AREnvironmentProbeManager manager) { manager.TryRemoveEnvironmentProbe(this); } } } }