A game about forced loneliness, made by TACStudios
1using System; 2using System.Collections.Generic; 3using UnityEngine.Serialization; 4 5namespace UnityEngine.Rendering 6{ 7 /// <summary> 8 /// A generic Volume component holding a <see cref="VolumeProfile"/>. 9 /// </summary> 10 [CurrentPipelineHelpURL("Volumes")] 11 [ExecuteAlways] 12 [AddComponentMenu("Miscellaneous/Volume")] 13 public class Volume : MonoBehaviour, IVolume 14 { 15 [SerializeField, FormerlySerializedAs("isGlobal")] 16 bool m_IsGlobal = true; 17 18 /// <summary> 19 /// Specifies whether to apply the Volume to the entire Scene or not. 20 /// </summary> 21 public bool isGlobal 22 { 23 get => m_IsGlobal; 24 set => m_IsGlobal = value; 25 } 26 27 /// <summary> 28 /// A value which determines which Volume is being used when Volumes have an equal amount of influence on the Scene. Volumes with a higher priority will override lower ones. 29 /// </summary> 30 [Delayed] 31 public float priority = 0f; 32 33 /// <summary> 34 /// The outer distance to start blending from. A value of 0 means no blending and Unity applies 35 /// the Volume overrides immediately upon entry. 36 /// </summary> 37 public float blendDistance = 0f; 38 39 /// <summary> 40 /// The total weight of this volume in the Scene. 0 means no effect and 1 means full effect. 41 /// </summary> 42 [Range(0f, 1f)] 43 public float weight = 1f; 44 45 /// <summary> 46 /// The shared Profile that this Volume uses. 47 /// Modifying <c>sharedProfile</c> changes every Volumes that uses this Profile and also changes 48 /// the Profile settings stored in the Project. 49 /// </summary> 50 /// <remarks> 51 /// You should not modify Profiles that <c>sharedProfile</c> returns. If you want 52 /// to modify the Profile of a Volume, use <see cref="profile"/> instead. 53 /// </remarks> 54 /// <seealso cref="profile"/> 55 public VolumeProfile sharedProfile = null; 56 57 /// <summary> 58 /// Gets the first instantiated <see cref="VolumeProfile"/> assigned to the Volume. 59 /// Modifying <c>profile</c> changes the Profile for this Volume only. If another Volume 60 /// uses the same Profile, this clones the shared Profile and starts using it from now on. 61 /// </summary> 62 /// <remarks> 63 /// This property automatically instantiates the Profile and make it unique to this Volume 64 /// so you can safely edit it via scripting at runtime without changing the original Asset 65 /// in the Project. 66 /// Note that if you pass your own Profile, you must destroy it when you finish using it. 67 /// </remarks> 68 /// <seealso cref="sharedProfile"/> 69 public VolumeProfile profile 70 { 71 get 72 { 73 if (m_InternalProfile == null) 74 { 75 m_InternalProfile = ScriptableObject.CreateInstance<VolumeProfile>(); 76 77 if (sharedProfile != null) 78 { 79 m_InternalProfile.name = sharedProfile.name; 80 81 foreach (var item in sharedProfile.components) 82 { 83 var itemCopy = Instantiate(item); 84 m_InternalProfile.components.Add(itemCopy); 85 } 86 } 87 } 88 89 return m_InternalProfile; 90 } 91 set => m_InternalProfile = value; 92 } 93 94 internal List<Collider> m_Colliders = new List<Collider>(); 95 96 /// <summary> 97 /// The colliders of the volume if <see cref="isGlobal"/> is false 98 /// </summary> 99 public List<Collider> colliders => m_Colliders; 100 101 internal VolumeProfile profileRef => m_InternalProfile == null ? sharedProfile : m_InternalProfile; 102 103 /// <summary> 104 /// Checks if the Volume has an instantiated Profile or if it uses a shared Profile. 105 /// </summary> 106 /// <returns><c>true</c> if the profile has been instantiated.</returns> 107 /// <seealso cref="profile"/> 108 /// <seealso cref="sharedProfile"/> 109 public bool HasInstantiatedProfile() => m_InternalProfile != null; 110 111 // Needed for state tracking (see the comments in Update) 112 int m_PreviousLayer; 113 float m_PreviousPriority; 114 VolumeProfile m_InternalProfile; 115 116 void OnEnable() 117 { 118 m_PreviousLayer = gameObject.layer; 119 VolumeManager.instance.Register(this); 120 GetComponents(m_Colliders); 121 } 122 123 void OnDisable() 124 { 125 VolumeManager.instance.Unregister(this); 126 } 127 128 void Update() 129 { 130 UpdateLayer(); 131 UpdatePriority(); 132 133#if UNITY_EDITOR 134 // In the editor, we refresh the list of colliders at every frame because it's frequent to add/remove them 135 GetComponents(m_Colliders); 136#endif 137 } 138 139 internal void UpdateLayer() 140 { 141 // Unfortunately we need to track the current layer to update the volume manager in 142 // real-time as the user could change it at any time in the editor or at runtime. 143 // Because no event is raised when the layer changes, we have to track it on every 144 // frame :/ 145 146 int layer = gameObject.layer; 147 if (layer == m_PreviousLayer) 148 return; 149 150 VolumeManager.instance.UpdateVolumeLayer(this, m_PreviousLayer, layer); 151 m_PreviousLayer = layer; 152 } 153 154 internal void UpdatePriority() 155 { 156 if (!(Math.Abs(priority - m_PreviousPriority) > Mathf.Epsilon)) 157 return; 158 159 // Same for priority. We could use a property instead, but it doesn't play nice with the 160 // serialization system. Using a custom Attribute/PropertyDrawer for a property is 161 // possible but it doesn't work with Undo/Redo in the editor, which makes it useless for 162 // our case. 163 VolumeManager.instance.SetLayerDirty(gameObject.layer); 164 m_PreviousPriority = priority; 165 } 166 167 void OnValidate() 168 { 169 blendDistance = Mathf.Max(blendDistance, 0f); 170 } 171 } 172}