A game about forced loneliness, made by TACStudios
at master 1239 lines 64 kB view raw
1using System; 2using System.Collections.Generic; 3using System.Linq; 4using UnityEngine.Rendering.RenderGraphModule; 5using UnityEditor; 6 7namespace UnityEngine.Rendering 8{ 9 /// <summary> 10 /// Modes for Debugging Probes 11 /// </summary> 12 [GenerateHLSL] 13 public enum DebugProbeShadingMode 14 { 15 /// <summary> 16 /// Based on Spherical Harmonics 17 /// </summary> 18 SH, 19 /// <summary> 20 /// Based on Spherical Harmonics first band only (ambient) 21 /// </summary> 22 SHL0, 23 /// <summary> 24 /// Based on Spherical Harmonics band zero and one only 25 /// </summary> 26 SHL0L1, 27 /// <summary> 28 /// Based on validity 29 /// </summary> 30 Validity, 31 /// <summary> 32 /// Based on validity over a dilation threshold 33 /// </summary> 34 ValidityOverDilationThreshold, 35 /// <summary> 36 /// Based on rendering layer masks 37 /// </summary> 38 RenderingLayerMasks, 39 /// <summary> 40 /// Show in red probes that have been made invalid by adjustment volumes. Important to note that this debug view will only show result for volumes still present in the scene. 41 /// </summary> 42 InvalidatedByAdjustmentVolumes, 43 /// <summary> 44 /// Based on size 45 /// </summary> 46 Size, 47 /// <summary> 48 /// Based on spherical harmonics sky occlusion 49 /// </summary> 50 SkyOcclusionSH, 51 /// <summary> 52 /// Based on shading direction 53 /// </summary> 54 SkyDirection, 55 /// <summary> 56 /// Occlusion values per probe 57 /// </summary> 58 ProbeOcclusion, 59 } 60 61 enum ProbeSamplingDebugUpdate 62 { 63 Never, 64 Once, 65 Always 66 } 67 68 class ProbeSamplingDebugData 69 { 70 public ProbeSamplingDebugUpdate update = ProbeSamplingDebugUpdate.Never; // When compute buffer should be updated 71 public Vector2 coordinates = new Vector2(0.5f, 0.5f); 72 public bool forceScreenCenterCoordinates = false; // use screen center instead of mouse position 73 public Camera camera = null; // useful in editor when multiple scene tabs are opened 74 public bool shortcutPressed = false; 75 public GraphicsBuffer positionNormalBuffer; // buffer storing position and normal 76 } 77 78 class ProbeVolumeDebug : IDebugData 79 { 80 public bool drawProbes; 81 public bool drawBricks; 82 public bool drawCells; 83 public bool realtimeSubdivision; 84 public int subdivisionCellUpdatePerFrame = 4; 85 public float subdivisionDelayInSeconds = 1; 86 public DebugProbeShadingMode probeShading; 87 public float probeSize = 0.3f; 88 public float subdivisionViewCullingDistance = 500.0f; 89 public float probeCullingDistance = 200.0f; 90 public int maxSubdivToVisualize = ProbeBrickIndex.kMaxSubdivisionLevels; 91 public int minSubdivToVisualize = 0; 92 public float exposureCompensation; 93 public bool drawProbeSamplingDebug = false; 94 public float probeSamplingDebugSize = 0.3f; 95 public bool debugWithSamplingNoise = false; 96 public uint samplingRenderingLayer; 97 public bool drawVirtualOffsetPush; 98 public float offsetSize = 0.025f; 99 public bool freezeStreaming; 100 public bool displayCellStreamingScore; 101 public bool displayIndexFragmentation; 102 public int otherStateIndex = 0; 103 public bool verboseStreamingLog; 104 public bool debugStreaming = false; 105 public bool autoDrawProbes = true; 106 public bool isolationProbeDebug = true; 107 public byte visibleLayers; 108 109 // NOTE: We should get that from the camera directly instead of storing it as static 110 // But we can't access the volume parameters as they are specific to the RP 111 public static Vector3 currentOffset; 112 113 static internal int s_ActiveAdjustmentVolumes = 0; 114 115 public ProbeVolumeDebug() 116 { 117 Init(); 118 } 119 120 void Init() 121 { 122 drawProbes = false; 123 drawBricks = false; 124 drawCells = false; 125 realtimeSubdivision = false; 126 subdivisionCellUpdatePerFrame = 4; 127 subdivisionDelayInSeconds = 1; 128 probeShading = DebugProbeShadingMode.SH; 129 probeSize = 0.3f; 130 subdivisionViewCullingDistance = 500.0f; 131 probeCullingDistance = 200.0f; 132 maxSubdivToVisualize = ProbeBrickIndex.kMaxSubdivisionLevels; 133 minSubdivToVisualize = 0; 134 exposureCompensation = 0.0f; 135 drawProbeSamplingDebug = false; 136 probeSamplingDebugSize = 0.3f; 137 drawVirtualOffsetPush = false; 138 offsetSize = 0.025f; 139 freezeStreaming = false; 140 displayCellStreamingScore = false; 141 displayIndexFragmentation = false; 142 otherStateIndex = 0; 143 autoDrawProbes = true; 144 isolationProbeDebug = true; 145 visibleLayers = 0xFF; 146 } 147 148 public Action GetReset() => () => Init(); 149 } 150 151 152#if UNITY_EDITOR 153 [UnityEditor.InitializeOnLoad] 154#endif 155 internal class ProbeVolumeDebugColorPreferences 156 { 157 internal static Func<Color> GetDetailSubdivisionColor; 158 internal static Func<Color> GetMediumSubdivisionColor; 159 internal static Func<Color> GetLowSubdivisionColor; 160 internal static Func<Color> GetVeryLowSubdivisionColor; 161 internal static Func<Color> GetSparseSubdivisionColor; 162 internal static Func<Color> GetSparsestSubdivisionColor; 163 164 internal static Color s_DetailSubdivision = new Color32(135, 35, 255, 255); 165 internal static Color s_MediumSubdivision = new Color32(54, 208, 228, 255); 166 internal static Color s_LowSubdivision = new Color32(255, 100, 45, 255); 167 internal static Color s_VeryLowSubdivision = new Color32(52, 87, 255, 255); 168 internal static Color s_SparseSubdivision = new Color32(255, 71, 97, 255); 169 internal static Color s_SparsestSubdivision = new Color32(200, 227, 39, 255); 170 171 static ProbeVolumeDebugColorPreferences() 172 { 173#if UNITY_EDITOR 174 GetDetailSubdivisionColor = CoreRenderPipelinePreferences.RegisterPreferenceColor("Adaptive Probe Volumes/Level 0 Subdivision", s_DetailSubdivision); 175 GetMediumSubdivisionColor = CoreRenderPipelinePreferences.RegisterPreferenceColor("Adaptive Probe Volumes/Level 1 Subdivision", s_MediumSubdivision); 176 GetLowSubdivisionColor = CoreRenderPipelinePreferences.RegisterPreferenceColor("Adaptive Probe Volumes/Level 2 Subdivision", s_LowSubdivision); 177 GetVeryLowSubdivisionColor = CoreRenderPipelinePreferences.RegisterPreferenceColor("Adaptive Probe Volumes/Level 3 Subdivision", s_VeryLowSubdivision); 178 GetSparseSubdivisionColor = CoreRenderPipelinePreferences.RegisterPreferenceColor("Adaptive Probe Volumes/Level 4 Subdivision", s_SparseSubdivision); 179 GetSparsestSubdivisionColor = CoreRenderPipelinePreferences.RegisterPreferenceColor("Adaptive Probe Volumes/Level 5 Subdivision", s_SparsestSubdivision); 180#endif 181 } 182 183 } 184 public partial class ProbeReferenceVolume 185 { 186 internal class CellInstancedDebugProbes 187 { 188 public List<Matrix4x4[]> probeBuffers; 189 public List<Matrix4x4[]> offsetBuffers; 190 public List<MaterialPropertyBlock> props; 191 } 192 193 const int kProbesPerBatch = 511; 194 195 /// <summary>Name of debug panel for Probe Volume</summary> 196 public static readonly string k_DebugPanelName = "Probe Volumes"; 197 198 internal ProbeVolumeDebug probeVolumeDebug { get; } = new ProbeVolumeDebug(); 199 200 /// <summary>Colors that can be used for debug visualization of the brick structure subdivision.</summary> 201 public Color[] subdivisionDebugColors { get; } = new Color[ProbeBrickIndex.kMaxSubdivisionLevels]; 202 203 Mesh m_DebugMesh; 204 Mesh debugMesh { 205 get 206 { 207 if (m_DebugMesh == null) 208 { 209 m_DebugMesh = DebugShapes.instance.BuildCustomSphereMesh(0.5f, 9, 8); // (longSubdiv + 1) * latSubdiv + 2 = 82 210 m_DebugMesh.bounds = new Bounds(Vector3.zero, Vector3.one * 9999999.9f); // dirty way of disabling culling (objects spawned at (0.0, 0.0, 0.0) but vertices moved in vertex shader) 211 } 212 return m_DebugMesh; 213 } 214 } 215 216 DebugUI.Widget[] m_DebugItems; 217 Material m_DebugMaterial; 218 219 // Sample position debug 220 Mesh m_DebugProbeSamplingMesh; // mesh with 8 quads, 1 arrow and 2 locators 221 Material m_ProbeSamplingDebugMaterial; // Used to draw probe sampling information (quad with weight, arrow, locator) 222 Material m_ProbeSamplingDebugMaterial02; // Used to draw probe sampling information (shaded probes) 223 224 Texture m_DisplayNumbersTexture; 225 226 internal static ProbeSamplingDebugData probeSamplingDebugData = new ProbeSamplingDebugData(); 227 228 Mesh m_DebugOffsetMesh; 229 Material m_DebugOffsetMaterial; 230 Material m_DebugFragmentationMaterial; 231 Plane[] m_DebugFrustumPlanes = new Plane[6]; 232 233 // Scenario blending debug data 234 GUIContent[] m_DebugScenarioNames = new GUIContent[0]; 235 int[] m_DebugScenarioValues = new int[0]; 236 string m_DebugActiveSceneGUID, m_DebugActiveScenario; 237 DebugUI.EnumField m_DebugScenarioField; 238 239 // Field used for the realtime subdivision preview 240 internal Dictionary<Bounds, ProbeBrickIndex.Brick[]> realtimeSubdivisionInfo = new (); 241 242 bool m_MaxSubdivVisualizedIsMaxAvailable = false; 243 244 /// <summary> 245 /// Obsolete. Render Probe Volume related debug 246 /// </summary> 247 /// <param name="camera">The <see cref="Camera"/></param> 248 /// <param name="exposureTexture">Texture containing the exposure value for this frame.</param> 249 [Obsolete("Use the other override to support sampling offset in debug modes.")] 250 public void RenderDebug(Camera camera, Texture exposureTexture) 251 { 252 RenderDebug(camera, null, exposureTexture); 253 } 254 255 /// <summary> 256 /// Render Probe Volume related debug 257 /// </summary> 258 /// <param name="camera">The <see cref="Camera"/></param> 259 /// <param name="options">Options coming from the volume stack.</param> 260 /// <param name="exposureTexture">Texture containing the exposure value for this frame.</param> 261 public void RenderDebug(Camera camera, ProbeVolumesOptions options, Texture exposureTexture) 262 { 263 if (camera.cameraType != CameraType.Reflection && camera.cameraType != CameraType.Preview) 264 { 265 if (options != null) 266 ProbeVolumeDebug.currentOffset = options.worldOffset.value; 267 268 DrawProbeDebug(camera, exposureTexture); 269 } 270 } 271 272 /// <summary> 273 /// Checks if APV sampling debug is enabled 274 /// </summary> 275 /// <returns>True if APV sampling debug is enabled</returns> 276 public bool IsProbeSamplingDebugEnabled() 277 { 278 return probeSamplingDebugData.update != ProbeSamplingDebugUpdate.Never; 279 } 280 281 /// <summary> 282 /// Returns the resources used for APV probe sampling debug mode 283 /// </summary> 284 /// <param name="camera">The camera for which to evaluate the debug mode</param> 285 /// <param name="resultBuffer">The buffer that should be filled with position and normal</param> 286 /// <param name="coords">The screen space coords to sample the position and normal</param> 287 /// <returns>True if the pipeline should write position and normal at coords in resultBuffer</returns> 288 public bool GetProbeSamplingDebugResources(Camera camera, out GraphicsBuffer resultBuffer, out Vector2 coords) 289 { 290 resultBuffer = probeSamplingDebugData.positionNormalBuffer; 291 coords = probeSamplingDebugData.coordinates; 292 293 if (!probeVolumeDebug.drawProbeSamplingDebug) 294 return false; 295 296#if UNITY_EDITOR 297 if (probeSamplingDebugData.camera != camera) 298 return false; 299#endif 300 301 if (probeSamplingDebugData.update == ProbeSamplingDebugUpdate.Never) 302 return false; 303 304 if (probeSamplingDebugData.update == ProbeSamplingDebugUpdate.Once) 305 { 306 probeSamplingDebugData.update = ProbeSamplingDebugUpdate.Never; 307 probeSamplingDebugData.forceScreenCenterCoordinates = false; 308 } 309 310 return true; 311 } 312 313#if UNITY_EDITOR 314 static void SceneGUI(SceneView sceneView) 315 { 316 // APV debug needs to detect user keyboard and mouse position to update ProbeSamplingPositionDebug 317 Event e = Event.current; 318 319 if (e.control && !ProbeReferenceVolume.probeSamplingDebugData.shortcutPressed) 320 ProbeReferenceVolume.probeSamplingDebugData.update = ProbeSamplingDebugUpdate.Always; 321 322 if (!e.control && ProbeReferenceVolume.probeSamplingDebugData.shortcutPressed) 323 ProbeReferenceVolume.probeSamplingDebugData.update = ProbeSamplingDebugUpdate.Never; 324 325 ProbeReferenceVolume.probeSamplingDebugData.shortcutPressed = e.control; 326 327 if (e.clickCount > 0 && e.button == 0) 328 { 329 if (ProbeReferenceVolume.probeSamplingDebugData.shortcutPressed) 330 ProbeReferenceVolume.probeSamplingDebugData.update = ProbeSamplingDebugUpdate.Once; 331 else 332 ProbeReferenceVolume.probeSamplingDebugData.update = ProbeSamplingDebugUpdate.Never; 333 } 334 335 if (ProbeReferenceVolume.probeSamplingDebugData.update == ProbeSamplingDebugUpdate.Never) 336 return; 337 338 Vector2 screenCoordinates; 339 340 if (ProbeReferenceVolume.probeSamplingDebugData.forceScreenCenterCoordinates) 341 screenCoordinates = new Vector2(sceneView.camera.scaledPixelWidth / 2.0f, sceneView.camera.scaledPixelHeight / 2.0f); 342 else 343 screenCoordinates = HandleUtility.GUIPointToScreenPixelCoordinate(e.mousePosition); 344 345 if (screenCoordinates.x < 0 || screenCoordinates.x > sceneView.camera.scaledPixelWidth || screenCoordinates.y < 0 || screenCoordinates.y > sceneView.camera.scaledPixelHeight) 346 return; 347 348 ProbeReferenceVolume.probeSamplingDebugData.camera = sceneView.camera; 349 ProbeReferenceVolume.probeSamplingDebugData.coordinates = screenCoordinates; 350 351 if (e.type != EventType.Repaint && e.type != EventType.Layout) 352 { 353 var go = HandleUtility.PickGameObject(e.mousePosition, false); 354 if (go != null && go.TryGetComponent<MeshRenderer>(out var renderer)) 355 instance.probeVolumeDebug.samplingRenderingLayer = renderer.renderingLayerMask; 356 } 357 358 SceneView.currentDrawingSceneView.Repaint(); // useful when 'Always Refresh' is not toggled 359 } 360#endif 361 362 bool TryCreateDebugRenderData() 363 { 364 if (!GraphicsSettings.TryGetRenderPipelineSettings<ProbeVolumeDebugResources>(out var debugResources)) 365 return false; 366 367#if !UNITY_EDITOR // On non editor builds, we need to check if the standalone build contains debug shaders 368 if (GraphicsSettings.TryGetRenderPipelineSettings<ShaderStrippingSetting>(out var shaderStrippingSetting) && shaderStrippingSetting.stripRuntimeDebugShaders) 369 return false; 370#endif 371 m_DebugMaterial = CoreUtils.CreateEngineMaterial(debugResources.probeVolumeDebugShader); 372 m_DebugMaterial.enableInstancing = true; 373 374 // Probe Sampling Debug Mesh : useful to show additional information concerning probe sampling for a specific fragment 375 // - Arrow : Debug fragment position and normal 376 // - Locator : Debug sampling position 377 // - 8 Quads : Debug probes weights 378 m_DebugProbeSamplingMesh = debugResources.probeSamplingDebugMesh; 379 m_DebugProbeSamplingMesh.bounds = new Bounds(Vector3.zero, Vector3.one * 9999999.9f); // dirty way of disabling culling (objects spawned at (0.0, 0.0, 0.0) but vertices moved in vertex shader) 380 m_ProbeSamplingDebugMaterial = CoreUtils.CreateEngineMaterial(debugResources.probeVolumeSamplingDebugShader); 381 m_ProbeSamplingDebugMaterial02 = CoreUtils.CreateEngineMaterial(debugResources.probeVolumeDebugShader); 382 m_ProbeSamplingDebugMaterial02.enableInstancing = true; 383 384 probeSamplingDebugData.positionNormalBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, 2, System.Runtime.InteropServices.Marshal.SizeOf(typeof(Vector4))); 385 386 m_DisplayNumbersTexture = debugResources.numbersDisplayTex; 387 388 m_DebugOffsetMesh = Resources.GetBuiltinResource<Mesh>("pyramid.fbx"); 389 m_DebugOffsetMesh.bounds = new Bounds(Vector3.zero, Vector3.one * 9999999.9f); // dirty way of disabling culling (objects spawned at (0.0, 0.0, 0.0) but vertices moved in vertex shader) 390 m_DebugOffsetMaterial = CoreUtils.CreateEngineMaterial(debugResources.probeVolumeOffsetDebugShader); 391 m_DebugOffsetMaterial.enableInstancing = true; 392 m_DebugFragmentationMaterial = CoreUtils.CreateEngineMaterial(debugResources.probeVolumeFragmentationDebugShader); 393 394 // Hard-coded colors for now. 395 Debug.Assert(ProbeBrickIndex.kMaxSubdivisionLevels == 7); // Update list if this changes. 396 397 subdivisionDebugColors[0] = ProbeVolumeDebugColorPreferences.s_DetailSubdivision; 398 subdivisionDebugColors[1] = ProbeVolumeDebugColorPreferences.s_MediumSubdivision; 399 subdivisionDebugColors[2] = ProbeVolumeDebugColorPreferences.s_LowSubdivision; 400 subdivisionDebugColors[3] = ProbeVolumeDebugColorPreferences.s_VeryLowSubdivision; 401 subdivisionDebugColors[4] = ProbeVolumeDebugColorPreferences.s_SparseSubdivision; 402 subdivisionDebugColors[5] = ProbeVolumeDebugColorPreferences.s_SparsestSubdivision; 403 subdivisionDebugColors[6] = ProbeVolumeDebugColorPreferences.s_DetailSubdivision; 404 405 return true; 406 } 407 408 void InitializeDebug() 409 { 410#if UNITY_EDITOR 411 SceneView.duringSceneGui += SceneGUI; // Used to get click and keyboard event on scene view for Probe Sampling Debug 412#endif 413 if (TryCreateDebugRenderData()) 414 RegisterDebug(); 415 416#if UNITY_EDITOR 417 UnityEditor.Lightmapping.lightingDataCleared += OnClearLightingdata; 418#endif 419 } 420 421 void CleanupDebug() 422 { 423 UnregisterDebug(true); 424 CoreUtils.Destroy(m_DebugMaterial); 425 CoreUtils.Destroy(m_ProbeSamplingDebugMaterial); 426 CoreUtils.Destroy(m_ProbeSamplingDebugMaterial02); 427 CoreUtils.Destroy(m_DebugOffsetMaterial); 428 CoreUtils.Destroy(m_DebugFragmentationMaterial); 429 CoreUtils.SafeRelease(probeSamplingDebugData?.positionNormalBuffer); 430 431#if UNITY_EDITOR 432 UnityEditor.Lightmapping.lightingDataCleared -= OnClearLightingdata; 433 SceneView.duringSceneGui -= SceneGUI; 434#endif 435 } 436 437 void DebugCellIndexChanged<T>(DebugUI.Field<T> field, T value) 438 { 439 ClearDebugData(); 440 } 441 442 void RegisterDebug() 443 { 444 void RefreshDebug<T>(DebugUI.Field<T> field, T value) 445 { 446 UnregisterDebug(false); 447 RegisterDebug(); 448 } 449 450 const float kProbeSizeMin = 0.05f, kProbeSizeMax = 10.0f; 451 const float kOffsetSizeMin = 0.001f, kOffsetSizeMax = 0.1f; 452 453 var widgetList = new List<DebugUI.Widget>(); 454 455 widgetList.Add(new DebugUI.RuntimeDebugShadersMessageBox()); 456 457 var subdivContainer = new DebugUI.Container() 458 { 459 displayName = "Subdivision Visualization", 460 isHiddenCallback = () => 461 { 462#if UNITY_EDITOR 463 return false; 464#else 465 return false; // Cells / Bricks visualization is not implemented in a runtime compatible way atm. 466#endif 467 } 468 }; 469 subdivContainer.children.Add(new DebugUI.BoolField 470 { 471 displayName = "Display Cells", 472 tooltip = "Draw Cells used for loading and streaming.", 473 getter = () => probeVolumeDebug.drawCells, 474 setter = value => probeVolumeDebug.drawCells = value, 475 onValueChanged = RefreshDebug 476 }); 477 subdivContainer.children.Add(new DebugUI.BoolField 478 { 479 displayName = "Display Bricks", 480 tooltip = "Display Subdivision bricks.", 481 getter = () => probeVolumeDebug.drawBricks, 482 setter = value => probeVolumeDebug.drawBricks = value, 483 onValueChanged = RefreshDebug 484 }); 485 486 subdivContainer.children.Add(new DebugUI.FloatField { displayName = "Debug Draw Distance", tooltip = "How far from the Scene Camera to draw debug visualization for Cells and Bricks. Large distances can impact Editor performance.", getter = () => probeVolumeDebug.subdivisionViewCullingDistance, setter = value => probeVolumeDebug.subdivisionViewCullingDistance = value, min = () => 0.0f }); 487 widgetList.Add(subdivContainer); 488 489#if UNITY_EDITOR 490 var subdivPreviewContainer = new DebugUI.Container() 491 { 492 displayName = "Subdivision Preview", 493 isHiddenCallback = () => 494 { 495 return (!probeVolumeDebug.drawCells && !probeVolumeDebug.drawBricks); 496 } 497 }; 498 subdivPreviewContainer.children.Add(new DebugUI.BoolField 499 { 500 displayName = "Live Updates", 501 tooltip = "Enable a preview of Adaptive Probe Volumes data in the Scene without baking. Can impact Editor performance.", 502 getter = () => probeVolumeDebug.realtimeSubdivision, 503 setter = value => probeVolumeDebug.realtimeSubdivision = value, 504 }); 505 506 var realtimeSubdivisonChildContainer = new DebugUI.Container() 507 { 508 isHiddenCallback = () => !probeVolumeDebug.realtimeSubdivision 509 }; 510 realtimeSubdivisonChildContainer.children.Add(new DebugUI.IntField { displayName = "Cell Updates Per Frame", tooltip = "The number of Cells, bricks, and probe positions updated per frame. Higher numbers can impact Editor performance.", getter = () => probeVolumeDebug.subdivisionCellUpdatePerFrame, setter = value => probeVolumeDebug.subdivisionCellUpdatePerFrame = value, min = () => 1, max = () => 100 }); 511 realtimeSubdivisonChildContainer.children.Add(new DebugUI.FloatField { displayName = "Update Frequency", tooltip = "Delay in seconds between updates to Cell, Brick, and Probe positions if Live Subdivision Preview is enabled.", getter = () => probeVolumeDebug.subdivisionDelayInSeconds, setter = value => probeVolumeDebug.subdivisionDelayInSeconds = value, min = () => 0.1f, max = () => 10 }); 512 subdivPreviewContainer.children.Add(realtimeSubdivisonChildContainer); 513 widgetList.Add(subdivPreviewContainer); 514#endif 515 516 widgetList.Add(new DebugUI.RuntimeDebugShadersMessageBox()); 517 518 var probeContainer = new DebugUI.Container() 519 { 520 displayName = "Probe Visualization" 521 }; 522 523 probeContainer.children.Add(new DebugUI.BoolField { displayName = "Display Probes", tooltip = "Render the debug view showing probe positions. Use the shading mode to determine which type of lighting data to visualize.", getter = () => probeVolumeDebug.drawProbes, setter = value => probeVolumeDebug.drawProbes = value, onValueChanged = RefreshDebug }); 524 { 525 var probeContainerChildren = new DebugUI.Container() 526 { 527 isHiddenCallback = () => !probeVolumeDebug.drawProbes 528 }; 529 530 probeContainerChildren.children.Add(new DebugUI.EnumField 531 { 532 displayName = "Probe Shading Mode", 533 tooltip = "Choose which lighting data to show in the probe debug visualization.", 534 getter = () => (int)probeVolumeDebug.probeShading, 535 setter = value => probeVolumeDebug.probeShading = (DebugProbeShadingMode)value, 536 autoEnum = typeof(DebugProbeShadingMode), 537 getIndex = () => (int)probeVolumeDebug.probeShading, 538 setIndex = value => probeVolumeDebug.probeShading = (DebugProbeShadingMode)value, 539 }); 540 probeContainerChildren.children.Add(new DebugUI.FloatField { displayName = "Debug Size", tooltip = "The size of probes shown in the debug view.", getter = () => probeVolumeDebug.probeSize, setter = value => probeVolumeDebug.probeSize = value, min = () => kProbeSizeMin, max = () => kProbeSizeMax }); 541 542 var exposureCompensation = new DebugUI.FloatField 543 { 544 displayName = "Exposure Compensation", 545 tooltip = "Modify the brightness of probe visualizations. Decrease this number to make very bright probes more visible.", 546 getter = () => probeVolumeDebug.exposureCompensation, 547 setter = value => probeVolumeDebug.exposureCompensation = value, 548 isHiddenCallback = () => 549 { 550 return probeVolumeDebug.probeShading switch 551 { 552 DebugProbeShadingMode.SH => false, 553 DebugProbeShadingMode.SHL0 => false, 554 DebugProbeShadingMode.SHL0L1 => false, 555 DebugProbeShadingMode.SkyOcclusionSH => false, 556 DebugProbeShadingMode.SkyDirection => false, 557 DebugProbeShadingMode.ProbeOcclusion => false, 558 _ => true 559 }; 560 } 561 }; 562 probeContainerChildren.children.Add(exposureCompensation); 563 564 probeContainerChildren.children.Add(new DebugUI.IntField 565 { 566 displayName = "Max Subdivisions Displayed", 567 tooltip = "The highest (most dense) probe subdivision level displayed in the debug view.", 568 getter = () => probeVolumeDebug.maxSubdivToVisualize, 569 setter = (v) => probeVolumeDebug.maxSubdivToVisualize = Mathf.Max(0, Mathf.Min(v, GetMaxSubdivision() - 1)), 570 min = () => 0, 571 max = () => Mathf.Max(0, GetMaxSubdivision() - 1), 572 }); 573 574 probeContainerChildren.children.Add(new DebugUI.IntField 575 { 576 displayName = "Min Subdivisions Displayed", 577 tooltip = "The lowest (least dense) probe subdivision level displayed in the debug view.", 578 getter = () => probeVolumeDebug.minSubdivToVisualize, 579 setter = (v) => probeVolumeDebug.minSubdivToVisualize = Mathf.Max(v, 0), 580 min = () => 0, 581 max = () => Mathf.Max(0, GetMaxSubdivision() - 1), 582 }); 583 584 probeContainer.children.Add(probeContainerChildren); 585 } 586 587 probeContainer.children.Add(new DebugUI.BoolField 588 { 589 displayName = "Debug Probe Sampling", 590 tooltip = "Render the debug view displaying how probes are sampled for a selected pixel. Use the viewport overlay 'SelectPixel' button or Ctrl+Click on the viewport to select the debugged pixel", 591 getter = () => probeVolumeDebug.drawProbeSamplingDebug, 592 setter = value => 593 { 594 probeVolumeDebug.drawProbeSamplingDebug = value; 595 probeSamplingDebugData.update = ProbeSamplingDebugUpdate.Once; 596 probeSamplingDebugData.forceScreenCenterCoordinates = true; 597 }, 598 }); 599 600 var drawProbeSamplingDebugChildren = new DebugUI.Container() 601 { 602 isHiddenCallback = () => !probeVolumeDebug.drawProbeSamplingDebug 603 }; 604 605 drawProbeSamplingDebugChildren.children.Add(new DebugUI.FloatField { displayName = "Debug Size", tooltip = "The size of gizmos shown in the debug view.", getter = () => probeVolumeDebug.probeSamplingDebugSize, setter = value => probeVolumeDebug.probeSamplingDebugSize = value, min = () => kProbeSizeMin, max = () => kProbeSizeMax }); 606 drawProbeSamplingDebugChildren.children.Add(new DebugUI.BoolField { displayName = "Debug With Sampling Noise", tooltip = "Enable Sampling Noise for this debug view. It should be enabled for accuracy but it can make results more difficult to read", getter = () => probeVolumeDebug.debugWithSamplingNoise, setter = value => { probeVolumeDebug.debugWithSamplingNoise = value; }, onValueChanged = RefreshDebug }); 607 probeContainer.children.Add(drawProbeSamplingDebugChildren); 608 609 probeContainer.children.Add(new DebugUI.BoolField 610 { 611 displayName = "Virtual Offset Debug", 612 tooltip = "Enable Virtual Offset debug visualization. Indicates the offsets applied to probe positions. These are used to capture lighting when probes are considered invalid.", 613 getter = () => probeVolumeDebug.drawVirtualOffsetPush, 614 setter = value => 615 { 616 probeVolumeDebug.drawVirtualOffsetPush = value; 617 618 if (probeVolumeDebug.drawVirtualOffsetPush && probeVolumeDebug.drawProbes && m_CurrentBakingSet != null) 619 { 620 // If probes are being drawn when enabling offset, automatically scale them down to a reasonable size so the arrows aren't obscured by the probes. 621 var searchDistance = CellSize(0) * MinBrickSize() / ProbeBrickPool.kBrickCellCount * m_CurrentBakingSet.settings.virtualOffsetSettings.searchMultiplier + m_CurrentBakingSet.settings.virtualOffsetSettings.outOfGeoOffset; 622 probeVolumeDebug.probeSize = Mathf.Min(probeVolumeDebug.probeSize, Mathf.Clamp(searchDistance, kProbeSizeMin, kProbeSizeMax)); 623 } 624 } 625 }); 626 627 var drawVirtualOffsetDebugChildren = new DebugUI.Container() 628 { 629 isHiddenCallback = () => !probeVolumeDebug.drawVirtualOffsetPush 630 }; 631 632 var voOffset = new DebugUI.FloatField 633 { 634 displayName = "Debug Size", 635 tooltip = "Modify the size of the arrows used in the virtual offset debug visualization.", 636 getter = () => probeVolumeDebug.offsetSize, 637 setter = value => probeVolumeDebug.offsetSize = value, 638 min = () => kOffsetSizeMin, 639 max = () => kOffsetSizeMax, 640 isHiddenCallback = () => !probeVolumeDebug.drawVirtualOffsetPush 641 }; 642 drawVirtualOffsetDebugChildren.children.Add(voOffset); 643 probeContainer.children.Add(drawVirtualOffsetDebugChildren); 644 645 probeContainer.children.Add(new DebugUI.FloatField { displayName = "Debug Draw Distance", tooltip = "How far from the Scene Camera to draw probe debug visualizations. Large distances can impact Editor performance.", getter = () => probeVolumeDebug.probeCullingDistance, setter = value => probeVolumeDebug.probeCullingDistance = value, min = () => 0.0f }); 646 widgetList.Add(probeContainer); 647 648 var adjustmentContainer = new DebugUI.Container() 649 { 650 displayName = "Probe Adjustment Volumes" 651 }; 652 adjustmentContainer.children.Add(new DebugUI.BoolField 653 { 654 displayName = "Auto Display Probes", 655 tooltip = "When enabled and a Probe Adjustment Volumes is selected, automatically display the probes.", 656 getter = () => probeVolumeDebug.autoDrawProbes, 657 setter = value => probeVolumeDebug.autoDrawProbes = value, 658 onValueChanged = RefreshDebug 659 }); 660 adjustmentContainer.children.Add(new DebugUI.BoolField 661 { 662 displayName = "Isolate Affected", 663 tooltip = "When enabled, only displayed probes in the influence of the currently selected Probe Adjustment Volumes.", 664 getter = () => probeVolumeDebug.isolationProbeDebug, 665 setter = value => probeVolumeDebug.isolationProbeDebug = value, 666 onValueChanged = RefreshDebug 667 }); 668 widgetList.Add(adjustmentContainer); 669 670 var streamingContainer = new DebugUI.Container() 671 { 672 displayName = "Streaming", 673 isHiddenCallback = () => !(gpuStreamingEnabled || diskStreamingEnabled) 674 }; 675 streamingContainer.children.Add(new DebugUI.BoolField { displayName = "Freeze Streaming", tooltip = "Stop Unity from streaming probe data in or out of GPU memory.", getter = () => probeVolumeDebug.freezeStreaming, setter = value => probeVolumeDebug.freezeStreaming = value }); 676 streamingContainer.children.Add(new DebugUI.BoolField { displayName = "Display Streaming Score", getter = () => probeVolumeDebug.displayCellStreamingScore, setter = value => probeVolumeDebug.displayCellStreamingScore = value }); 677 streamingContainer.children.Add(new DebugUI.BoolField { displayName = "Maximum cell streaming", tooltip = "Enable streaming as many cells as possible every frame.", getter = () => instance.loadMaxCellsPerFrame, setter = value => instance.loadMaxCellsPerFrame = value}); 678 679 var maxCellStreamingContainerChildren = new DebugUI.Container() 680 { 681 isHiddenCallback = () => instance.loadMaxCellsPerFrame 682 }; 683 maxCellStreamingContainerChildren.children.Add(new DebugUI.IntField { displayName = "Loaded Cells Per Frame", tooltip = "Determines the maximum number of Cells Unity streams per frame. Loading more Cells per frame can impact performance.", getter = () => instance.numberOfCellsLoadedPerFrame, setter = value => instance.SetNumberOfCellsLoadedPerFrame(value), min = () => 1, max = () => kMaxCellLoadedPerFrame }); 684 streamingContainer.children.Add(maxCellStreamingContainerChildren); 685 686 // Those are mostly for internal dev purpose. 687 if (Debug.isDebugBuild) 688 { 689 streamingContainer.children.Add(new DebugUI.BoolField { displayName = "Display Index Fragmentation", getter = () => probeVolumeDebug.displayIndexFragmentation, setter = value => probeVolumeDebug.displayIndexFragmentation = value }); 690 var indexDefragContainerChildren = new DebugUI.Container() 691 { 692 isHiddenCallback = () => !probeVolumeDebug.displayIndexFragmentation 693 }; 694 indexDefragContainerChildren.children.Add(new DebugUI.Value { displayName = "Index Fragmentation Rate", getter = () => instance.indexFragmentationRate }); 695 streamingContainer.children.Add(indexDefragContainerChildren); 696 streamingContainer.children.Add(new DebugUI.BoolField { displayName = "Verbose Log", getter = () => probeVolumeDebug.verboseStreamingLog, setter = value => probeVolumeDebug.verboseStreamingLog = value }); 697 streamingContainer.children.Add(new DebugUI.BoolField { displayName = "Debug Streaming", getter = () => probeVolumeDebug.debugStreaming, setter = value => probeVolumeDebug.debugStreaming = value }); 698 } 699 700 widgetList.Add(streamingContainer); 701 702 if (supportScenarioBlending && m_CurrentBakingSet != null) 703 { 704 var blendingContainer = new DebugUI.Container() { displayName = "Scenario Blending" }; 705 blendingContainer.children.Add(new DebugUI.IntField { displayName = "Number Of Cells Blended Per Frame", getter = () => instance.numberOfCellsBlendedPerFrame, setter = value => instance.numberOfCellsBlendedPerFrame = value, min = () => 0 }); 706 blendingContainer.children.Add(new DebugUI.FloatField { displayName = "Turnover Rate", getter = () => instance.turnoverRate, setter = value => instance.turnoverRate = value, min = () => 0, max = () => 1 }); 707 708 void RefreshScenarioNames(string guid) 709 { 710 HashSet<string> allScenarios = new(); 711 foreach (var set in Resources.FindObjectsOfTypeAll<ProbeVolumeBakingSet>()) 712 { 713 if (!set.sceneGUIDs.Contains(guid)) 714 continue; 715 foreach (var scenario in set.lightingScenarios) 716 allScenarios.Add(scenario); 717 } 718 719 allScenarios.Remove(m_CurrentBakingSet.lightingScenario); 720 if (m_DebugActiveSceneGUID == guid && allScenarios.Count + 1 == m_DebugScenarioNames.Length && m_DebugActiveScenario == m_CurrentBakingSet.lightingScenario) 721 return; 722 723 int i = 0; 724 ArrayExtensions.ResizeArray(ref m_DebugScenarioNames, allScenarios.Count + 1); 725 ArrayExtensions.ResizeArray(ref m_DebugScenarioValues, allScenarios.Count + 1); 726 m_DebugScenarioNames[0] = new GUIContent("None"); 727 m_DebugScenarioValues[0] = 0; 728 foreach (var scenario in allScenarios) 729 { 730 i++; 731 m_DebugScenarioNames[i] = new GUIContent(scenario); 732 m_DebugScenarioValues[i] = i; 733 } 734 735 m_DebugActiveSceneGUID = guid; 736 m_DebugActiveScenario = m_CurrentBakingSet.lightingScenario; 737 m_DebugScenarioField.enumNames = m_DebugScenarioNames; 738 m_DebugScenarioField.enumValues = m_DebugScenarioValues; 739 if (probeVolumeDebug.otherStateIndex >= m_DebugScenarioNames.Length) 740 probeVolumeDebug.otherStateIndex = 0; 741 } 742 743 m_DebugScenarioField = new DebugUI.EnumField 744 { 745 displayName = "Scenario Blend Target", 746 tooltip = "Select another lighting scenario to blend with the active lighting scenario.", 747 enumNames = m_DebugScenarioNames, 748 enumValues = m_DebugScenarioValues, 749 getIndex = () => 750 { 751 if (m_CurrentBakingSet == null) 752 return 0; 753 RefreshScenarioNames(GetSceneGUID(SceneManagement.SceneManager.GetActiveScene())); 754 755 probeVolumeDebug.otherStateIndex = 0; 756 if (!string.IsNullOrEmpty(m_CurrentBakingSet.otherScenario)) 757 { 758 for (int i = 1; i < m_DebugScenarioNames.Length; i++) 759 { 760 if (m_DebugScenarioNames[i].text == m_CurrentBakingSet.otherScenario) 761 { 762 probeVolumeDebug.otherStateIndex = i; 763 break; 764 } 765 } 766 } 767 return probeVolumeDebug.otherStateIndex; 768 }, 769 setIndex = value => 770 { 771 string other = value == 0 ? null : m_DebugScenarioNames[value].text; 772 m_CurrentBakingSet.BlendLightingScenario(other, m_CurrentBakingSet.scenarioBlendingFactor); 773 probeVolumeDebug.otherStateIndex = value; 774 }, 775 getter = () => probeVolumeDebug.otherStateIndex, 776 setter = (value) => probeVolumeDebug.otherStateIndex = value, 777 }; 778 779 blendingContainer.children.Add(m_DebugScenarioField); 780 blendingContainer.children.Add(new DebugUI.FloatField { displayName = "Scenario Blending Factor", tooltip = "Blend between lighting scenarios by adjusting this slider.", getter = () => instance.scenarioBlendingFactor, setter = value => instance.scenarioBlendingFactor = value, min = () => 0.0f, max = () => 1.0f }); 781 782 widgetList.Add(blendingContainer); 783 } 784 785 if (widgetList.Count > 0) 786 { 787 m_DebugItems = widgetList.ToArray(); 788 var panel = DebugManager.instance.GetPanel(k_DebugPanelName, true); 789 panel.children.Add(m_DebugItems); 790 } 791 792 DebugManager debugManager = DebugManager.instance; 793 debugManager.RegisterData(probeVolumeDebug); 794 } 795 796 void UnregisterDebug(bool destroyPanel) 797 { 798 if (destroyPanel) 799 DebugManager.instance.RemovePanel(k_DebugPanelName); 800 else 801 DebugManager.instance.GetPanel(k_DebugPanelName, false).children.Remove(m_DebugItems); 802 } 803 804 class RenderFragmentationOverlayPassData 805 { 806 public Material debugFragmentationMaterial; 807 public Rendering.DebugOverlay debugOverlay; 808 public int chunkCount; 809 public ComputeBuffer debugFragmentationData; 810 public TextureHandle colorBuffer; 811 public TextureHandle depthBuffer; 812 } 813 814 /// <summary> 815 /// Render a debug view showing fragmentation of the GPU memory. 816 /// </summary> 817 /// <param name="renderGraph">The RenderGraph responsible for executing this pass.</param> 818 /// <param name="colorBuffer">The color buffer where the overlay will be rendered.</param> 819 /// <param name="depthBuffer">The depth buffer used for depth-testing the overlay.</param> 820 /// <param name="debugOverlay">The debug overlay manager to orchestrate multiple overlays.</param> 821 public void RenderFragmentationOverlay(RenderGraph renderGraph, TextureHandle colorBuffer, TextureHandle depthBuffer, DebugOverlay debugOverlay) 822 { 823 if (!m_ProbeReferenceVolumeInit || !probeVolumeDebug.displayIndexFragmentation) 824 return; 825 826 using (var builder = renderGraph.AddRenderPass<RenderFragmentationOverlayPassData>("APVFragmentationOverlay", out var passData)) 827 { 828 passData.debugOverlay = debugOverlay; 829 passData.debugFragmentationMaterial = m_DebugFragmentationMaterial; 830 passData.colorBuffer = builder.UseColorBuffer(colorBuffer, 0); 831 passData.depthBuffer = builder.UseDepthBuffer(depthBuffer, DepthAccess.ReadWrite); 832 passData.debugFragmentationData = m_Index.GetDebugFragmentationBuffer(); 833 passData.chunkCount = passData.debugFragmentationData.count; 834 835 builder.SetRenderFunc( 836 (RenderFragmentationOverlayPassData data, RenderGraphContext ctx) => 837 { 838 var mpb = ctx.renderGraphPool.GetTempMaterialPropertyBlock(); 839 840 data.debugOverlay.SetViewport(ctx.cmd); 841 mpb.SetInt("_ChunkCount", data.chunkCount); 842 mpb.SetBuffer("_DebugFragmentation", data.debugFragmentationData); 843 ctx.cmd.DrawProcedural(Matrix4x4.identity, data.debugFragmentationMaterial, 0, MeshTopology.Triangles, 3, 1, mpb); 844 data.debugOverlay.Next(); 845 }); 846 } 847 } 848 849 bool ShouldCullCell(Vector3 cellPosition, Transform cameraTransform, Plane[] frustumPlanes) 850 { 851 var volumeAABB = GetCellBounds(cellPosition); 852 var cellSize = MaxBrickSize(); 853 854 // We do coarse culling with cell, finer culling later. 855 float distanceRoundedUpWithCellSize = Mathf.CeilToInt(probeVolumeDebug.probeCullingDistance / cellSize) * cellSize; 856 857 if (Vector3.Distance(cameraTransform.position, volumeAABB.center) > distanceRoundedUpWithCellSize) 858 return true; 859 860 return !GeometryUtility.TestPlanesAABB(frustumPlanes, volumeAABB); 861 } 862 863 static Vector4[] s_BoundsArray = new Vector4[16 * 3]; 864 865 static void UpdateDebugFromSelection(ref Vector4[] _AdjustmentVolumeBounds, ref int _AdjustmentVolumeCount) 866 { 867 if (ProbeVolumeDebug.s_ActiveAdjustmentVolumes == 0) 868 return; 869 870 #if UNITY_EDITOR 871 foreach (var touchup in Selection.GetFiltered<ProbeAdjustmentVolume>(SelectionMode.Unfiltered)) 872 { 873 if (!touchup.isActiveAndEnabled) continue; 874 875 Volume volume = new Volume(Matrix4x4.TRS(touchup.transform.position, touchup.transform.rotation, touchup.GetExtents()), 0, 0); 876 volume.CalculateCenterAndSize(out Vector3 center, out var _); 877 878 if (touchup.shape == ProbeAdjustmentVolume.Shape.Sphere) 879 { 880 volume.Z.x = float.MaxValue; 881 volume.X.x = touchup.radius; 882 } 883 else 884 { 885 volume.X *= 0.5f; 886 volume.Y *= 0.5f; 887 volume.Z *= 0.5f; 888 } 889 890 _AdjustmentVolumeBounds[_AdjustmentVolumeCount * 3 + 0] = new Vector4(center.x, center.y, center.z, volume.Z.x); 891 _AdjustmentVolumeBounds[_AdjustmentVolumeCount * 3 + 1] = new Vector4(volume.X.x, volume.X.y, volume.X.z, volume.Z.y); 892 _AdjustmentVolumeBounds[_AdjustmentVolumeCount * 3 + 2] = new Vector4(volume.Y.x, volume.Y.y, volume.Y.z, volume.Z.z); 893 894 if (++_AdjustmentVolumeCount == 16) 895 break; 896 } 897 #endif 898 } 899 900 Bounds GetCellBounds(Vector3 cellPosition) 901 { 902 var cellSize = MaxBrickSize(); 903 var cellOffset = ProbeOffset() + ProbeVolumeDebug.currentOffset; 904 Vector3 cellCenterWS = cellOffset + cellPosition * cellSize + Vector3.one * (cellSize / 2.0f); 905 906 return new Bounds(cellCenterWS, cellSize * Vector3.one); 907 } 908 909 bool ShouldCullCell(Vector3 cellPosition, Vector4[] adjustmentVolumeBounds, int adjustmentVolumeCount) 910 { 911 var cellAABB = GetCellBounds(cellPosition); 912 913 for (int touchup = 0; touchup < adjustmentVolumeCount; touchup++) 914 { 915 Vector3 center = adjustmentVolumeBounds[touchup * 3 + 0]; 916 917 if (adjustmentVolumeBounds[touchup * 3].w == float.MaxValue) // sphere 918 { 919 var diameter = adjustmentVolumeBounds[touchup * 3 + 1].x * 2.0f; 920 Bounds bounds = new Bounds(center, new Vector3(diameter, diameter, diameter)); 921 922 if (bounds.Intersects(cellAABB)) 923 return false; 924 } 925 else 926 { 927 Volume volume = new Volume(); 928 volume.X = adjustmentVolumeBounds[touchup * 3 + 1]; 929 volume.Y = adjustmentVolumeBounds[touchup * 3 + 2]; 930 volume.Z = new Vector3(adjustmentVolumeBounds[touchup * 3 + 0].w, adjustmentVolumeBounds[touchup * 3 + 1].w, adjustmentVolumeBounds[touchup * 3 + 2].w); 931 932 volume.corner = center - volume.X - volume.Y - volume.Z; 933 volume.X *= 2.0f; 934 volume.Y *= 2.05f; 935 volume.Z *= 2.0f; 936 937 if (ProbeVolumePositioning.OBBAABBIntersect(volume, cellAABB, volume.CalculateAABB())) 938 return false; 939 } 940 } 941 return true; 942 } 943 944 void DrawProbeDebug(Camera camera, Texture exposureTexture) 945 { 946 if (!enabledBySRP || !isInitialized) 947 return; 948 949 bool drawProbes = probeVolumeDebug.drawProbes; 950 bool debugDraw = drawProbes || 951 probeVolumeDebug.drawVirtualOffsetPush || 952 probeVolumeDebug.drawProbeSamplingDebug; 953 954 int adjustmentVolumeCount = 0; 955 Vector4[] adjustmentVolumeBounds = s_BoundsArray; 956 if (!debugDraw && probeVolumeDebug.autoDrawProbes) 957 { 958 UpdateDebugFromSelection(ref adjustmentVolumeBounds, ref adjustmentVolumeCount); 959 drawProbes |= adjustmentVolumeCount != 0; 960 } 961 962 if (!debugDraw && !drawProbes) 963 return; 964 965 GeometryUtility.CalculateFrustumPlanes(camera, m_DebugFrustumPlanes); 966 967 m_DebugMaterial.shaderKeywords = null; 968 if (m_SHBands == ProbeVolumeSHBands.SphericalHarmonicsL1) 969 m_DebugMaterial.EnableKeyword("PROBE_VOLUMES_L1"); 970 else if (m_SHBands == ProbeVolumeSHBands.SphericalHarmonicsL2) 971 m_DebugMaterial.EnableKeyword("PROBE_VOLUMES_L2"); 972 973 // This is to force the rendering not to draw to the depth pre pass and still behave. 974 // They are going to be rendered opaque anyhow, just using the transparent render queue to make sure 975 // they properly behave w.r.t fog. 976 m_DebugMaterial.renderQueue = (int)RenderQueue.Transparent; 977 m_DebugOffsetMaterial.renderQueue = (int)RenderQueue.Transparent; 978 m_ProbeSamplingDebugMaterial.renderQueue = (int)RenderQueue.Transparent; 979 m_ProbeSamplingDebugMaterial02.renderQueue = (int)RenderQueue.Transparent; 980 981 m_DebugMaterial.SetVector("_DebugEmptyProbeData", APVDefinitions.debugEmptyColor); 982 983 if (probeVolumeDebug.drawProbeSamplingDebug) 984 { 985 m_ProbeSamplingDebugMaterial.SetInt("_ShadingMode", (int)probeVolumeDebug.probeShading); 986 m_ProbeSamplingDebugMaterial.SetInt("_RenderingLayerMask", (int)probeVolumeDebug.samplingRenderingLayer); 987 m_ProbeSamplingDebugMaterial.SetVector("_DebugArrowColor", new Vector4(1.0f, 1.0f, 1.0f, 1.0f)); 988 m_ProbeSamplingDebugMaterial.SetVector("_DebugLocator01Color", new Vector4(1.0f, 1.0f, 1.0f, 1.0f)); 989 m_ProbeSamplingDebugMaterial.SetVector("_DebugLocator02Color", new Vector4(0.3f, 0.3f, 0.3f, 1.0f)); 990 m_ProbeSamplingDebugMaterial.SetFloat("_ProbeSize", probeVolumeDebug.probeSamplingDebugSize); 991 m_ProbeSamplingDebugMaterial.SetTexture("_NumbersTex", m_DisplayNumbersTexture); 992 m_ProbeSamplingDebugMaterial.SetInt("_DebugSamplingNoise", Convert.ToInt32(probeVolumeDebug.debugWithSamplingNoise)); 993 m_ProbeSamplingDebugMaterial.SetInt("_ForceDebugNormalViewBias", 0); // Add a secondary locator to show intermediate position (with no Anti-Leak) when Anti-Leak is active 994 995 m_ProbeSamplingDebugMaterial.SetBuffer("_positionNormalBuffer", probeSamplingDebugData.positionNormalBuffer); 996 997 Graphics.DrawMesh(m_DebugProbeSamplingMesh, new Vector4(0.0f, 0.0f, 0.0f, 1.0f), Quaternion.identity, m_ProbeSamplingDebugMaterial, 0, camera); 998 Graphics.ClearRandomWriteTargets(); 999 } 1000 1001 // Sanitize the min max subdiv levels with what is available 1002 int minAvailableSubdiv = cells.Count > 0 ? GetMaxSubdivision()-1 : 0; 1003 foreach (var cell in cells.Values) 1004 { 1005 minAvailableSubdiv = Mathf.Min(minAvailableSubdiv, cell.desc.minSubdiv); 1006 } 1007 1008 int maxSubdivToVisualize = Mathf.Max(0, Mathf.Min(probeVolumeDebug.maxSubdivToVisualize, GetMaxSubdivision() - 1)); 1009 int minSubdivToVisualize = Mathf.Clamp(probeVolumeDebug.minSubdivToVisualize, minAvailableSubdiv, maxSubdivToVisualize); 1010 m_MaxSubdivVisualizedIsMaxAvailable = maxSubdivToVisualize == GetMaxSubdivision() - 1; 1011 1012 bool adjustmentCulling = drawProbes && !probeVolumeDebug.drawProbes && probeVolumeDebug.isolationProbeDebug; 1013 foreach (var cell in cells.Values) 1014 { 1015 if (ShouldCullCell(cell.desc.position, camera.transform, m_DebugFrustumPlanes)) 1016 continue; 1017 1018 if (adjustmentCulling && ShouldCullCell(cell.desc.position, adjustmentVolumeBounds, adjustmentVolumeCount)) 1019 continue; 1020 1021 var debug = CreateInstancedProbes(cell); 1022 1023 if (debug == null) 1024 continue; 1025 1026 for (int i = 0; i < debug.probeBuffers.Count; ++i) 1027 { 1028 var props = debug.props[i]; 1029 props.SetInt("_ShadingMode", (int)probeVolumeDebug.probeShading); 1030 props.SetFloat("_ExposureCompensation", probeVolumeDebug.exposureCompensation); 1031 props.SetFloat("_ProbeSize", probeVolumeDebug.probeSize); 1032 props.SetFloat("_CullDistance", probeVolumeDebug.probeCullingDistance); 1033 props.SetInt("_MaxAllowedSubdiv", maxSubdivToVisualize); 1034 props.SetInt("_MinAllowedSubdiv", minSubdivToVisualize); 1035 props.SetFloat("_ValidityThreshold", m_CurrentBakingSet.settings.dilationSettings.dilationValidityThreshold); 1036 props.SetInt("_RenderingLayerMask", probeVolumeDebug.visibleLayers); 1037 props.SetFloat("_OffsetSize", probeVolumeDebug.offsetSize); 1038 props.SetTexture("_ExposureTexture", exposureTexture); 1039 1040 if (drawProbes) 1041 { 1042 m_DebugMaterial.SetVectorArray("_TouchupVolumeBounds", adjustmentVolumeBounds); 1043 m_DebugMaterial.SetInt("_AdjustmentVolumeCount", probeVolumeDebug.isolationProbeDebug ? adjustmentVolumeCount : 0); 1044 m_DebugMaterial.SetVector("_ScreenSize", new Vector4(camera.pixelWidth, camera.pixelHeight, 1.0f/camera.pixelWidth, 1.0f/camera.pixelHeight)); 1045 1046 var probeBuffer = debug.probeBuffers[i]; 1047 m_DebugMaterial.SetInt("_DebugProbeVolumeSampling", 0); 1048 m_DebugMaterial.SetBuffer("_positionNormalBuffer", probeSamplingDebugData.positionNormalBuffer); 1049 Graphics.DrawMeshInstanced(debugMesh, 0, m_DebugMaterial, probeBuffer, probeBuffer.Length, props, ShadowCastingMode.Off, false, 0, camera, LightProbeUsage.Off, null); 1050 } 1051 1052 if (probeVolumeDebug.drawProbeSamplingDebug) 1053 { 1054 var probeBuffer = debug.probeBuffers[i]; 1055 m_ProbeSamplingDebugMaterial02.SetInt("_DebugProbeVolumeSampling", 1); 1056 props.SetInt("_ShadingMode", (int)DebugProbeShadingMode.SH); 1057 props.SetFloat("_ProbeSize", probeVolumeDebug.probeSamplingDebugSize); 1058 props.SetInt("_DebugSamplingNoise", Convert.ToInt32(probeVolumeDebug.debugWithSamplingNoise)); 1059 props.SetInt("_RenderingLayerMask", (int)probeVolumeDebug.samplingRenderingLayer); 1060 m_ProbeSamplingDebugMaterial02.SetBuffer("_positionNormalBuffer", probeSamplingDebugData.positionNormalBuffer); 1061 Graphics.DrawMeshInstanced(debugMesh, 0, m_ProbeSamplingDebugMaterial02, probeBuffer, probeBuffer.Length, props, ShadowCastingMode.Off, false, 0, camera, LightProbeUsage.Off, null); 1062 } 1063 1064 if (probeVolumeDebug.drawVirtualOffsetPush) 1065 { 1066 m_DebugOffsetMaterial.SetVectorArray("_TouchupVolumeBounds", adjustmentVolumeBounds); 1067 m_DebugOffsetMaterial.SetInt("_AdjustmentVolumeCount", probeVolumeDebug.isolationProbeDebug ? adjustmentVolumeCount : 0); 1068 1069 var offsetBuffer = debug.offsetBuffers[i]; 1070 Graphics.DrawMeshInstanced(m_DebugOffsetMesh, 0, m_DebugOffsetMaterial, offsetBuffer, offsetBuffer.Length, props, ShadowCastingMode.Off, false, 0, camera, LightProbeUsage.Off, null); 1071 } 1072 } 1073 } 1074 } 1075 1076 internal void ResetDebugViewToMaxSubdiv() 1077 { 1078 if (m_MaxSubdivVisualizedIsMaxAvailable) 1079 probeVolumeDebug.maxSubdivToVisualize = GetMaxSubdivision() - 1; 1080 } 1081 1082 void ClearDebugData() 1083 { 1084 realtimeSubdivisionInfo.Clear(); 1085 } 1086 1087 CellInstancedDebugProbes CreateInstancedProbes(Cell cell) 1088 { 1089 if (cell.debugProbes != null) 1090 return cell.debugProbes; 1091 1092 int maxSubdiv = GetMaxSubdivision() - 1; 1093 1094 if (!cell.data.bricks.IsCreated || cell.data.bricks.Length == 0 || !cell.data.probePositions.IsCreated || !cell.loaded) 1095 return null; 1096 1097 List<Matrix4x4[]> probeBuffers = new List<Matrix4x4[]>(); 1098 List<Matrix4x4[]> offsetBuffers = new List<Matrix4x4[]>(); 1099 List<MaterialPropertyBlock> props = new List<MaterialPropertyBlock>(); 1100 var chunks = cell.poolInfo.chunkList; 1101 1102 Vector4[] texels = new Vector4[kProbesPerBatch]; 1103 float[] layer = new float[kProbesPerBatch]; 1104 float[] validity = new float[kProbesPerBatch]; 1105 float[] dilationThreshold = new float[kProbesPerBatch]; 1106 float[] relativeSize = new float[kProbesPerBatch]; 1107 float[] touchupUpVolumeAction = cell.data.touchupVolumeInteraction.Length > 0 ? new float[kProbesPerBatch] : null; 1108 Vector4[] offsets = cell.data.offsetVectors.Length > 0 ? new Vector4[kProbesPerBatch] : null; 1109 1110 List<Matrix4x4> probeBuffer = new List<Matrix4x4>(); 1111 List<Matrix4x4> offsetBuffer = new List<Matrix4x4>(); 1112 1113 var debugData = new CellInstancedDebugProbes(); 1114 debugData.probeBuffers = probeBuffers; 1115 debugData.offsetBuffers = offsetBuffers; 1116 debugData.props = props; 1117 1118 var chunkSizeInProbes = ProbeBrickPool.GetChunkSizeInProbeCount(); 1119 1120 var loc = ProbeBrickPool.ProbeCountToDataLocSize(chunkSizeInProbes); 1121 1122 float baseThreshold = m_CurrentBakingSet.settings.dilationSettings.dilationValidityThreshold; 1123 int idxInBatch = 0; 1124 int globalIndex = 0; 1125 int brickCount = cell.desc.probeCount / ProbeBrickPool.kBrickProbeCountTotal; 1126 int bx = 0, by = 0, bz = 0; 1127 for (int brickIndex = 0; brickIndex < brickCount; ++brickIndex) 1128 { 1129 Debug.Assert(bz < loc.z); 1130 1131 int brickSize = cell.data.bricks[brickIndex].subdivisionLevel; 1132 int chunkIndex = brickIndex / ProbeBrickPool.GetChunkSizeInBrickCount(); 1133 var chunk = chunks[chunkIndex]; 1134 Vector3Int brickStart = new Vector3Int(chunk.x + bx, chunk.y + by, chunk.z + bz); 1135 1136 for (int z = 0; z < ProbeBrickPool.kBrickProbeCountPerDim; ++z) 1137 { 1138 for (int y = 0; y < ProbeBrickPool.kBrickProbeCountPerDim; ++y) 1139 { 1140 for (int x = 0; x < ProbeBrickPool.kBrickProbeCountPerDim; ++x) 1141 { 1142 Vector3Int texelLoc = new Vector3Int(brickStart.x + x, brickStart.y + y, brickStart.z + z); 1143 1144 int probeFlatIndex = chunkIndex * chunkSizeInProbes + (bx + x) + loc.x * ((by + y) + loc.y * (bz + z)); 1145 var position = cell.data.probePositions[probeFlatIndex] - ProbeOffset(); // Offset is applied in shader 1146 1147 probeBuffer.Add(Matrix4x4.TRS(position, Quaternion.identity, Vector3.one * (0.3f * (brickSize + 1)))); 1148 validity[idxInBatch] = cell.data.validity[probeFlatIndex]; 1149 dilationThreshold[idxInBatch] = baseThreshold; 1150 texels[idxInBatch] = new Vector4(texelLoc.x, texelLoc.y, texelLoc.z, brickSize); 1151 relativeSize[idxInBatch] = (float)brickSize / (float)maxSubdiv; 1152 1153 layer[idxInBatch] = Unity.Mathematics.math.asfloat(cell.data.layer.Length > 0 ? cell.data.layer[probeFlatIndex] : 0xFFFFFFFF); 1154 1155 if (touchupUpVolumeAction != null) 1156 { 1157 touchupUpVolumeAction[idxInBatch] = cell.data.touchupVolumeInteraction[probeFlatIndex]; 1158 dilationThreshold[idxInBatch] = touchupUpVolumeAction[idxInBatch] > 1.0f ? touchupUpVolumeAction[idxInBatch] - 1.0f : baseThreshold; 1159 } 1160 1161 if (offsets != null) 1162 { 1163 const float kOffsetThresholdSqr = 1e-6f; 1164 1165 var offset = cell.data.offsetVectors[probeFlatIndex]; 1166 offsets[idxInBatch] = offset; 1167 1168 if (offset.sqrMagnitude < kOffsetThresholdSqr) 1169 { 1170 offsetBuffer.Add(Matrix4x4.identity); 1171 } 1172 else 1173 { 1174 var orientation = Quaternion.LookRotation(-offset); 1175 var scale = new Vector3(0.5f, 0.5f, offset.magnitude); 1176 offsetBuffer.Add(Matrix4x4.TRS(position + offset, orientation, scale)); 1177 } 1178 } 1179 idxInBatch++; 1180 1181 if (probeBuffer.Count >= kProbesPerBatch || globalIndex == cell.desc.probeCount - 1) 1182 { 1183 idxInBatch = 0; 1184 MaterialPropertyBlock prop = new MaterialPropertyBlock(); 1185 1186 prop.SetFloatArray("_Validity", validity); 1187 prop.SetFloatArray("_RenderingLayer", layer); 1188 prop.SetFloatArray("_DilationThreshold", dilationThreshold); 1189 prop.SetFloatArray("_TouchupedByVolume", touchupUpVolumeAction); 1190 prop.SetFloatArray("_RelativeSize", relativeSize); 1191 prop.SetVectorArray("_IndexInAtlas", texels); 1192 1193 if (offsets != null) 1194 prop.SetVectorArray("_Offset", offsets); 1195 1196 props.Add(prop); 1197 1198 probeBuffers.Add(probeBuffer.ToArray()); 1199 probeBuffer.Clear(); 1200 1201 offsetBuffers.Add(offsetBuffer.ToArray()); 1202 offsetBuffer.Clear(); 1203 } 1204 1205 globalIndex++; 1206 } 1207 } 1208 } 1209 1210 bx += ProbeBrickPool.kBrickProbeCountPerDim; 1211 if (bx >= loc.x) 1212 { 1213 bx = 0; 1214 by += ProbeBrickPool.kBrickProbeCountPerDim; 1215 if (by >= loc.y) 1216 { 1217 by = 0; 1218 bz += ProbeBrickPool.kBrickProbeCountPerDim; 1219 if (bz >= loc.z) 1220 { 1221 bx = 0; 1222 by = 0; 1223 bz = 0; 1224 } 1225 } 1226 } 1227 } 1228 1229 cell.debugProbes = debugData; 1230 1231 return debugData; 1232 } 1233 1234 void OnClearLightingdata() 1235 { 1236 ClearDebugData(); 1237 } 1238 } 1239}