/// <summary>
        /// Lerps between profile1 and profile2 using t as the transition amount (0..1) and assign the values to given fog
        /// </summary>
        public static void Lerp(VolumetricFogProfile profile1, VolumetricFogProfile profile2, float t, VolumetricFog fog)
        {
            if (t < 0)
            {
                t = 0;
            }
            else if (t > 1f)
            {
                t = 1f;
            }

            // Fog Geo
            fog.density                       = profile1.density * (1f - t) + profile2.density * t;
            fog.noiseStrength                 = profile1.noiseStrength * (1f - t) + profile2.noiseStrength * t;
            fog.height                        = profile1.height * (1f - t) + profile2.height * t;
            fog.baselineHeight                = profile1.baselineHeight * (1f - t) + profile2.baselineHeight * t;
            fog.distance                      = profile1.baselineHeight * (1f - t) + profile2.distance * t;
            fog.distanceFallOff               = profile1.distanceFallOff * (1f - t) + profile2.distanceFallOff * t;
            fog.maxFogLength                  = profile1.maxFogLength * (1f - t) + profile2.maxFogLength * t;
            fog.maxFogLengthFallOff           = profile1.maxFogLengthFallOff * (1f - t) + profile2.maxFogLengthFallOff * t;
            fog.baselineRelativeToCamera      = t < 0.5f ? profile1.baselineRelativeToCamera : profile2.baselineRelativeToCamera;
            fog.baselineRelativeToCameraDelay = profile1.baselineRelativeToCameraDelay * (1f - t) + profile2.baselineRelativeToCameraDelay * t;
            fog.noiseScale                    = profile1.noiseScale * (1f - t) + profile2.noiseScale * t;
            fog.noiseSparse                   = profile1.noiseSparse * (1f - t) + profile2.noiseSparse * t;
            fog.noiseFinalMultiplier          = profile1.noiseFinalMultiplier * (1f - t) + profile2.noiseFinalMultiplier * t;

            // Fog Colors
            fog.sunCopyColor      = t < 0.5f ? profile1.sunCopyColor : profile2.sunCopyColor;
            fog.alpha             = profile1.alpha * (1f - t) + profile2.alpha * t;
            fog.color             = profile1.color * (1f - t) + profile2.color * t;
            fog.specularColor     = profile1.specularColor * (1f - t) + profile2.color * t;
            fog.specularThreshold = profile1.specularThreshold * (1f - t) + profile2.specularThreshold * t;
            fog.specularIntensity = profile1.specularIntensity * (1f - t) + profile2.specularIntensity * t;
            fog.lightDirection    = profile1.lightDirection * (1f - t) + profile2.lightDirection * t;
            fog.lightIntensity    = profile1.lightIntensity * (1f - t) + profile2.lightIntensity * t;
            fog.lightColor        = profile1.lightColor * (1f - t) + profile2.lightColor * t;

            // Fog animation
            fog.speed              = profile1.speed * (1f - t) + profile2.speed * t;
            fog.windDirection      = profile1.windDirection * (1f - t) + profile2.windDirection * t;
            fog.turbulenceStrength = profile1.turbulenceStrength * (1f - t) + profile2.turbulenceStrength * t;

            // Fog sky
            fog.skyColor         = profile1.skyColor * (1f - t) + profile2.skyColor * t;
            fog.skyHaze          = profile1.skyHaze * (1f - t) + profile2.skyHaze * t;
            fog.skySpeed         = profile1.skySpeed * (1f - t) + profile2.skySpeed * t;
            fog.skyNoiseStrength = profile1.skyNoiseStrength * (1f - t) + profile2.skyNoiseStrength * t;
            fog.skyAlpha         = profile1.skyAlpha * (1f - t) + profile2.skyAlpha * t;

            // Optimization
            fog.stepping       = profile1.stepping * (1f - t) + profile2.stepping * t;
            fog.steppingNear   = profile1.steppingNear * (1f - t) + profile2.steppingNear * t;
            fog.dithering      = t < 0.5f ? profile1.dithering : profile2.dithering;
            fog.ditherStrength = profile1.ditherStrength * (1f - t) + profile2.ditherStrength * t;
        }
        public override void OnInspectorGUI()
        {
            serializedObject.Update();

            EditorGUILayout.Separator();
            EditorGUILayout.BeginVertical();

            EditorGUILayout.BeginHorizontal();
            DrawTitleLabel("Volumetric Fog Profile");
            if (GUILayout.Button("Help", GUILayout.Width(50)))
            {
                EditorUtility.DisplayDialog("Help", "Move the mouse over each label to show a description of the parameter.", "Ok");
            }
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.Separator();
            EditorGUILayout.EndVertical();
            EditorGUILayout.Separator();

            EditorGUILayout.BeginVertical();
            DrawTitleLabel("Geometry");
            EditorGUILayout.PropertyField(distance, new GUIContent("Distance", "Distance in meters from the camera at which the fog starts. It works with Distance FallOff."));
            EditorGUILayout.PropertyField(distanceFallOff, new GUIContent("   Fall Off", "When you set a value to Distance > 0, this parameter defines the gradient of the fog to the camera. The higher the value, the shorter the gradient."));
            EditorGUILayout.PropertyField(maxFogLength, new GUIContent("Max. Distance", "Maximum distance from camera at which the fog is rendered. Decrease this value to improve performance."));
            EditorGUILayout.PropertyField(maxFogLengthFallOff, new GUIContent("   FallOff", "Blends far range with background."));
            EditorGUILayout.PropertyField(height, new GUIContent("Height", "Maximum height of the fog in meters."));
            EditorGUILayout.PropertyField(useXYPlane, new GUIContent("Use XY Plane", "Switches between normal mode to XY mode."));
            EditorGUILayout.BeginHorizontal();
            if (useXYPlane.boolValue)
            {
                EditorGUILayout.PropertyField(baselineHeight, new GUIContent("Base Z", "Starting Z of the fog in meters."));
            }
            else
            {
                EditorGUILayout.PropertyField(baselineHeight, new GUIContent("Base Height", "Starting height of the fog in meters. You can set this value above Camera position. Try it!"));
            }
            EditorGUILayout.EndHorizontal();

            if (useXYPlane.boolValue)
            {
                GUI.enabled = false;
            }
            EditorGUILayout.PropertyField(baselineRelativeToCamera, new GUIContent("Relative To Camera", "If set to true, the base height will be added to the camera height. This is useful for cloud styles so they always stay over your head!"));
            if (baselineRelativeToCamera.boolValue)
            {
                EditorGUILayout.PropertyField(baselineRelativeToCameraDelay, new GUIContent("Delay", "Speed factor for transitioning to new camera heights."));
            }
            GUI.enabled = true;

            EditorGUILayout.Separator();

            EditorGUILayout.EndVertical();
            EditorGUILayout.Separator();

            EditorGUILayout.BeginVertical();
            DrawTitleLabel("Appearance");
            EditorGUILayout.PropertyField(density, new GUIContent("Density", "General density of the fog. Higher density fog means darker fog as well."));
            EditorGUILayout.PropertyField(noiseStrength, new GUIContent("Noise Strength", "Randomness of the fog formation. 0 means uniform fog whereas a value towards 1 will make areas of different densities and heights."));
            EditorGUILayout.PropertyField(noiseScale, new GUIContent("   Scale", "Increasing this value will expand the size of the noise."));
            EditorGUILayout.PropertyField(noiseSparse, new GUIContent("   Sparse", "Increase to make noise sparser."));
            EditorGUILayout.PropertyField(noiseFinalMultiplier, new GUIContent("   Final Multiplier", "Final noise value multiplier."));
            EditorGUILayout.PropertyField(alpha, new GUIContent("Alpha", "Transparency for the fog. You may want to reduce this value if you experiment issues with billboards."));
            EditorGUILayout.PropertyField(color, new GUIContent("Albedo", "Base color of the fog."));
            EditorGUILayout.PropertyField(specularColor, new GUIContent("Specular Color", "This is the color reflected by the fog under direct light exposure (see Light parameters)"));
            EditorGUILayout.PropertyField(specularThreshold, new GUIContent("Specular Threshold", "Area of the fog subject to light reflectancy"));
            EditorGUILayout.PropertyField(specularIntensity, new GUIContent("Specular Intensity", "The intensity of the reflected light."));
            EditorGUILayout.PropertyField(lightDirection, new GUIContent("Light Direction", "The normalized direction of a simulated directional light."));
            EditorGUILayout.PropertyField(lightingModel, new GUIContent("Lighting Model", "The lighting model used to calculate fog color. 'Legacy' is provided for previous version compatibility. 'Natural' uses ambient + light color. 'Single Light' excludes ambient color."));
            EditorGUILayout.PropertyField(lightIntensity, new GUIContent("Light Intensity", "Intensity of the simulated directional light."));
            EditorGUILayout.PropertyField(lightColor, new GUIContent("Light Color", "Color of the simulated direcional light."));
            EditorGUILayout.PropertyField(sunCopyColor, new GUIContent("Copy Sun Color", "Always use Sun light color. Disable this property to allow choosing a custom light color."));

            EditorGUILayout.EndVertical();
            EditorGUILayout.Separator();

            EditorGUILayout.BeginVertical();
            DrawTitleLabel("Animation");
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.PropertyField(speed, new GUIContent("Wind Speed", "Speed factor for the simulated wind effect over the fog."));
            if (GUILayout.Button("Stop", GUILayout.Width(60)))
            {
                speed.floatValue = 0;
            }
            EditorGUILayout.EndHorizontal();
            EditorGUILayout.PropertyField(windDirection, new GUIContent("Wind Direction", "Normalized direcional vector for the wind effect."));
            EditorGUILayout.PropertyField(turbulenceStrength, new GUIContent("Turbulence", "Turbulence strength. Set to zero to deactivate. Turbulence adds a render pass to compute fog animation."));
            EditorGUILayout.PropertyField(useRealTime, new GUIContent("Use Real Time", "Uses real elapsed time since last fog rendering instead of Time.deltaTime (elapsed time since last frame) to ensure continuous fog animation irrespective of camera enable state. For example, if you disable the camera and 'Use Real Time' is enabled, when you enable the camera again, the fog animation wil compute the total elapsed time so it shows as if fog continues animating while camera was disabled.  If set to false, fog animation will use Time.deltaTime (elapsed time since last frame) which will cause fog to resume previous state."));
            EditorGUILayout.EndVertical();

            EditorGUILayout.Separator();

            EditorGUILayout.BeginVertical();
            DrawTitleLabel("Sky");
            if (useXYPlane.boolValue)
            {
                EditorGUILayout.HelpBox("Sky haze is disabled when using XY plane.", MessageType.Info);
            }
            EditorGUILayout.PropertyField(skyHaze, new GUIContent("Haze", "Height of the sky haze in meters. Reduce this or alpha to 0 to disable sky haze."));
            EditorGUILayout.PropertyField(skyColor, new GUIContent("Color", "Sky haze color."));
            EditorGUILayout.PropertyField(skySpeed, new GUIContent("Speed", "Speed of the haze animation."));
            EditorGUILayout.PropertyField(skyNoiseStrength, new GUIContent("Noise Strength", "Amount of noise for the sky haze."));
            EditorGUILayout.PropertyField(skyAlpha, new GUIContent("Alpha", "Transparency of the sky haze. Reduce this or Haze value to 0 to disable sky haze."));
            EditorGUILayout.EndVertical();

            EditorGUILayout.Separator();

            EditorGUILayout.BeginVertical();
            DrawTitleLabel("Light Scattering");
            EditorGUILayout.PropertyField(lightScatteringOverride, new GUIContent("Override", "Override current light scattering fog settings."));
            if (!lightScatteringOverride.boolValue)
            {
                GUI.enabled = false;
            }
            EditorGUILayout.PropertyField(lightScatteringEnabled, new GUIContent("Enable", "Enables screen space light scattering. Simulates scattering of Sun light through atmosphere."));
            if (lightScatteringEnabled.boolValue)
            {
                EditorGUILayout.PropertyField(lightScatteringDiffusion, new GUIContent("Diffusion", "Spread or intensity of Sun light scattering."));
                EditorGUILayout.PropertyField(lightScatteringExposure, new GUIContent("Shafts Intensity", "Intensity for the Sun shafts effect."));
                EditorGUILayout.PropertyField(lightScatteringSpread, new GUIContent("   Spread", "Length of the Sun rays. "));
                EditorGUILayout.PropertyField(lightScatteringWeight, new GUIContent("   Sample Weight", "Strength of Sun rays."));
                EditorGUILayout.PropertyField(lightScatteringIllumination, new GUIContent("   Start Illumination", "Initial strength of each ray."));
                EditorGUILayout.PropertyField(lightScatteringDecay, new GUIContent("   Decay", "Decay multiplier applied on each step."));
                EditorGUILayout.PropertyField(lightScatteringSamples, new GUIContent("   Samples", "Number of light samples used when Light Scattering is enabled. Reduce to increse performance."));
                EditorGUILayout.PropertyField(lightScatteringJittering, new GUIContent("   Jittering", "Smooths rays removing artifacts and allowing to use less samples."));
            }
            GUI.enabled = true;
            EditorGUILayout.EndVertical();

            EditorGUILayout.Separator();

            EditorGUILayout.BeginVertical();
            DrawTitleLabel("Fog Void");
            EditorGUILayout.PropertyField(fogVoidOverride, new GUIContent("Override", "Override current fog void settings."));
            if (!fogVoidOverride.boolValue)
            {
                GUI.enabled = false;
            }
            EditorGUILayout.PropertyField(fogVoidPosition, new GUIContent("Center", "Location of the center of the fog void in world space (area where the fog disappear).\nThis option is very useful if you want a clear area around your character in 3rd person view."));
            EditorGUILayout.PropertyField(fogVoidTopology, new GUIContent("Topology", "Shape of the void area."));
            if (fogVoidTopology.intValue == (int)FOG_VOID_TOPOLOGY.Sphere)
            {
                EditorGUILayout.PropertyField(fogVoidRadius, new GUIContent("Radius", "Radius of the void area."));
            }
            else if (fogVoidTopology.intValue == (int)FOG_VOID_TOPOLOGY.Box)
            {
                EditorGUILayout.PropertyField(fogVoidRadius, new GUIContent("Width", "Width of the void area."));
                EditorGUILayout.PropertyField(fogVoidHeight, new GUIContent("Height", "Height of the void area."));
                EditorGUILayout.PropertyField(fogVoidDepth, new GUIContent("Depth", "Depth of the void area."));
            }
            EditorGUILayout.PropertyField(fogVoidFallOff, new GUIContent("FallOff", "Gradient of the void area effect."));
            GUI.enabled = true;
            EditorGUILayout.EndVertical();

            EditorGUILayout.Separator();

            EditorGUILayout.BeginVertical();
            DrawTitleLabel("Rendering");
            EditorGUILayout.PropertyField(downsamplingOverride, new GUIContent("Downsampling Override", "Overrides downsampling settings."));
            if (!downsamplingOverride.boolValue)
            {
                GUI.enabled = false;
            }
            EditorGUILayout.PropertyField(downsampling, new GUIContent("   Downsampling", "Reduces the size of the depth texture to improve performance."));
            if (downsampling.intValue == 1)
            {
                EditorGUILayout.PropertyField(forceComposition, new GUIContent("   Force Composition", "Enables final composition with optional edge filter at no downscale to improve edges when MSAA is enabled."));
            }

            if (downsampling.intValue > 1 || forceComposition.boolValue)
            {
                EditorGUILayout.PropertyField(edgeImprove, new GUIContent("   Improve Edges", "Check this option to reduce artifacts and halos around geometry edges when downsampling is applied. This is an option because it's faster to not take care or geometry edges, which is probably unnecesary if you use fog as elevated clouds."));
                if (edgeImprove.boolValue)
                {
                    EditorGUILayout.PropertyField(edgeThreshold, new GUIContent("      Threshold", "Depth threshold used to detected edges."));
                }
            }
            GUI.enabled = true;

            EditorGUILayout.PropertyField(stepping, new GUIContent("Stepping", "Multiplier to the ray-marching algorithm. Values between 8-12 are good. Increasing the stepping will produce more accurate and better quality fog but performance will be reduced. The less the density of the fog the lower you can set this value."));
            EditorGUILayout.PropertyField(steppingNear, new GUIContent("Stepping Near", "Works with Stepping parameter but applies only to short distances from camera. Lowering this value can help to reduce banding effect (performance can be reduced as well)."));
            EditorGUILayout.PropertyField(dithering, new GUIContent("Dithering", "Blends final fog color with a pattern to reduce banding artifacts. Use the slider to choose the intensity of dither."));
            if (dithering.boolValue)
            {
                EditorGUILayout.PropertyField(ditherStrength, new GUIContent("   Strength", "Dither strength."));
            }
            EditorGUILayout.EndVertical();
            EditorGUILayout.Separator();

            if (serializedObject.ApplyModifiedProperties() || (Event.current.type == EventType.ExecuteCommand &&
                                                               Event.current.commandName == "UndoRedoPerformed"))
            {
                // Triggers profile reload on all Volumetric Fog scripts
                VolumetricFog[] fogs = FindObjectsOfType <VolumetricFog>();
                for (int t = 0; t < targets.Length; t++)
                {
                    VolumetricFogProfile profile = (VolumetricFogProfile)targets[t];
                    for (int k = 0; k < fogs.Length; k++)
                    {
                        if (fogs[k] != null && fogs[k].profile == profile)
                        {
                            profile.Load(fogs[k]);
                        }
                    }
                }
                EditorUtility.SetDirty(target);
            }
        }
        /// <summary>
        /// Lerps between profile1 and profile2 using t as the transition amount (0..1) and assign the values to given fog
        /// </summary>
        public static void Lerp(VolumetricFogProfile profile1, VolumetricFogProfile profile2, float t, VolumetricFog fog)
        {
            if (t < 0)
            {
                t = 0;
            }
            else if (t > 1f)
            {
                t = 1f;
            }

            // Fog Geo
            fog.density                       = profile1.density * (1f - t) + profile2.density * t;
            fog.noiseStrength                 = profile1.noiseStrength * (1f - t) + profile2.noiseStrength * t;
            fog.height                        = profile1.height * (1f - t) + profile2.height * t;
            fog.heightFallOff                 = profile1.heightFallOff * (1f - t) + profile2.heightFallOff * t;
            fog.baselineHeight                = profile1.baselineHeight * (1f - t) + profile2.baselineHeight * t;
            fog.distance                      = profile1.distance * (1f - t) + profile2.distance * t;
            fog.distanceFallOff               = profile1.distanceFallOff * (1f - t) + profile2.distanceFallOff * t;
            fog.maxFogLength                  = profile1.maxFogLength * (1f - t) + profile2.maxFogLength * t;
            fog.maxFogLengthFallOff           = profile1.maxFogLengthFallOff * (1f - t) + profile2.maxFogLengthFallOff * t;
            fog.baselineRelativeToCamera      = t < 0.5f ? profile1.baselineRelativeToCamera : profile2.baselineRelativeToCamera;
            fog.baselineRelativeToCameraDelay = profile1.baselineRelativeToCameraDelay * (1f - t) + profile2.baselineRelativeToCameraDelay * t;
            fog.noiseScale                    = profile1.noiseScale * (1f - t) + profile2.noiseScale * t;
            fog.noiseSparse                   = profile1.noiseSparse * (1f - t) + profile2.noiseSparse * t;
            fog.noiseFinalMultiplier          = profile1.noiseFinalMultiplier * (1f - t) + profile2.noiseFinalMultiplier * t;

            // Fog Colors
            fog.sunCopyColor      = t < 0.5f ? profile1.sunCopyColor : profile2.sunCopyColor;
            fog.alpha             = profile1.alpha * (1f - t) + profile2.alpha * t;
            fog.color             = profile1.color * (1f - t) + profile2.color * t;
            fog.deepObscurance    = profile1.deepObscurance * (1f - t) + profile2.deepObscurance * t;
            fog.specularColor     = profile1.specularColor * (1f - t) + profile2.specularColor * t;
            fog.specularThreshold = profile1.specularThreshold * (1f - t) + profile2.specularThreshold * t;
            fog.specularIntensity = profile1.specularIntensity * (1f - t) + profile2.specularIntensity * t;
            fog.lightDirection    = profile1.lightDirection * (1f - t) + profile2.lightDirection * t;
            fog.lightIntensity    = profile1.lightIntensity * (1f - t) + profile2.lightIntensity * t;
            fog.lightColor        = profile1.lightColor * (1f - t) + profile2.lightColor * t;

            // Fog animation
            fog.speed              = profile1.speed * (1f - t) + profile2.speed * t;
            fog.windDirection      = profile1.windDirection * (1f - t) + profile2.windDirection * t;
            fog.turbulenceStrength = profile1.turbulenceStrength * (1f - t) + profile2.turbulenceStrength * t;

            // Fog sky
            fog.skyColor         = profile1.skyColor * (1f - t) + profile2.skyColor * t;
            fog.skyHaze          = profile1.skyHaze * (1f - t) + profile2.skyHaze * t;
            fog.skySpeed         = profile1.skySpeed * (1f - t) + profile2.skySpeed * t;
            fog.skyNoiseStrength = profile1.skyNoiseStrength * (1f - t) + profile2.skyNoiseStrength * t;
            fog.skyNoiseScale    = profile1.skyNoiseScale * (1f - t) + profile2.skyNoiseScale * t;
            fog.skyAlpha         = profile1.skyAlpha * (1f - t) + profile2.skyAlpha * t;
            fog.skyDepth         = profile1.skyDepth * (1f - t) + profile2.skyDepth * t;

            // Optimization
            fog.stepping       = profile1.stepping * (1f - t) + profile2.stepping * t;
            fog.steppingNear   = profile1.steppingNear * (1f - t) + profile2.steppingNear * t;
            fog.dithering      = t < 0.5f ? profile1.dithering : profile2.dithering;
            fog.ditherStrength = profile1.ditherStrength * (1f - t) + profile2.ditherStrength * t;

            // Fog Void
            if (profile1.fogVoidOverride && profile2.fogVoidOverride)
            {
                fog.fogVoidDepth    = profile1.fogVoidDepth * (1f - t) + profile2.fogVoidDepth * t;
                fog.fogVoidFallOff  = profile1.fogVoidFallOff * (1f - t) + profile2.fogVoidFallOff * t;
                fog.fogVoidHeight   = profile1.fogVoidHeight * (1f - t) + profile2.fogVoidHeight * t;
                fog.fogVoidPosition = profile1.fogVoidPosition * (1f - t) + profile2.fogVoidPosition * t;
                fog.fogVoidRadius   = profile1.fogVoidRadius * (1f - t) + profile2.fogVoidRadius * t;
            }

            // Light Scattering
            if (profile1.lightScatteringOverride && profile2.lightScatteringOverride)
            {
                fog.lightScatteringDecay        = profile1.lightScatteringDecay * (1f - t) + profile2.lightScatteringDecay * t;
                fog.lightScatteringDiffusion    = profile1.lightScatteringDiffusion * (1f - t) + profile2.lightScatteringDiffusion * t;
                fog.lightScatteringExposure     = profile1.lightScatteringExposure * (1f - t) + profile2.lightScatteringExposure * t;
                fog.lightScatteringIllumination = profile1.lightScatteringIllumination * (1f - t) + profile2.lightScatteringIllumination * t;
                fog.lightScatteringJittering    = profile1.lightScatteringJittering * (1f - t) + profile2.lightScatteringJittering * t;
                fog.lightScatteringSamples      = (int)(profile1.lightScatteringSamples * (1f - t) + profile2.lightScatteringSamples * t);
                fog.lightScatteringSpread       = profile1.lightScatteringSpread * (1f - t) + profile2.lightScatteringSpread * t;
                fog.lightScatteringWeight       = profile1.lightScatteringWeight * (1f - t) + profile2.lightScatteringWeight * t;
            }
        }