Rasagar/Library/PackageCache/com.unity.render-pipelines.core/Runtime/Volume/Volume.cs
2024-08-26 23:07:20 +03:00

167 lines
6.1 KiB
C#

using System.Collections.Generic;
using UnityEngine.Serialization;
namespace UnityEngine.Rendering
{
/// <summary>
/// A generic Volume component holding a <see cref="VolumeProfile"/>.
/// </summary>
[CurrentPipelineHelpURL("Volumes")]
[ExecuteAlways]
[AddComponentMenu("Miscellaneous/Volume")]
public class Volume : MonoBehaviour, IVolume
{
[SerializeField, FormerlySerializedAs("isGlobal")]
bool m_IsGlobal = true;
/// <summary>
/// Specifies whether to apply the Volume to the entire Scene or not.
/// </summary>
public bool isGlobal
{
get => m_IsGlobal;
set => m_IsGlobal = value;
}
/// <summary>
/// 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.
/// </summary>
[Delayed]
public float priority = 0f;
/// <summary>
/// The outer distance to start blending from. A value of 0 means no blending and Unity applies
/// the Volume overrides immediately upon entry.
/// </summary>
public float blendDistance = 0f;
/// <summary>
/// The total weight of this volume in the Scene. 0 means no effect and 1 means full effect.
/// </summary>
[Range(0f, 1f)]
public float weight = 1f;
/// <summary>
/// The shared Profile that this Volume uses.
/// Modifying <c>sharedProfile</c> changes every Volumes that uses this Profile and also changes
/// the Profile settings stored in the Project.
/// </summary>
/// <remarks>
/// You should not modify Profiles that <c>sharedProfile</c> returns. If you want
/// to modify the Profile of a Volume, use <see cref="profile"/> instead.
/// </remarks>
/// <seealso cref="profile"/>
public VolumeProfile sharedProfile = null;
/// <summary>
/// Gets the first instantiated <see cref="VolumeProfile"/> assigned to the Volume.
/// Modifying <c>profile</c> changes the Profile for this Volume only. If another Volume
/// uses the same Profile, this clones the shared Profile and starts using it from now on.
/// </summary>
/// <remarks>
/// This property automatically instantiates the Profile and make it unique to this Volume
/// so you can safely edit it via scripting at runtime without changing the original Asset
/// in the Project.
/// Note that if you pass your own Profile, you must destroy it when you finish using it.
/// </remarks>
/// <seealso cref="sharedProfile"/>
public VolumeProfile profile
{
get
{
if (m_InternalProfile == null)
{
m_InternalProfile = ScriptableObject.CreateInstance<VolumeProfile>();
if (sharedProfile != null)
{
m_InternalProfile.name = sharedProfile.name;
foreach (var item in sharedProfile.components)
{
var itemCopy = Instantiate(item);
m_InternalProfile.components.Add(itemCopy);
}
}
}
return m_InternalProfile;
}
set => m_InternalProfile = value;
}
internal List<Collider> m_Colliders = new List<Collider>();
/// <summary>
/// The colliders of the volume if <see cref="isGlobal"/> is false
/// </summary>
public List<Collider> colliders => m_Colliders;
internal VolumeProfile profileRef => m_InternalProfile == null ? sharedProfile : m_InternalProfile;
/// <summary>
/// Checks if the Volume has an instantiated Profile or if it uses a shared Profile.
/// </summary>
/// <returns><c>true</c> if the profile has been instantiated.</returns>
/// <seealso cref="profile"/>
/// <seealso cref="sharedProfile"/>
public bool HasInstantiatedProfile() => m_InternalProfile != null;
// Needed for state tracking (see the comments in Update)
int m_PreviousLayer;
float m_PreviousPriority;
VolumeProfile m_InternalProfile;
void OnEnable()
{
m_PreviousLayer = gameObject.layer;
VolumeManager.instance.Register(this, m_PreviousLayer);
GetComponents(m_Colliders);
}
void OnDisable()
{
VolumeManager.instance.Unregister(this, gameObject.layer);
}
void Update()
{
// Unfortunately we need to track the current layer to update the volume manager in
// real-time as the user could change it at any time in the editor or at runtime.
// Because no event is raised when the layer changes, we have to track it on every
// frame :/
UpdateLayer();
// Same for priority. We could use a property instead, but it doesn't play nice with the
// serialization system. Using a custom Attribute/PropertyDrawer for a property is
// possible but it doesn't work with Undo/Redo in the editor, which makes it useless for
// our case.
if (priority != m_PreviousPriority)
{
VolumeManager.instance.SetLayerDirty(gameObject.layer);
m_PreviousPriority = priority;
}
#if UNITY_EDITOR
// In the editor, we refresh the list of colliders at every frame because it's frequent to add/remove them
GetComponents(m_Colliders);
#endif
}
internal void UpdateLayer()
{
int layer = gameObject.layer;
if (layer != m_PreviousLayer)
{
VolumeManager.instance.UpdateVolumeLayer(this, m_PreviousLayer, layer);
m_PreviousLayer = layer;
}
}
void OnValidate()
{
blendDistance = Mathf.Max(blendDistance, 0f);
}
}
}