A game about forced loneliness, made by TACStudios
1using System;
2
3namespace UnityEngine.Rendering
4{
5 /// <summary>
6 /// A marker to adjust probes in an area of the scene.
7 /// </summary>
8 [CoreRPHelpURL("probevolumes-settings#probe-adjustment-volume", "com.unity.render-pipelines.high-definition")]
9 [ExecuteAlways]
10 [AddComponentMenu("Rendering/Probe Adjustment Volume")]
11 public class ProbeAdjustmentVolume : MonoBehaviour, ISerializationCallbackReceiver
12 {
13 /// <summary>The type of shape that an adjustment volume can take. </summary>
14 public enum Shape
15 {
16 /// <summary>A Box shape.</summary>
17 Box,
18 /// <summary>A Sphere shape.</summary>
19 Sphere,
20 };
21
22 /// <summary>The shape of the adjustment volume</summary>
23 [Tooltip("Select the shape used for this Probe Adjustment Volume.")]
24 public Shape shape = Shape.Box;
25
26 /// <summary>
27 /// The size for box shape.
28 /// </summary>
29 [Min(0.0f), Tooltip("Modify the size of this Probe Adjustment Volume. This is unaffected by the GameObject's Transform's Scale property.")]
30 public Vector3 size = new Vector3(1, 1, 1);
31
32 /// <summary>
33 /// The size for sphere shape.
34 /// </summary>
35 [Min(0.0f), Tooltip("Modify the radius of this Probe Adjustment Volume. This is unaffected by the GameObject's Transform's Scale property.")]
36 public float radius = 1.0f;
37
38
39 /// <summary>The mode that adjustment volume will operate in. It determines what probes falling within the volume will do. </summary>
40 public enum Mode
41 {
42 /// <summary>Invalidate the probes within the adjustment volume.</summary>
43 InvalidateProbes,
44 /// <summary>Override the dilation validity threshold for the probes within the adjustment volume.</summary>
45 OverrideValidityThreshold,
46 /// <summary>Apply an explicit virtual offset to the probes within the adjustment volume.</summary>
47 ApplyVirtualOffset,
48 /// <summary>Override the virtual offset settings for the probes within the adjustment volume.</summary>
49 OverrideVirtualOffsetSettings,
50 /// <summary>Override the dynamic sky shading direction for the probes within the adjustment volume.</summary>
51 OverrideSkyDirection,
52 /// <summary>Override the Lightmapper sample count for the probes within the adjustment volume.</summary>
53 OverrideSampleCount,
54 /// <summary>Control the rendering layer masks for the probes within the adjustment volume.</summary>
55 OverrideRenderingLayerMask,
56
57 /// <summary>Scale probe intensity.</summary>
58 IntensityScale = 99, // make sure this appears last
59 };
60
61 /// <summary>The mode that adjustment volume will operate in. It determines what probes falling within the volume will do. </summary>
62 public enum RenderingLayerMaskOperation
63 {
64 /// <summary>Overrides the rendering layer mask for the probes within the adjustment volume.</summary>
65 Override,
66 /// <summary>Add a rendering layer to the probes within the adjustment volume.</summary>
67 Add,
68 /// <summary>Removes a rendering layer to the probes within the adjustment volume.</summary>
69 Remove,
70 };
71
72 /// <summary>Choose what to do with probes falling inside this volume</summary>
73 public Mode mode = Mode.InvalidateProbes;
74
75 /// <summary>
76 /// A scale to apply to probes falling within the invalidation volume. It is really important to use this with caution as it can lead to inconsistent lighting.
77 /// </summary>
78 [Range(0.0001f, 2.0f), Tooltip("A multiplier applied to the intensity of probes covered by this Probe Adjustment Volume.")]
79 public float intensityScale = 1.0f;
80
81 /// <summary>
82 /// The overridden dilation threshold.
83 /// </summary>
84 [Range(0.0f, 0.95f)]
85 public float overriddenDilationThreshold = 0.75f;
86
87 /// <summary>The rotation angles for the virtual offset direction.</summary>
88 public Vector3 virtualOffsetRotation = Vector3.zero;
89
90 /// <summary>Determines how far probes are pushed along the specified virtual offset direction.</summary>
91 [Min(0.0f)]
92 public float virtualOffsetDistance = 1.0f;
93
94 /// <summary>Determines how far Unity pushes a probe out of geometry after a ray hit.</summary>
95 [Range(0f, 1f), Tooltip("Determines how far Unity pushes a probe out of geometry after a ray hit.")]
96 public float geometryBias = 0.01f;
97
98 /// <summary>Virtual Offset validity threshold.</summary>
99 [Range(0f, 0.95f)]
100 public float virtualOffsetThreshold = 0.75f;
101
102 /// <summary>Distance from the probe position used to determine the origin of the sampling ray.</summary>
103 [Range(-0.05f, 0f), Tooltip("Distance from the probe position used to determine the origin of the sampling ray.")]
104 public float rayOriginBias = -0.001f;
105
106 /// <summary>The sky direction.</summary>
107 [Tooltip("The direction for sampling the ambient probe in worldspace when using the Sky Visibility feature.")]
108 public Vector3 skyDirection = Vector3.zero;
109
110 internal Vector3 skyShadingDirectionRotation = Vector3.zero;
111
112 /// <summary>Number of samples for direct lighting computations.</summary>
113 [Logarithmic(1, 1024), Tooltip("Number of samples for direct lighting computations.")]
114 public int directSampleCount = 32;
115
116 /// <summary>Number of samples for indirect lighting computations. This includes environment samples.</summary>
117 [Logarithmic(1, 8192), Tooltip("Number of samples for indirect lighting computations. This includes environment samples.")]
118 public int indirectSampleCount = 512;
119
120 /// <summary>Multiplier for the number of samples specified above.</summary>
121 [Min(0), Tooltip("Multiplier for the number of samples specified above.")]
122 public int sampleCountMultiplier = 4;
123
124 /// <summary>Maximum number of bounces for indirect lighting.</summary>
125 [Min(0), Tooltip("Maximum number of bounces for indirect lighting.")]
126 public int maxBounces = 2;
127
128 /// <summary>Controls the number of samples per probe for sky occlusion baking.</summary>
129 [Logarithmic(1, ProbeVolumeBakingSet.k_MaxSkyOcclusionBakingSamples)]
130 public int skyOcclusionSampleCount = 2048;
131
132 /// <summary>Controls the number of bounces per light path for sky occlusion baking.</summary>
133 [Range(0, 5)]
134 public int skyOcclusionMaxBounces = 2;
135
136 /// <summary>Rendering Layer Mask operation.</summary>
137 public RenderingLayerMaskOperation renderingLayerMaskOperation;
138
139 /// <summary>Rendering layer mask used for the combine operation with the probes inside the volume.</summary>
140 public byte renderingLayerMask;
141
142#if UNITY_EDITOR
143 [SerializeField] internal int cachedHashCode = 0;
144
145 public override int GetHashCode()
146 {
147 int hash = 17;
148
149 unchecked
150 {
151 hash = hash * 23 + gameObject.transform.worldToLocalMatrix.GetHashCode();
152 hash = hash * 23 + shape.GetHashCode();
153 hash = hash * 23 + size.GetHashCode();
154 hash = hash * 23 + radius.GetHashCode();
155 hash = hash * 23 + mode.GetHashCode();
156 hash = hash * 23 + intensityScale.GetHashCode();
157 hash = hash * 23 + overriddenDilationThreshold.GetHashCode();
158 hash = hash * 23 + virtualOffsetRotation.GetHashCode();
159 hash = hash * 23 + virtualOffsetDistance.GetHashCode();
160 hash = hash * 23 + geometryBias.GetHashCode();
161 hash = hash * 23 + rayOriginBias.GetHashCode();
162 hash = hash * 23 + skyDirection.GetHashCode();
163 hash = hash * 23 + skyShadingDirectionRotation.GetHashCode();
164 hash = hash * 23 + directSampleCount.GetHashCode();
165 hash = hash * 23 + indirectSampleCount.GetHashCode();
166 hash = hash * 23 + sampleCountMultiplier.GetHashCode();
167 hash = hash * 23 + maxBounces.GetHashCode();
168 hash = hash * 23 + skyOcclusionSampleCount.GetHashCode();
169 hash = hash * 23 + skyOcclusionMaxBounces.GetHashCode();
170 }
171
172 return hash;
173 }
174#endif
175
176#if UNITY_EDITOR
177 /// <summary>
178 /// Returns the extents of the volume.
179 /// </summary>
180 /// <returns>The extents of the ProbeVolume.</returns>
181 public Vector3 GetExtents()
182 {
183 return size;
184 }
185
186 internal void GetOBBandAABB(out ProbeReferenceVolume.Volume volume, out Bounds bounds)
187 {
188 if (shape == Shape.Box)
189 {
190 volume = new ProbeReferenceVolume.Volume(Matrix4x4.TRS(transform.position, transform.rotation, GetExtents()), 0, 0);
191 bounds = volume.CalculateAABB();
192 }
193 else
194 {
195 volume = default;
196 bounds = new Bounds(transform.position, radius * Vector3.up);
197 }
198 }
199
200 internal float ComputeVolume(in ProbeReferenceVolume.Volume touchupOBB)
201 {
202 if (shape == Shape.Box)
203 return touchupOBB.X.magnitude * touchupOBB.Y.magnitude * touchupOBB.Z.magnitude;
204 else
205 return (4.0f / 3.0f) * Mathf.PI * radius * radius * radius;
206 }
207
208 internal bool IntersectsVolume(in ProbeReferenceVolume.Volume touchupOBB, in Bounds touchupBounds, Bounds volumeBounds)
209 {
210 if (shape == Shape.Box)
211 return ProbeVolumePositioning.OBBAABBIntersect(touchupOBB, volumeBounds, touchupBounds);
212 else
213 return volumeBounds.SqrDistance(touchupBounds.center) < radius * radius;
214 }
215
216 internal bool ContainsPoint(in ProbeReferenceVolume.Volume touchupOBB, in Vector3 touchupCenter, in Vector3 position)
217 {
218 if (shape == Shape.Box)
219 return ProbeVolumePositioning.OBBContains(touchupOBB, position);
220 else
221 return (touchupCenter - position).sqrMagnitude < radius * radius;
222 }
223
224 internal Vector3 GetVirtualOffset()
225 {
226 if (mode != Mode.ApplyVirtualOffset)
227 return Vector3.zero;
228 return (transform.rotation * Quaternion.Euler(virtualOffsetRotation) * Vector3.forward) * virtualOffsetDistance;
229 }
230
231 void OnDrawGizmos()
232 {
233 Gizmos.DrawIcon(transform.position, ProbeVolume.s_gizmosLocationPath + "ProbeTouchupVolume.png", true);
234 }
235#endif
236
237
238 // Migration related stuff
239
240 enum Version
241 {
242 Initial,
243 Mode,
244
245 Count
246 }
247
248 [SerializeField]
249 Version version = Version.Count;
250
251 /// <summary>Whether to invalidate all probes falling within this volume.</summary>
252 [Obsolete("Use mode")]
253 public bool invalidateProbes = false;
254 /// <summary>Whether to use a custom threshold for dilation for probes falling withing this volume.</summary>
255 [Obsolete("Use mode")]
256 public bool overrideDilationThreshold = false;
257
258 void Awake()
259 {
260 if (version == Version.Count)
261 return;
262
263 if (version == Version.Initial)
264 {
265#pragma warning disable 618 // Type or member is obsolete
266 if (invalidateProbes)
267 mode = Mode.InvalidateProbes;
268 else if (overrideDilationThreshold)
269 mode = Mode.OverrideValidityThreshold;
270#pragma warning restore 618
271
272 version++;
273 }
274 }
275
276 // This piece of code is needed because some objects could have been created before existence of Version enum
277 /// <summary>OnBeforeSerialize needed to handle migration before the versioning system was in place.</summary>
278 void ISerializationCallbackReceiver.OnBeforeSerialize()
279 {
280 if (version == Version.Count) // serializing a newly created object
281 version = Version.Count - 1; // mark as up to date
282 }
283
284 /// <summary>OnAfterDeserialize needed to handle migration before the versioning system was in place.</summary>
285 void ISerializationCallbackReceiver.OnAfterDeserialize()
286 {
287 if (version == Version.Count) // deserializing and object without version
288 version = Version.Initial; // reset to run the migration
289 }
290 }
291}