tree sway and shadow improvements
[WindSway-HDRP.git] / Library / PackageCache / com.unity.postprocessing@2.1.2 / PostProcessing / Runtime / PostProcessVolume.cs
blob474ff10736581b4a3f4a2530ba02b83c98dd5e90
1 using System.Collections.Generic;
3 namespace UnityEngine.Rendering.PostProcessing
5 //
6 // Here's a quick look at the architecture of this framework and how it's integrated into Unity
7 // (written between versions 5.6 and 2017.1):
8 //
9 // Users have to be able to plug in their own effects without having to modify the codebase and
10 // these custom effects should work out-of-the-box with all the other features we provide
11 // (volume blending etc). This relies on heavy use of polymorphism, but the only way to get
12 // the serialization system to work well with polymorphism in Unity is to use ScriptableObjects.
14 // Users can push their custom effects at different (hardcoded) injection points.
16 // Each effect consists of at least two classes (+ shaders): a POD "Settings" class which only
17 // stores parameters, and a "Renderer" class that holds the rendering logic. Settings are linked
18 // to renderers using a PostProcessAttribute. These are automatically collected at init time
19 // using reflection. Settings in this case are ScriptableObjects, we only need to serialize
20 // these.
22 // We could store these settings object straight into each volume and call it a day, but
23 // unfortunately there's one feature of Unity that doesn't work well with scene-stored assets:
24 // prefabs. So we need to store all of these settings in a disk-asset and treat them as
25 // sub-assets.
27 // Note: We have to use ScriptableObject for everything but these don't work with the Animator
28 // tool. It's unfortunate but it's the only way to make it easily extensible. On the other
29 // hand, users can animate post-processing effects using Volumes or straight up scripting.
31 // Volume blending leverages the physics system for distance checks to the nearest point on
32 // volume colliders. Each volume can have several colliders or any type (cube, mesh...), making
33 // it quite a powerful feature to use.
35 // Volumes & blending are handled by a singleton manager (see PostProcessManager).
37 // Rendering is handled by a PostProcessLayer component living on the camera, which mean you
38 // can easily toggle post-processing on & off or change the anti-aliasing type per-camera,
39 // which is very useful when doing multi-layered camera rendering or any other technique that
40 // involves multiple-camera setups. This PostProcessLayer component can also filters volumes
41 // by layers (as in Unity layers) so you can easily choose which volumes should affect the
42 // camera.
44 // All post-processing shaders MUST use the custom Standard Shader Library bundled with the
45 // framework. The reason for that is because the codebase is meant to work without any
46 // modification on the Classic Render Pipelines (Forward, Deferred...) and the upcoming
47 // Scriptable Render Pipelines (HDPipe, LDPipe...). But these don't have compatible shader
48 // libraries so instead of writing two code paths we chose to provide a minimalist, generic
49 // Standard Library geared toward post-processing use. An added bonus to that if users create
50 // their own post-processing effects using this framework, then they'll work without any
51 // modification on both Classic and Scriptable Render Pipelines.
54 /// <summary>
55 /// A post-process volume component holding a post-process profile.
56 /// </summary>
57 /// <seealso cref="RuntimeUtilities.DestroyVolume"/>
58 #if UNITY_2018_3_OR_NEWER
59 [ExecuteAlways]
60 #else
61 [ExecuteInEditMode]
62 #endif
63 [AddComponentMenu("Rendering/Post-process Volume", 1001)]
64 public sealed class PostProcessVolume : MonoBehaviour
66 /// <summary>
67 /// The shared profile of this volume.
68 /// Modifying <c>sharedProfile</c> will change all volumes using this profile, and change
69 /// profile settings that are stored in the project too.
70 /// </summary>
71 /// <remarks>
72 /// It is not recommended to modify profiles returned by <c>sharedProfile</c>. If you want
73 /// to modify the profile of a volume use <see cref="profile"/> instead.
74 /// </remarks>
75 /// <seealso cref="profile"/>
76 public PostProcessProfile sharedProfile;
78 /// <summary>
79 /// Should this volume be applied to the whole scene?
80 /// </summary>
81 [Tooltip("Check this box to mark this volume as global. This volume's Profile will be applied to the whole Scene.")]
82 public bool isGlobal = false;
84 /// <summary>
85 /// The outer distance to start blending from. A value of 0 means no blending and the volume
86 /// overrides will be applied immediatly upon entry.
87 /// </summary>
88 [Min(0f), Tooltip("The distance (from the attached Collider) to start blending from. A value of 0 means there will be no blending and the Volume overrides will be applied immediatly upon entry to the attached Collider.")]
89 public float blendDistance = 0f;
91 /// <summary>
92 /// The total weight of this volume in the scene. 0 means it won't do anything, 1 means full
93 /// effect.
94 /// </summary>
95 [Range(0f, 1f), Tooltip("The total weight of this Volume in the Scene. A value of 0 signifies that it will have no effect, 1 signifies full effect.")]
96 public float weight = 1f;
98 /// <summary>
99 /// The volume priority in the stack. Higher number means higher priority. Negative values
100 /// are supported.
101 /// </summary>
102 [Tooltip("The volume priority in the stack. A higher value means higher priority. Negative values are supported.")]
103 public float priority = 0f;
105 /// <summary>
106 /// Returns the first instantiated <see cref="PostProcessProfile"/> assigned to the volume.
107 /// Modifying <paramref name="profile"/> will change the profile for this volume only. If
108 /// the profile is used by any other volume, this will clone the shared profile and start
109 /// using it from now on.
110 /// </summary>
111 /// <remarks>
112 /// This property automatically instantiates the profile and make it unique to this volume
113 /// so you can safely edit it via scripting at runtime without changing the original asset
114 /// in the project.
115 /// Note that if you pass in your own profile, it is your responsibility to destroy it once
116 /// it's not in use anymore.
117 /// </remarks>
118 /// <seealso cref="sharedProfile"/>
119 /// <seealso cref="RuntimeUtilities.DestroyProfile"/>
120 public PostProcessProfile profile
124 if (m_InternalProfile == null)
126 m_InternalProfile = ScriptableObject.CreateInstance<PostProcessProfile>();
128 if (sharedProfile != null)
130 foreach (var item in sharedProfile.settings)
132 var itemCopy = Instantiate(item);
133 m_InternalProfile.settings.Add(itemCopy);
138 return m_InternalProfile;
142 m_InternalProfile = value;
146 internal PostProcessProfile profileRef
150 return m_InternalProfile == null
151 ? sharedProfile
152 : m_InternalProfile;
156 /// <summary>
157 /// Checks if the volume has an intantiated profile or is using a shared profile.
158 /// </summary>
159 /// <returns><c>true</c> if the profile has been intantiated</returns>
160 /// <seealso cref="profile"/>
161 /// <seealso cref="sharedProfile"/>
162 public bool HasInstantiatedProfile()
164 return m_InternalProfile != null;
167 int m_PreviousLayer;
168 float m_PreviousPriority;
169 List<Collider> m_TempColliders;
170 PostProcessProfile m_InternalProfile;
172 void OnEnable()
174 PostProcessManager.instance.Register(this);
175 m_PreviousLayer = gameObject.layer;
176 m_TempColliders = new List<Collider>();
179 void OnDisable()
181 PostProcessManager.instance.Unregister(this);
184 void Update()
186 // Unfortunately we need to track the current layer to update the volume manager in
187 // real-time as the user could change it at any time in the editor or at runtime.
188 // Because no event is raised when the layer changes, we have to track it on every
189 // frame :/
190 int layer = gameObject.layer;
191 if (layer != m_PreviousLayer)
193 PostProcessManager.instance.UpdateVolumeLayer(this, m_PreviousLayer, layer);
194 m_PreviousLayer = layer;
197 // Same for `priority`. We could use a property instead, but it doesn't play nice with
198 // the serialization system. Using a custom Attribute/PropertyDrawer for a property is
199 // possible but it doesn't work with Undo/Redo in the editor, which makes it useless.
200 if (priority != m_PreviousPriority)
202 PostProcessManager.instance.SetLayerDirty(layer);
203 m_PreviousPriority = priority;
207 // TODO: Look into a better volume previsualization system
208 void OnDrawGizmos()
210 var colliders = m_TempColliders;
211 GetComponents(colliders);
213 if (isGlobal || colliders == null)
214 return;
216 #if UNITY_EDITOR
217 // Can't access the UnityEditor.Rendering.PostProcessing namespace from here, so
218 // we'll get the preferred color manually
219 unchecked
221 int value = UnityEditor.EditorPrefs.GetInt("PostProcessing.Volume.GizmoColor", (int)0x8033cc1a);
222 Gizmos.color = ColorUtilities.ToRGBA((uint)value);
224 #endif
226 var scale = transform.lossyScale;
227 var invScale = new Vector3(1f / scale.x, 1f / scale.y, 1f / scale.z);
228 Gizmos.matrix = Matrix4x4.TRS(transform.position, transform.rotation, scale);
230 // Draw a separate gizmo for each collider
231 foreach (var collider in colliders)
233 if (!collider.enabled)
234 continue;
236 // We'll just use scaling as an approximation for volume skin. It's far from being
237 // correct (and is completely wrong in some cases). Ultimately we'd use a distance
238 // field or at least a tesselate + push modifier on the collider's mesh to get a
239 // better approximation, but the current Gizmo system is a bit limited and because
240 // everything is dynamic in Unity and can be changed at anytime, it's hard to keep
241 // track of changes in an elegant way (which we'd need to implement a nice cache
242 // system for generated volume meshes).
243 var type = collider.GetType();
245 if (type == typeof(BoxCollider))
247 var c = (BoxCollider)collider;
248 Gizmos.DrawCube(c.center, c.size);
249 Gizmos.DrawWireCube(c.center, c.size + invScale * blendDistance * 4f);
251 else if (type == typeof(SphereCollider))
253 var c = (SphereCollider)collider;
254 Gizmos.DrawSphere(c.center, c.radius);
255 Gizmos.DrawWireSphere(c.center, c.radius + invScale.x * blendDistance * 2f);
257 else if (type == typeof(MeshCollider))
259 var c = (MeshCollider)collider;
261 // Only convex mesh colliders are allowed
262 if (!c.convex)
263 c.convex = true;
265 // Mesh pivot should be centered or this won't work
266 Gizmos.DrawMesh(c.sharedMesh);
267 Gizmos.DrawWireMesh(c.sharedMesh, Vector3.zero, Quaternion.identity, Vector3.one + invScale * blendDistance * 4f);
270 // Nothing for capsule (DrawCapsule isn't exposed in Gizmo), terrain, wheel and
271 // other colliders...
274 colliders.Clear();