-
Notifications
You must be signed in to change notification settings - Fork 826
/
Copy pathVolumeDebugSettings.cs
293 lines (250 loc) · 10.8 KB
/
VolumeDebugSettings.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor;
namespace UnityEngine.Rendering
{
/// <summary>
/// The volume settings
/// </summary>
/// <typeparam name="T">A <see cref="MonoBehaviour"/> with <see cref="IAdditionalData"/></typeparam>
public abstract partial class VolumeDebugSettings<T> : IVolumeDebugSettings2
where T : MonoBehaviour, IAdditionalData
{
/// <summary>Current volume component to debug.</summary>
public int selectedComponent { get; set; } = 0;
private Camera m_SelectedCamera;
/// <summary>Current camera to debug.</summary>
public Camera selectedCamera => m_SelectedCamera;
/// <summary>
/// The selected camera index, use the property for better handling
/// </summary>
protected int m_SelectedCameraIndex = -1;
/// <summary>Selected camera index.</summary>
public int selectedCameraIndex
{
get => m_SelectedCameraIndex;
set
{
m_SelectedCameraIndex = value;
var count = cameras.Count();
if (count != 0)
{
m_SelectedCamera = m_SelectedCameraIndex < 0 || m_SelectedCameraIndex >= count ?
cameras.First() : cameras.ElementAt(m_SelectedCameraIndex);
}
else
{
m_SelectedCamera = null;
}
}
}
private Camera[] m_CamerasArray;
private List<Camera> m_Cameras = new List<Camera>();
/// <summary>Returns the collection of registered cameras.</summary>
public IEnumerable<Camera> cameras
{
get
{
m_Cameras.Clear();
#if UNITY_EDITOR
if (SceneView.lastActiveSceneView != null)
{
var sceneCamera = SceneView.lastActiveSceneView.camera;
if (sceneCamera != null)
m_Cameras.Add(sceneCamera);
}
#endif
if (m_CamerasArray == null || m_CamerasArray.Length != Camera.allCamerasCount)
{
m_CamerasArray = new Camera[Camera.allCamerasCount];
}
Camera.GetAllCameras(m_CamerasArray);
foreach (var camera in m_CamerasArray)
{
if (camera == null)
continue;
if (camera.cameraType != CameraType.Preview && camera.cameraType != CameraType.Reflection)
{
if (!camera.TryGetComponent<T>(out T additionalData))
additionalData = camera.gameObject.AddComponent<T>();
if (additionalData != null)
m_Cameras.Add(camera);
}
}
return m_Cameras;
}
}
/// <summary>Selected camera volume stack.</summary>
public abstract VolumeStack selectedCameraVolumeStack { get; }
/// <summary>Selected camera volume layer mask.</summary>
public abstract LayerMask selectedCameraLayerMask { get; }
/// <summary>Selected camera volume position.</summary>
public abstract Vector3 selectedCameraPosition { get; }
/// <summary>Type of the current component to debug.</summary>
public Type selectedComponentType
{
get => volumeComponentsPathAndType[selectedComponent - 1].Item2;
set
{
var index = volumeComponentsPathAndType.FindIndex(t => t.Item2 == value);
if (index != -1)
selectedComponent = index + 1;
}
}
static List<(string, Type)> s_ComponentPathAndType;
/// <summary>List of Volume component types.</summary>
public List<(string, Type)> volumeComponentsPathAndType => s_ComponentPathAndType ??= VolumeManager.GetSupportedVolumeComponents(targetRenderPipeline);
/// <summary>
/// Specifies the render pipeline for this volume settings
/// </summary>
public abstract Type targetRenderPipeline { get; }
internal VolumeParameter GetParameter(VolumeComponent component, FieldInfo field)
{
return (VolumeParameter)field.GetValue(component);
}
internal VolumeParameter GetParameter(FieldInfo field)
{
VolumeStack stack = selectedCameraVolumeStack;
return stack == null ? null : GetParameter(stack.GetComponent(selectedComponentType), field);
}
internal VolumeParameter GetParameter(Volume volume, FieldInfo field)
{
var profile = volume.HasInstantiatedProfile() ? volume.profile : volume.sharedProfile;
if (!profile.TryGet(selectedComponentType, out VolumeComponent component))
return null;
var param = GetParameter(component, field);
if (!param.overrideState)
return null;
return param;
}
float[] weights = null;
float ComputeWeight(Volume volume, Vector3 triggerPos)
{
if (volume == null) return 0;
var profile = volume.HasInstantiatedProfile() ? volume.profile : volume.sharedProfile;
if (!volume.gameObject.activeInHierarchy) return 0;
if (!volume.enabled || profile == null || volume.weight <= 0f) return 0;
if (!profile.TryGet(selectedComponentType, out VolumeComponent component)) return 0;
if (!component.active) return 0;
float weight = Mathf.Clamp01(volume.weight);
if (!volume.isGlobal)
{
var colliders = volume.GetComponents<Collider>();
// Find closest distance to volume, 0 means it's inside it
float closestDistanceSqr = float.PositiveInfinity;
foreach (var collider in colliders)
{
if (!collider.enabled)
continue;
var closestPoint = collider.ClosestPoint(triggerPos);
var d = (closestPoint - triggerPos).sqrMagnitude;
if (d < closestDistanceSqr)
closestDistanceSqr = d;
}
float blendDistSqr = volume.blendDistance * volume.blendDistance;
if (closestDistanceSqr > blendDistSqr)
weight = 0f;
else if (blendDistSqr > 0f)
weight *= 1f - (closestDistanceSqr / blendDistSqr);
}
return weight;
}
Volume[] volumes = null;
/// <summary>Get an array of volumes on the <see cref="selectedCameraLayerMask"/></summary>
/// <returns>An array of volumes sorted by influence.</returns>
public Volume[] GetVolumes()
{
return VolumeManager.instance.GetVolumes(selectedCameraLayerMask)
.Where(v => v.sharedProfile != null)
.Reverse().ToArray();
}
VolumeParameter[,] savedStates = null;
VolumeParameter[,] GetStates()
{
var fields = selectedComponentType
.GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)
.Where(t => t.FieldType.IsSubclassOf(typeof(VolumeParameter)))
.ToArray();
VolumeParameter[,] states = new VolumeParameter[volumes.Length, fields.Length];
for (int i = 0; i < volumes.Length; i++)
{
var profile = volumes[i].HasInstantiatedProfile() ? volumes[i].profile : volumes[i].sharedProfile;
if (!profile.TryGet(selectedComponentType, out VolumeComponent component))
continue;
for (int j = 0; j < fields.Length; j++)
{
var param = GetParameter(component, fields[j]); ;
states[i, j] = param.overrideState ? param : null;
}
}
return states;
}
bool ChangedStates(VolumeParameter[,] newStates)
{
if (savedStates.GetLength(1) != newStates.GetLength(1))
return true;
for (int i = 0; i < savedStates.GetLength(0); i++)
{
for (int j = 0; j < savedStates.GetLength(1); j++)
{
if ((savedStates[i, j] == null) != (newStates[i, j] == null))
return true;
}
}
return false;
}
/// <summary>
/// Refreshes the volumes, fetches the stored volumes on the panel
/// </summary>
/// <param name="newVolumes">The list of <see cref="Volume"/> to refresh</param>
/// <returns>If the volumes have been refreshed</returns>
public bool RefreshVolumes(Volume[] newVolumes)
{
bool ret = false;
if (volumes == null || !newVolumes.SequenceEqual(volumes))
{
volumes = (Volume[])newVolumes.Clone();
savedStates = GetStates();
ret = true;
}
else
{
var newStates = GetStates();
if (savedStates == null || ChangedStates(newStates))
{
savedStates = newStates;
ret = true;
}
}
var triggerPos = selectedCameraPosition;
weights = new float[volumes.Length];
for (int i = 0; i < volumes.Length; i++)
weights[i] = ComputeWeight(volumes[i], triggerPos);
return ret;
}
/// <summary>
/// Obtains the volume weight
/// </summary>
/// <param name="volume"><see cref="Volume"/></param>
/// <returns>The weight of the volume</returns>
public float GetVolumeWeight(Volume volume)
{
// TODO: Store the calculated weight in the stack for the volumes that have influence and return it here
var triggerPos = selectedCameraPosition;
return ComputeWeight(volume, triggerPos);
}
/// <summary>
/// Return if the <see cref="Volume"/> has influence
/// </summary>
/// <param name="volume"><see cref="Volume"/> to check the influence</param>
/// <returns>If the volume has influence</returns>
public bool VolumeHasInfluence(Volume volume)
{
// TODO: Store the calculated weight in the stack for the volumes that have influence and return it here
var triggerPos = selectedCameraPosition;
return ComputeWeight(volume, triggerPos) > 0.0f;
}
}
}