using System; using System.Collections.Generic; using UnityEngine.Serialization; namespace UnityEngine.Rendering.HighDefinition { /// /// Class controlling which sky is used for static and baked lighting. /// [HelpURL(Documentation.baseURL + Documentation.version + Documentation.subURL + "Static-Lighting-Sky" + Documentation.endURL)] [ExecuteAlways] [AddComponentMenu("")] // Hide this object from the Add Component menu public class StaticLightingSky : MonoBehaviour { [SerializeField] VolumeProfile m_Profile; [SerializeField, FormerlySerializedAs("m_BakingSkyUniqueID")] int m_StaticLightingSkyUniqueID = 0; int m_LastComputedHash; bool m_NeedUpdateStaticLightingSky; SkySettings m_SkySettings; // This one contain only property values from overridden properties in the original profile component SkySettings m_SkySettingsFromProfile; internal SkySettings skySettings { get { GetSkyFromIDAndVolume(m_StaticLightingSkyUniqueID, m_Profile, out var skyFromProfile, out var skyType); if (skyFromProfile != null) { int newHash = skyFromProfile.GetHashCode(); if (m_LastComputedHash != newHash) UpdateCurrentStaticLightingSky(); } else { ResetSky(); } return m_SkySettings; } } List m_VolumeSkyList = new List(); /// /// Volume profile where the sky settings used for static lighting will be fetched. /// public VolumeProfile profile { get { return m_Profile; } set { if (value != m_Profile) { // Changing the volume is considered a destructive operation => reset the static lighting sky. m_StaticLightingSkyUniqueID = 0; //Registration is also done when we go from null to not null if (m_Profile == null) SkyManager.RegisterStaticLightingSky(this); //Unregistration is also done when we go from not null to null if (value == null) SkyManager.UnRegisterStaticLightingSky(this); } m_Profile = value; } } /// /// Unique ID of the sky used for static lighting. /// The unique ID should be for a sky that is present in the profile. See SkySettings.GetUniqueID to get the ID per sky type. /// public int staticLightingSkyUniqueID { get { return m_StaticLightingSkyUniqueID; } set { m_StaticLightingSkyUniqueID = value; UpdateCurrentStaticLightingSky(); } } void GetSkyFromIDAndVolume(int skyUniqueID, VolumeProfile profile, out SkySettings skySetting, out System.Type skyType) { skySetting = null; skyType = typeof(SkySettings); if (profile != null && skyUniqueID != 0) { m_VolumeSkyList.Clear(); if (profile.TryGetAllSubclassOf(typeof(SkySettings), m_VolumeSkyList)) { foreach (var sky in m_VolumeSkyList) { if (skyUniqueID == SkySettings.GetUniqueID(sky.GetType()) && sky.active) { skyType = sky.GetType(); skySetting = sky; } } } } } void UpdateCurrentStaticLightingSky() { // First, grab the sky settings of the right type in the profile. CoreUtils.Destroy(m_SkySettings); m_SkySettings = null; m_LastComputedHash = 0; GetSkyFromIDAndVolume(m_StaticLightingSkyUniqueID, m_Profile, out m_SkySettingsFromProfile, out var skyType); if (m_SkySettingsFromProfile != null) { // The static lighting sky is a Volume Component that lives outside of the volume system (we just grab a component from a profile) // As such, it may contain values that are not actually overridden // For example, user overrides a value, change it, and disable overrides. In this case the volume still contains the old overridden value // In this case, we want to use values only if they are still overridden, so we create a volume component with default values and then copy the overridden values from the profile. // Also, a default profile might be set in the HDRP project settings, this volume is applied by default to all the scene so it should also be taken into account here. // Create an instance with default values m_SkySettings = (SkySettings)ScriptableObject.CreateInstance(skyType); var newSkyParameters = m_SkySettings.parameters; var profileSkyParameters = m_SkySettingsFromProfile.parameters; var defaultVolume = HDRenderPipeline.GetOrCreateDefaultVolume(); SkySettings defaultSky = null; if (defaultVolume.sharedProfile != null) // This can happen with old projects. defaultVolume.sharedProfile.TryGet(skyType, out defaultSky); var defaultSkyParameters = defaultSky != null ? defaultSky.parameters : null; // Can be null if the profile does not contain the component. // Seems to inexplicably happen sometimes on domain reload. if (profileSkyParameters == null) { return; } int parameterCount = m_SkySettings.parameters.Count; // Copy overridden parameters. for (int i = 0; i < parameterCount; ++i) { if (profileSkyParameters[i].overrideState == true) { newSkyParameters[i].SetValue(profileSkyParameters[i]); } // Fallback to the default profile if values are overridden in there. else if (defaultSkyParameters != null && defaultSkyParameters[i].overrideState == true) { newSkyParameters[i].SetValue(defaultSkyParameters[i]); } } m_LastComputedHash = m_SkySettingsFromProfile.GetHashCode(); } } // All actions done in this method are because Editor won't go through setters so we need to manually check consistency of our data. void OnValidate() { if (!isActiveAndEnabled) return; // If we detect that the profile has been removed we need to reset the static lighting sky. if (m_Profile == null) { m_StaticLightingSkyUniqueID = 0; } // If we detect that the profile has changed, we need to reset the static lighting sky. // We have to do that manually because PropertyField won't go through setters. if (profile != null && m_SkySettingsFromProfile != null) { if (!profile.components.Find(x => x == m_SkySettingsFromProfile)) { m_StaticLightingSkyUniqueID = 0; } } // We can't call UpdateCurrentStaticLightingSky in OnValidate because we may destroy an object there and it's forbidden. // So we delay the update. m_NeedUpdateStaticLightingSky = true; } void OnEnable() { UpdateCurrentStaticLightingSky(); if (m_Profile != null) SkyManager.RegisterStaticLightingSky(this); } void OnDisable() { if (m_Profile != null) SkyManager.UnRegisterStaticLightingSky(this); ResetSky(); } void Update() { if (m_NeedUpdateStaticLightingSky) { UpdateCurrentStaticLightingSky(); m_NeedUpdateStaticLightingSky = false; } } void ResetSky() { CoreUtils.Destroy(m_SkySettings); m_SkySettings = null; m_SkySettingsFromProfile = null; m_LastComputedHash = 0; } } }