void Refresh()
            {
                var panel = DebugManager.instance.GetPanel(PanelName);

                if (panel == null)
                {
                    return;
                }

                bool needsRefresh = false;

                if (m_VolumeTable != null)
                {
                    needsRefresh = true;
                    panel.children.Remove(m_VolumeTable);
                }

                if (m_Data.volumeDebugSettings.selectedComponent > 0 && m_Data.volumeDebugSettings.selectedCamera != null)
                {
                    needsRefresh  = true;
                    m_VolumeTable = WidgetFactory.CreateVolumeTable(m_Data);
                    AddWidget(m_VolumeTable);
                    panel.children.Add(m_VolumeTable);
                }

                if (needsRefresh)
                {
                    DebugManager.instance.ReDrawOnScreenDebug();
                }
            }
            public static DebugUI.Table CreateVolumeTable(DebugDisplaySettingsVolume data)
            {
                var table = new DebugUI.Table()
                {
                    displayName = Strings.parameter,
                    isReadOnly  = true
                };

                Type selectedType = data.volumeDebugSettings.selectedComponentType;

                if (selectedType == null)
                {
                    return(table);
                }

                var stack          = data.volumeDebugSettings.selectedCameraVolumeStack ?? VolumeManager.instance.stack;
                var stackComponent = stack.GetComponent(selectedType);

                if (stackComponent == null)
                {
                    return(table);
                }

                var volumes = data.volumeDebugSettings.GetVolumes();

                var inst = (VolumeComponent)ScriptableObject.CreateInstance(selectedType);

                // First row for volume info
                float timer = 0.0f, refreshRate = 0.2f;
                var   row = new DebugUI.Table.Row()
                {
                    displayName = Strings.volumeInfo,
                    opened      = true, // Open by default for the in-game view
                    children    = { new DebugUI.Value()
                                    {
                                        displayName = Strings.interpolatedValue,
                                        getter      = () => {
                                            // This getter is called first at each render
                                            // It is used to update the volumes
                                            if (Time.time - timer < refreshRate)
                                            {
                                                return(string.Empty);
                                            }
                                            timer = Time.deltaTime;
                                            if (data.volumeDebugSettings.selectedCamera != null)
                                            {
                                                var newVolumes = data.volumeDebugSettings.GetVolumes();
                                                if (!data.volumeDebugSettings.RefreshVolumes(newVolumes))
                                                {
                                                    for (int i = 0; i < newVolumes.Length; i++)
                                                    {
                                                        var visible = data.volumeDebugSettings.VolumeHasInfluence(newVolumes[i]);
                                                        table.SetColumnVisibility(i + 1, visible);
                                                    }
                                                    return(string.Empty);
                                                }
                                            }
                                            DebugManager.instance.ReDrawOnScreenDebug();
                                            return(string.Empty);
                                        }
                                    } }
                };

                // Second row, links to volume gameobjects
                var row2 = new DebugUI.Table.Row()
                {
                    displayName = "GameObject",
                    children    = { new DebugUI.Value()
                                    {
                                        getter = () => string.Empty
                                    } }
                };

                foreach (var volume in volumes)
                {
                    var profile = volume.HasInstantiatedProfile() ? volume.profile : volume.sharedProfile;
                    row.children.Add(new DebugUI.Value()
                    {
                        displayName = profile.name,
                        getter      = () =>
                        {
                            var scope  = volume.isGlobal ? Strings.global : Strings.local;
                            var weight = data.volumeDebugSettings.GetVolumeWeight(volume);
                            return(scope + " (" + (weight * 100f) + "%)");
                        }
                    });

                    row2.children.Add(new DebugUI.ObjectField()
                    {
                        displayName = profile.name,
                        getter      = () => volume,
                    });
                }

                row.children.Add(new DebugUI.Value()
                {
                    displayName = Strings.defaultValue, getter = () => string.Empty
                });
                table.children.Add(row);

                row2.children.Add(new DebugUI.Value()
                {
                    getter = () => string.Empty
                });
                table.children.Add(row2);

                // Build rows - recursively handles nested parameters
                var rows = new List <DebugUI.Table.Row>();

                void AddParameterRows(Type type, string baseName = null)
                {
                    void AddRow(FieldInfo f, string prefix)
                    {
                        var fieldName = prefix + f.Name;

                        var attr = (DisplayInfoAttribute[])f.GetCustomAttributes(typeof(DisplayInfoAttribute), true);

                        if (attr.Length != 0)
                        {
                            fieldName = prefix + attr[0].name;
                        }
#if UNITY_EDITOR
                        // Would be nice to have the equivalent for the runtime debug.
                        else
                        {
                            fieldName = UnityEditor.ObjectNames.NicifyVariableName(fieldName);
                        }
#endif

                        int currentParam = rows.Count;
                        row = new DebugUI.Table.Row()
                        {
                            displayName = fieldName,
                            children    = { CreateVolumeParameterWidget(Strings.interpolatedValue, stackComponent.parameters[currentParam]) },
                        };

                        foreach (var volume in volumes)
                        {
                            VolumeParameter param   = null;
                            var             profile = volume.HasInstantiatedProfile() ? volume.profile : volume.sharedProfile;
                            if (profile.TryGet(selectedType, out VolumeComponent component))
                            {
                                param = component.parameters[currentParam];
                            }
                            row.children.Add(CreateVolumeParameterWidget(volume.name + " (" + profile.name + ")", param, () => !component.parameters[currentParam].overrideState));
                        }

                        row.children.Add(CreateVolumeParameterWidget(Strings.defaultValue, inst.parameters[currentParam]));
                        rows.Add(row);
                    }

                    var fields = type
                                 .GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
                                 .OrderBy(t => t.MetadataToken);
                    foreach (var field in fields)
                    {
                        if (field.GetCustomAttributes(typeof(ObsoleteAttribute), false).Length != 0)
                        {
                            continue;
                        }
                        var fieldType = field.FieldType;
                        if (fieldType.IsSubclassOf(typeof(VolumeParameter)))
                        {
                            AddRow(field, baseName ?? string.Empty);
                        }
                        else if (!fieldType.IsArray && fieldType.IsClass)
                        {
                            AddParameterRows(fieldType, baseName ?? (field.Name + " "));
                        }
                    }
                }

                AddParameterRows(selectedType);
                foreach (var r in rows.OrderBy(t => t.displayName))
                {
                    table.children.Add(r);
                }

                data.volumeDebugSettings.RefreshVolumes(volumes);
                for (int i = 0; i < volumes.Length; i++)
                {
                    table.SetColumnVisibility(i + 1, data.volumeDebugSettings.VolumeHasInfluence(volumes[i]));
                }

                return(table);
            }