From 953cbb6e405f3db4df937e8546d71af6ef190d0c Mon Sep 17 00:00:00 2001 From: Muzz Date: Tue, 25 Feb 2025 14:02:15 +1000 Subject: [PATCH 1/2] Advanced Bloom commit. --- .../Engine/Graphics/PostProcessSettings.cpp | 7 +- Source/Engine/Graphics/PostProcessSettings.h | 346 ++++++++++-------- Source/Engine/Renderer/PostProcessingPass.cpp | 213 ++++++----- Source/Engine/Renderer/PostProcessingPass.h | 27 +- Source/Shaders/PostProcessing.shader | 279 ++++++++++++-- 5 files changed, 567 insertions(+), 305 deletions(-) diff --git a/Source/Engine/Graphics/PostProcessSettings.cpp b/Source/Engine/Graphics/PostProcessSettings.cpp index 738cc4505..e717559f0 100644 --- a/Source/Engine/Graphics/PostProcessSettings.cpp +++ b/Source/Engine/Graphics/PostProcessSettings.cpp @@ -42,10 +42,13 @@ void BloomSettings::BlendWith(BloomSettings& other, float weight) BLEND_BOOL(Enabled); BLEND_FLOAT(Intensity); BLEND_FLOAT(Threshold); - BLEND_FLOAT(BlurSigma); - BLEND_FLOAT(Limit); + BLEND_FLOAT(ThresholdKnee); + BLEND_FLOAT(Clamp); + BLEND_FLOAT(BaseMix); + BLEND_FLOAT(HighMix); } + void ToneMappingSettings::BlendWith(ToneMappingSettings& other, float weight) { const bool isHalf = weight >= 0.5f; diff --git a/Source/Engine/Graphics/PostProcessSettings.h b/Source/Engine/Graphics/PostProcessSettings.h index dc3895954..f2297f240 100644 --- a/Source/Engine/Graphics/PostProcessSettings.h +++ b/Source/Engine/Graphics/PostProcessSettings.h @@ -236,43 +236,43 @@ API_STRUCT() struct FLAXENGINE_API AmbientOcclusionSettings : ISerializable /// The flags for overriden properties. /// API_FIELD(Attributes="HideInEditor") - AmbientOcclusionSettingsOverride OverrideFlags = Override::None; + AmbientOcclusionSettingsOverride OverrideFlags = Override::None; /// /// Enable/disable ambient occlusion effect. /// API_FIELD(Attributes="EditorOrder(0), PostProcessSetting((int)AmbientOcclusionSettingsOverride.Enabled)") - bool Enabled = true; + bool Enabled = true; /// /// Ambient occlusion intensity. /// API_FIELD(Attributes="Limit(0, 10.0f, 0.01f), EditorOrder(1), PostProcessSetting((int)AmbientOcclusionSettingsOverride.Intensity)") - float Intensity = 0.8f; + float Intensity = 0.8f; /// /// Ambient occlusion power. /// API_FIELD(Attributes="Limit(0, 10.0f, 0.01f), EditorOrder(2), PostProcessSetting((int)AmbientOcclusionSettingsOverride.Power)") - float Power = 0.75f; + float Power = 0.75f; /// /// Ambient occlusion check range radius. /// API_FIELD(Attributes="Limit(0, 100.0f, 0.01f), EditorOrder(3), PostProcessSetting((int)AmbientOcclusionSettingsOverride.Radius)") - float Radius = 0.7f; + float Radius = 0.7f; /// /// Ambient occlusion fade out end distance from camera (in world units). /// API_FIELD(Attributes="Limit(0.0f), EditorOrder(4), PostProcessSetting((int)AmbientOcclusionSettingsOverride.FadeOutDistance)") - float FadeOutDistance = 5000.0f; + float FadeOutDistance = 5000.0f; /// /// Ambient occlusion fade distance (in world units). Defines the size of the effect fade from fully visible to fully invisible at FadeOutDistance. /// API_FIELD(Attributes="Limit(0.0f), EditorOrder(5), PostProcessSetting((int)AmbientOcclusionSettingsOverride.FadeDistance)") - float FadeDistance = 500.0f; + float FadeDistance = 500.0f; public: /// @@ -342,43 +342,43 @@ API_STRUCT() struct FLAXENGINE_API GlobalIlluminationSettings : ISerializable /// The flags for overriden properties. /// API_FIELD(Attributes="HideInEditor") - GlobalIlluminationSettingsOverride OverrideFlags = Override::None; + GlobalIlluminationSettingsOverride OverrideFlags = Override::None; /// /// The Global Illumination mode to use. /// API_FIELD(Attributes="EditorOrder(0), PostProcessSetting((int)GlobalIlluminationSettingsOverride.Mode)") - GlobalIlluminationMode Mode = GlobalIlluminationMode::None; + GlobalIlluminationMode Mode = GlobalIlluminationMode::None; /// /// Global Illumination indirect lighting intensity scale. Can be used to boost or reduce GI effect. /// API_FIELD(Attributes="EditorOrder(10), Limit(0, 10, 0.01f), PostProcessSetting((int)GlobalIlluminationSettingsOverride.Intensity)") - float Intensity = 1.0f; + float Intensity = 1.0f; /// /// Global Illumination infinite indirect lighting bounce intensity scale. Can be used to boost or reduce GI effect for the light bouncing on the surfaces. /// API_FIELD(Attributes="EditorOrder(11), Limit(0, 10, 0.01f), PostProcessSetting((int)GlobalIlluminationSettingsOverride.BounceIntensity)") - float BounceIntensity = 1.0f; + float BounceIntensity = 1.0f; /// /// Defines how quickly GI blends between the current frame and the history buffer. Lower values update GI faster, but with more jittering and noise. If the camera in your game doesn't move much, we recommend values closer to 1. /// API_FIELD(Attributes="EditorOrder(20), Limit(0, 1), PostProcessSetting((int)GlobalIlluminationSettingsOverride.TemporalResponse)") - float TemporalResponse = 0.9f; + float TemporalResponse = 0.9f; /// /// Draw distance of the Global Illumination effect. Scene outside the range will use fallback irradiance. /// API_FIELD(Attributes="EditorOrder(30), Limit(1000), PostProcessSetting((int)GlobalIlluminationSettingsOverride.Distance)") - float Distance = 20000.0f; + float Distance = 20000.0f; /// /// The irradiance lighting outside the GI range used as a fallback to prevent pure-black scene outside the Global Illumination range. /// API_FIELD(Attributes="EditorOrder(40), PostProcessSetting((int)GlobalIlluminationSettingsOverride.FallbackIrradiance)") - Color FallbackIrradiance = Color::Black; + Color FallbackIrradiance = Color::Black; public: /// @@ -415,19 +415,29 @@ API_ENUM(Attributes="Flags") enum class BloomSettingsOverride : int32 Threshold = 1 << 2, /// - /// Overrides property. + /// Overrides property. /// - BlurSigma = 1 << 3, + ThresholdKnee = 1 << 3, /// - /// Overrides property. + /// Overrides property. /// - Limit = 1 << 4, + Clamp = 1 << 4, + + /// + /// Overrides property. + /// + BaseMix = 1 << 5, + + /// + /// Overrides property. + /// + HighMix = 1 << 6, /// /// All properties. /// - All = Enabled | Intensity | Threshold | BlurSigma | Limit, + All = Enabled | Intensity | Threshold | ThresholdKnee | Clamp | BaseMix | HighMix, }; /// @@ -443,37 +453,49 @@ API_STRUCT() struct FLAXENGINE_API BloomSettings : ISerializable /// The flags for overriden properties. /// API_FIELD(Attributes="HideInEditor") - BloomSettingsOverride OverrideFlags = Override::None; + BloomSettingsOverride OverrideFlags = Override::None; /// /// If checked, bloom effect will be rendered. /// API_FIELD(Attributes="EditorOrder(0), PostProcessSetting((int)BloomSettingsOverride.Enabled)") - bool Enabled = true; + bool Enabled = true; /// - /// Bloom effect strength. Set a value of 0 to disabled it, while higher values increase the effect. + /// Overall bloom effect strength. Higher values create a stronger glow effect. /// - API_FIELD(Attributes="Limit(0, 20.0f, 0.01f), EditorOrder(1), PostProcessSetting((int)BloomSettingsOverride.Intensity)") - float Intensity = 1.0f; + API_FIELD(Attributes "Limit(0, 100.0f, 0.001f), EditorOrder(1), PostProcessSetting((int)BloomSettingsOverride.Intensity)") + float Intensity = 1.0f; /// - /// Minimum pixel brightness value to start blooming. Values below this threshold are skipped. + /// Luminance threshold where bloom begins. /// - API_FIELD(Attributes="Limit(0, 15.0f, 0.01f), EditorOrder(2), PostProcessSetting((int)BloomSettingsOverride.Threshold)") - float Threshold = 3.0f; + API_FIELD(Attributes="Limit(0, 100.0f, 0.1f), EditorOrder(2), PostProcessSetting((int)BloomSettingsOverride.Threshold)") + float Threshold = 1.0f; /// - /// This affects the fall-off of the bloom. It's the standard deviation (sigma) used in the Gaussian blur formula when calculating the kernel of the bloom. + /// Controls the threshold rolloff curve. Higher values create a softer transition. /// - API_FIELD(Attributes="Limit(0, 20.0f, 0.01f), EditorOrder(3), PostProcessSetting((int)BloomSettingsOverride.BlurSigma)") - float BlurSigma = 4.0f; + API_FIELD(Attributes="Limit(0, 100.0f, 0.01f), EditorOrder(3), PostProcessSetting((int)BloomSettingsOverride.ThresholdKnee)") + float ThresholdKnee = 0.5f; /// - /// Bloom effect brightness limit. Pixels with higher luminance will be capped to this brightness level. + /// Maximum brightness limit for bloom highlights. /// - API_FIELD(Attributes="Limit(0, 100.0f, 0.01f), EditorOrder(4), PostProcessSetting((int)BloomSettingsOverride.Limit)") - float Limit = 10.0f; + API_FIELD(Attributes="Limit(0, 100.0f, 0.1f), EditorOrder(4), PostProcessSetting((int)BloomSettingsOverride.Clamp)") + float Clamp = 3.0f; + + /// + /// Base mip contribution for wider, softer bloom. + /// + API_FIELD(Attributes="Limit(0, 1.0f, 0.01f), EditorOrder(5), PostProcessSetting((int)BloomSettingsOverride.BaseMix)") + float BaseMix = 0.6f; + + /// + /// High mip contribution for tighter, core bloom. + /// + API_FIELD(Attributes="Limit(0, 1.0f, 0.01f), EditorOrder(6), PostProcessSetting((int)BloomSettingsOverride.HighMix)") + float HighMix = 1.0f; public: /// @@ -487,7 +509,7 @@ public: /// /// The structure members override flags. /// -API_ENUM(Attributes="Flags") enum class ToneMappingSettingsOverride : int32 +API_ENUM(Attributes ="Flags") enum class ToneMappingSettingsOverride : int32 { /// /// None properties. @@ -528,25 +550,25 @@ API_STRUCT() struct FLAXENGINE_API ToneMappingSettings : ISerializable /// The flags for overriden properties. /// API_FIELD(Attributes="HideInEditor") - ToneMappingSettingsOverride OverrideFlags = Override::None; + ToneMappingSettingsOverride OverrideFlags = Override::None; /// /// Adjusts the white balance in relation to the temperature of the light in the scene. When the light temperature and this one match the light will appear white. When a value is used that is higher than the light in the scene it will yield a "warm" or yellow color, and, conversely, if the value is lower, it would yield a "cool" or blue color. /// API_FIELD(Attributes="Limit(1500, 15000), EditorOrder(0), PostProcessSetting((int)ToneMappingSettingsOverride.WhiteTemperature)") - float WhiteTemperature = 6500.0f; + float WhiteTemperature = 6500.0f; /// /// Adjusts the white balance temperature tint for the scene by adjusting the cyan and magenta color ranges. Ideally, this setting should be used once you've adjusted the white balance temperature to get accurate colors. Under some light temperatures, the colors may appear to be more yellow or blue. This can be used to balance the resulting color to look more natural. /// API_FIELD(Attributes="Limit(-1, 1, 0.001f), EditorOrder(1), PostProcessSetting((int)ToneMappingSettingsOverride.WhiteTint)") - float WhiteTint = 0.0f; + float WhiteTint = 0.0f; /// /// The tone mapping mode to use for the color grading process. /// API_FIELD(Attributes="EditorOrder(2), PostProcessSetting((int)ToneMappingSettingsOverride.Mode)") - ToneMappingMode Mode = ToneMappingMode::ACES; + ToneMappingMode Mode = ToneMappingMode::ACES; public: /// @@ -706,7 +728,7 @@ API_STRUCT() struct FLAXENGINE_API ColorGradingSettings : ISerializable /// The flags for overriden properties. /// API_FIELD(Attributes="HideInEditor") - ColorGradingSettingsOverride OverrideFlags = Override::None; + ColorGradingSettingsOverride OverrideFlags = Override::None; // Global @@ -714,31 +736,31 @@ API_STRUCT() struct FLAXENGINE_API ColorGradingSettings : ISerializable /// Gets or sets the color saturation (applies globally to the whole image). Default is 1. /// API_FIELD(Attributes="DefaultValue(typeof(Float4), \"1,1,1,1\"), CustomEditorAlias(\"FlaxEditor.CustomEditors.Editors.ColorTrackball\"), EditorOrder(0), PostProcessSetting((int)ColorGradingSettingsOverride.ColorSaturation), Limit(0, 2, 0.01f), EditorDisplay(\"Global\", \"Saturation\")") - Float4 ColorSaturation = Float4::One; + Float4 ColorSaturation = Float4::One; /// /// Gets or sets the color contrast (applies globally to the whole image). Default is 1. /// API_FIELD(Attributes="DefaultValue(typeof(Float4), \"1,1,1,1\"), CustomEditorAlias(\"FlaxEditor.CustomEditors.Editors.ColorTrackball\"), EditorOrder(1), PostProcessSetting((int)ColorGradingSettingsOverride.ColorContrast), Limit(0, 2, 0.01f), EditorDisplay(\"Global\", \"Contrast\")") - Float4 ColorContrast = Float4::One; + Float4 ColorContrast = Float4::One; /// /// Gets or sets the color gamma (applies globally to the whole image). Default is 1. /// API_FIELD(Attributes="DefaultValue(typeof(Float4), \"1,1,1,1\"), CustomEditorAlias(\"FlaxEditor.CustomEditors.Editors.ColorTrackball\"), EditorOrder(2), PostProcessSetting((int)ColorGradingSettingsOverride.ColorGamma), Limit(0, 2, 0.01f), EditorDisplay(\"Global\", \"Gamma\")") - Float4 ColorGamma = Float4::One; + Float4 ColorGamma = Float4::One; /// /// Gets or sets the color gain (applies globally to the whole image). Default is 1. /// API_FIELD(Attributes="DefaultValue(typeof(Float4), \"1,1,1,1\"), CustomEditorAlias(\"FlaxEditor.CustomEditors.Editors.ColorTrackball\"), EditorOrder(3), PostProcessSetting((int)ColorGradingSettingsOverride.ColorGain), Limit(0, 2, 0.01f), EditorDisplay(\"Global\", \"Gain\")") - Float4 ColorGain = Float4::One; + Float4 ColorGain = Float4::One; /// /// Gets or sets the color offset (applies globally to the whole image). Default is 0. /// API_FIELD(Attributes="DefaultValue(typeof(Float4), \"0,0,0,0\"), CustomEditorAlias(\"FlaxEditor.CustomEditors.Editors.ColorTrackball\"), EditorOrder(4), PostProcessSetting((int)ColorGradingSettingsOverride.ColorOffset), Limit(-1, 1, 0.001f), EditorDisplay(\"Global\", \"Offset\")") - Float4 ColorOffset = Float4::Zero; + Float4 ColorOffset = Float4::Zero; // Shadows @@ -746,31 +768,31 @@ API_STRUCT() struct FLAXENGINE_API ColorGradingSettings : ISerializable /// Gets or sets the color saturation (applies to shadows only). Default is 1. /// API_FIELD(Attributes="DefaultValue(typeof(Float4), \"1,1,1,1\"), CustomEditorAlias(\"FlaxEditor.CustomEditors.Editors.ColorTrackball\"), EditorOrder(5), PostProcessSetting((int)ColorGradingSettingsOverride.ColorSaturationShadows), Limit(0, 2, 0.01f), EditorDisplay(\"Shadows\", \"Shadows Saturation\")") - Float4 ColorSaturationShadows = Float4::One; + Float4 ColorSaturationShadows = Float4::One; /// /// Gets or sets the color contrast (applies to shadows only). Default is 1. /// API_FIELD(Attributes="DefaultValue(typeof(Float4), \"1,1,1,1\"), CustomEditorAlias(\"FlaxEditor.CustomEditors.Editors.ColorTrackball\"), EditorOrder(6), PostProcessSetting((int)ColorGradingSettingsOverride.ColorContrastShadows), Limit(0, 2, 0.01f), EditorDisplay(\"Shadows\", \"Shadows Contrast\")") - Float4 ColorContrastShadows = Float4::One; + Float4 ColorContrastShadows = Float4::One; /// /// Gets or sets the color gamma (applies to shadows only). Default is 1. /// API_FIELD(Attributes="DefaultValue(typeof(Float4), \"1,1,1,1\"), CustomEditorAlias(\"FlaxEditor.CustomEditors.Editors.ColorTrackball\"), EditorOrder(7), PostProcessSetting((int)ColorGradingSettingsOverride.ColorGammaShadows), Limit(0, 2, 0.01f), EditorDisplay(\"Shadows\", \"Shadows Gamma\")") - Float4 ColorGammaShadows = Float4::One; + Float4 ColorGammaShadows = Float4::One; /// /// Gets or sets the color gain (applies to shadows only). Default is 1. /// API_FIELD(Attributes="DefaultValue(typeof(Float4), \"1,1,1,1\"), CustomEditorAlias(\"FlaxEditor.CustomEditors.Editors.ColorTrackball\"), EditorOrder(8), PostProcessSetting((int)ColorGradingSettingsOverride.ColorGainShadows), Limit(0, 2, 0.01f), EditorDisplay(\"Shadows\", \"Shadows Gain\")") - Float4 ColorGainShadows = Float4::One; + Float4 ColorGainShadows = Float4::One; /// /// Gets or sets the color offset (applies to shadows only). Default is 0. /// API_FIELD(Attributes="DefaultValue(typeof(Float4), \"0,0,0,0\"), CustomEditorAlias(\"FlaxEditor.CustomEditors.Editors.ColorTrackball\"), EditorOrder(9), PostProcessSetting((int)ColorGradingSettingsOverride.ColorOffsetShadows), Limit(-1, 1, 0.001f), EditorDisplay(\"Shadows\", \"Shadows Offset\")") - Float4 ColorOffsetShadows = Float4::Zero; + Float4 ColorOffsetShadows = Float4::Zero; // Midtones @@ -778,31 +800,31 @@ API_STRUCT() struct FLAXENGINE_API ColorGradingSettings : ISerializable /// Gets or sets the color saturation (applies to midtones only). Default is 1. /// API_FIELD(Attributes="DefaultValue(typeof(Float4), \"1,1,1,1\"), CustomEditorAlias(\"FlaxEditor.CustomEditors.Editors.ColorTrackball\"), EditorOrder(10), PostProcessSetting((int)ColorGradingSettingsOverride.ColorSaturationMidtones), Limit(0, 2, 0.01f), EditorDisplay(\"Midtones\", \"Midtones Saturation\")") - Float4 ColorSaturationMidtones = Float4::One; + Float4 ColorSaturationMidtones = Float4::One; /// /// Gets or sets the color contrast (applies to midtones only). Default is 1. /// API_FIELD(Attributes="DefaultValue(typeof(Float4), \"1,1,1,1\"), CustomEditorAlias(\"FlaxEditor.CustomEditors.Editors.ColorTrackball\"), EditorOrder(11), PostProcessSetting((int)ColorGradingSettingsOverride.ColorContrastMidtones), Limit(0, 2, 0.01f), EditorDisplay(\"Midtones\", \"Midtones Contrast\")") - Float4 ColorContrastMidtones = Float4::One; + Float4 ColorContrastMidtones = Float4::One; /// /// Gets or sets the color gamma (applies to midtones only). Default is 1. /// API_FIELD(Attributes="DefaultValue(typeof(Float4), \"1,1,1,1\"), CustomEditorAlias(\"FlaxEditor.CustomEditors.Editors.ColorTrackball\"), EditorOrder(12), PostProcessSetting((int)ColorGradingSettingsOverride.ColorGammaMidtones), Limit(0, 2, 0.01f), EditorDisplay(\"Midtones\", \"Midtones Gamma\")") - Float4 ColorGammaMidtones = Float4::One; + Float4 ColorGammaMidtones = Float4::One; /// /// Gets or sets the color gain (applies to midtones only). Default is 1. /// API_FIELD(Attributes="DefaultValue(typeof(Float4), \"1,1,1,1\"), CustomEditorAlias(\"FlaxEditor.CustomEditors.Editors.ColorTrackball\"), EditorOrder(13), PostProcessSetting((int)ColorGradingSettingsOverride.ColorGainMidtones), Limit(0, 2, 0.01f), EditorDisplay(\"Midtones\", \"Midtones Gain\")") - Float4 ColorGainMidtones = Float4::One; + Float4 ColorGainMidtones = Float4::One; /// /// Gets or sets the color offset (applies to midtones only). Default is 0. /// API_FIELD(Attributes="DefaultValue(typeof(Float4), \"0,0,0,0\"), CustomEditorAlias(\"FlaxEditor.CustomEditors.Editors.ColorTrackball\"), EditorOrder(14), PostProcessSetting((int)ColorGradingSettingsOverride.ColorOffsetMidtones), Limit(-1, 1, 0.001f), EditorDisplay(\"Midtones\", \"Midtones Offset\")") - Float4 ColorOffsetMidtones = Float4::Zero; + Float4 ColorOffsetMidtones = Float4::Zero; // Highlights @@ -810,31 +832,31 @@ API_STRUCT() struct FLAXENGINE_API ColorGradingSettings : ISerializable /// Gets or sets the color saturation (applies to highlights only). Default is 1. /// API_FIELD(Attributes="DefaultValue(typeof(Float4), \"1,1,1,1\"), CustomEditorAlias(\"FlaxEditor.CustomEditors.Editors.ColorTrackball\"), EditorOrder(15), PostProcessSetting((int)ColorGradingSettingsOverride.ColorSaturationHighlights), Limit(0, 2, 0.01f), EditorDisplay(\"Highlights\", \"Highlights Saturation\")") - Float4 ColorSaturationHighlights = Float4::One; + Float4 ColorSaturationHighlights = Float4::One; /// /// Gets or sets the color contrast (applies to highlights only). Default is 1. /// API_FIELD(Attributes="DefaultValue(typeof(Float4), \"1,1,1,1\"), CustomEditorAlias(\"FlaxEditor.CustomEditors.Editors.ColorTrackball\"), EditorOrder(16), PostProcessSetting((int)ColorGradingSettingsOverride.ColorContrastHighlights), Limit(0, 2, 0.01f), EditorDisplay(\"Highlights\", \"Highlights Contrast\")") - Float4 ColorContrastHighlights = Float4::One; + Float4 ColorContrastHighlights = Float4::One; /// /// Gets or sets the color gamma (applies to highlights only). Default is 1. /// API_FIELD(Attributes="DefaultValue(typeof(Float4), \"1,1,1,1\"), CustomEditorAlias(\"FlaxEditor.CustomEditors.Editors.ColorTrackball\"), EditorOrder(17), PostProcessSetting((int)ColorGradingSettingsOverride.ColorGammaHighlights), Limit(0, 2, 0.01f), EditorDisplay(\"Highlights\", \"Highlights Gamma\")") - Float4 ColorGammaHighlights = Float4::One; + Float4 ColorGammaHighlights = Float4::One; /// /// Gets or sets the color gain (applies to highlights only). Default is 1. /// API_FIELD(Attributes="DefaultValue(typeof(Float4), \"1,1,1,1\"), CustomEditorAlias(\"FlaxEditor.CustomEditors.Editors.ColorTrackball\"), EditorOrder(18), PostProcessSetting((int)ColorGradingSettingsOverride.ColorGainHighlights), Limit(0, 2, 0.01f), EditorDisplay(\"Highlights\", \"Highlights Gain\")") - Float4 ColorGainHighlights = Float4::One; + Float4 ColorGainHighlights = Float4::One; /// /// Gets or sets the color offset (applies to highlights only). Default is 0. /// API_FIELD(Attributes="DefaultValue(typeof(Float4), \"0,0,0,0\"), CustomEditorAlias(\"FlaxEditor.CustomEditors.Editors.ColorTrackball\"), EditorOrder(19), PostProcessSetting((int)ColorGradingSettingsOverride.ColorOffsetHighlights), Limit(-1, 1, 0.001f), EditorDisplay(\"Highlights\", \"Highlights Offset\")") - Float4 ColorOffsetHighlights = Float4::Zero; + Float4 ColorOffsetHighlights = Float4::Zero; // @@ -842,13 +864,13 @@ API_STRUCT() struct FLAXENGINE_API ColorGradingSettings : ISerializable /// The shadows maximum value. Default is 0.09. /// API_FIELD(Attributes="Limit(-1, 1, 0.01f), EditorOrder(20), PostProcessSetting((int)ColorGradingSettingsOverride.ShadowsMax)") - float ShadowsMax = 0.09f; + float ShadowsMax = 0.09f; /// /// The highlights minimum value. Default is 0.5. /// API_FIELD(Attributes="Limit(-1, 1, 0.01f), EditorOrder(21), PostProcessSetting((int)ColorGradingSettingsOverride.HighlightsMin)") - float HighlightsMin = 0.5f; + float HighlightsMin = 0.5f; // @@ -856,13 +878,13 @@ API_STRUCT() struct FLAXENGINE_API ColorGradingSettings : ISerializable /// The Lookup Table (LUT) used to perform color correction. /// API_FIELD(Attributes="DefaultValue(null), EditorOrder(22), PostProcessSetting((int)ColorGradingSettingsOverride.LutTexture)") - SoftAssetReference LutTexture; + SoftAssetReference LutTexture; /// /// The LUT blending weight (normalized to range 0-1). Default is 1.0. /// API_FIELD(Attributes="Limit(0, 1, 0.01f), EditorOrder(23), PostProcessSetting((int)ColorGradingSettingsOverride.LutWeight)") - float LutWeight = 1.0f; + float LutWeight = 1.0f; public: /// @@ -947,61 +969,61 @@ API_STRUCT() struct FLAXENGINE_API EyeAdaptationSettings : ISerializable /// The flags for overriden properties. /// API_FIELD(Attributes="HideInEditor") - EyeAdaptationSettingsOverride OverrideFlags = Override::None; + EyeAdaptationSettingsOverride OverrideFlags = Override::None; /// /// The effect rendering mode used for the exposure processing. /// API_FIELD(Attributes="EditorOrder(0), PostProcessSetting((int)EyeAdaptationSettingsOverride.Mode)") - EyeAdaptationMode Mode = EyeAdaptationMode::AutomaticHistogram; + EyeAdaptationMode Mode = EyeAdaptationMode::AutomaticHistogram; /// /// The speed at which the exposure changes when the scene brightness moves from a dark area to a bright area (brightness goes up). /// API_FIELD(Attributes="Limit(0, 100.0f, 0.01f), EditorOrder(1), PostProcessSetting((int)EyeAdaptationSettingsOverride.SpeedUp)") - float SpeedUp = 3.0f; + float SpeedUp = 3.0f; /// /// The speed at which the exposure changes when the scene brightness moves from a bright area to a dark area (brightness goes down). /// API_FIELD(Attributes="Limit(0, 100.0f, 0.01f), EditorOrder(2), PostProcessSetting((int)EyeAdaptationSettingsOverride.SpeedDown)") - float SpeedDown = 10.0f; + float SpeedDown = 10.0f; /// /// The pre-exposure value applied to the scene color before performing post-processing (such as bloom, lens flares, etc.). /// API_FIELD(Attributes="Limit(-100, 100, 0.01f), EditorOrder(3), PostProcessSetting((int)EyeAdaptationSettingsOverride.PreExposure)") - float PreExposure = 0.0f; + float PreExposure = 0.0f; /// /// The post-exposure value applied to the scene color after performing post-processing (such as bloom, lens flares, etc.) but before color grading and tone mapping. /// API_FIELD(Attributes="Limit(-100, 100, 0.01f), EditorOrder(3), PostProcessSetting((int)EyeAdaptationSettingsOverride.PostExposure)") - float PostExposure = 0.0f; + float PostExposure = 0.0f; /// /// The minimum brightness for the auto exposure which limits the lower brightness the eye can adapt within. /// API_FIELD(Attributes="Limit(0, 20.0f, 0.01f), EditorOrder(5), PostProcessSetting((int)EyeAdaptationSettingsOverride.MinBrightness), EditorDisplay(null, \"Minimum Brightness\")") - float MinBrightness = 0.03f; + float MinBrightness = 0.03f; /// /// The maximum brightness for the auto exposure which limits the upper brightness the eye can adapt within. /// API_FIELD(Attributes="Limit(0, 100.0f, 0.01f), EditorOrder(6), PostProcessSetting((int)EyeAdaptationSettingsOverride.MaxBrightness), EditorDisplay(null, \"Maximum Brightness\")") - float MaxBrightness = 15.0f; + float MaxBrightness = 15.0f; /// /// The lower bound for the luminance histogram of the scene color. This value is in percent and limits the pixels below this brightness. Use values in the range of 60-80. Used only in AutomaticHistogram mode. /// API_FIELD(Attributes="Limit(1, 99, 0.001f), EditorOrder(3), PostProcessSetting((int)EyeAdaptationSettingsOverride.HistogramLowPercent)") - float HistogramLowPercent = 70.0f; + float HistogramLowPercent = 70.0f; /// /// The upper bound for the luminance histogram of the scene color. This value is in percent and limits the pixels above this brightness. Use values in the range of 80-95. Used only in AutomaticHistogram mode. /// API_FIELD(Attributes="Limit(1, 99, 0.001f), EditorOrder(3), PostProcessSetting((int)EyeAdaptationSettingsOverride.HistogramHighPercent)") - float HistogramHighPercent = 90.0f; + float HistogramHighPercent = 90.0f; public: /// @@ -1081,55 +1103,55 @@ API_STRUCT() struct FLAXENGINE_API CameraArtifactsSettings : ISerializable /// The flags for overriden properties. /// API_FIELD(Attributes="HideInEditor") - CameraArtifactsSettingsOverride OverrideFlags = Override::None; + CameraArtifactsSettingsOverride OverrideFlags = Override::None; /// /// Strength of the vignette effect. Value 0 hides it. /// API_FIELD(Attributes="Limit(0, 2, 0.001f), EditorOrder(0), PostProcessSetting((int)CameraArtifactsSettingsOverride.VignetteIntensity)") - float VignetteIntensity = 0.4f; + float VignetteIntensity = 0.4f; /// /// Color of the vignette. /// API_FIELD(Attributes="EditorOrder(1), PostProcessSetting((int)CameraArtifactsSettingsOverride.VignetteColor)") - Float3 VignetteColor = Float3(0, 0, 0.001f); + Float3 VignetteColor = Float3(0, 0, 0.001f); /// /// Controls the shape of the vignette. Values near 0 produce a rectangular shape. Higher values result in a rounder shape. /// API_FIELD(Attributes="Limit(0.0001f, 2.0f, 0.001f), EditorOrder(2), PostProcessSetting((int)CameraArtifactsSettingsOverride.VignetteShapeFactor)") - float VignetteShapeFactor = 0.125f; + float VignetteShapeFactor = 0.125f; /// /// Intensity of the grain filter. A value of 0 hides it. /// API_FIELD(Attributes="Limit(0.0f, 2.0f, 0.005f), EditorOrder(3), PostProcessSetting((int)CameraArtifactsSettingsOverride.GrainAmount)") - float GrainAmount = 0.006f; + float GrainAmount = 0.006f; /// /// Size of the grain particles. /// API_FIELD(Attributes="Limit(1.0f, 3.0f, 0.01f), EditorOrder(4), PostProcessSetting((int)CameraArtifactsSettingsOverride.GrainParticleSize)") - float GrainParticleSize = 1.6f; + float GrainParticleSize = 1.6f; /// /// Speed of the grain particle animation. /// API_FIELD(Attributes="Limit(0.0f, 10.0f, 0.01f), EditorOrder(5), PostProcessSetting((int)CameraArtifactsSettingsOverride.GrainSpeed)") - float GrainSpeed = 1.0f; + float GrainSpeed = 1.0f; /// /// Controls the chromatic aberration effect strength. A value of 0 hides it. /// API_FIELD(Attributes="Limit(0.0f, 1.0f, 0.01f), EditorOrder(6), PostProcessSetting((int)CameraArtifactsSettingsOverride.ChromaticDistortion)") - float ChromaticDistortion = 0.0f; + float ChromaticDistortion = 0.0f; /// /// Screen tint color (the alpha channel defines the blending factor). /// API_FIELD(Attributes="DefaultValue(typeof(Color), \"0,0,0,0\"), EditorOrder(7), PostProcessSetting((int)CameraArtifactsSettingsOverride.ScreenFadeColor)") - Color ScreenFadeColor = Color::Transparent; + Color ScreenFadeColor = Color::Transparent; public: /// @@ -1229,79 +1251,79 @@ API_STRUCT() struct FLAXENGINE_API LensFlaresSettings : ISerializable /// The flags for overriden properties. /// API_FIELD(Attributes="HideInEditor") - LensFlaresSettingsOverride OverrideFlags = Override::None; + LensFlaresSettingsOverride OverrideFlags = Override::None; /// /// Strength of the effect. A value of 0 disables it. /// API_FIELD(Attributes="Limit(0, 10.0f, 0.01f), EditorOrder(0), PostProcessSetting((int)LensFlaresSettingsOverride.Intensity)") - float Intensity = 0.5f; + float Intensity = 0.5f; /// /// Amount of lens flares ghosts. /// API_FIELD(Attributes="Limit(0, 16), EditorOrder(1), PostProcessSetting((int)LensFlaresSettingsOverride.Ghosts)") - int32 Ghosts = 4; + int32 Ghosts = 4; /// /// Lens flares halo width. /// API_FIELD(Attributes="EditorOrder(2), PostProcessSetting((int)LensFlaresSettingsOverride.HaloWidth)") - float HaloWidth = 0.04f; + float HaloWidth = 0.04f; /// /// Lens flares halo intensity. /// API_FIELD(Attributes="Limit(0, 10.0f, 0.01f), EditorOrder(3), PostProcessSetting((int)LensFlaresSettingsOverride.HaloIntensity)") - float HaloIntensity = 0.5f; + float HaloIntensity = 0.5f; /// /// Ghost samples dispersal parameter. /// API_FIELD(Attributes="EditorOrder(4), PostProcessSetting((int)LensFlaresSettingsOverride.GhostDispersal)") - float GhostDispersal = 0.3f; + float GhostDispersal = 0.3f; /// /// Lens flares color distortion parameter. /// API_FIELD(Attributes="EditorOrder(5), PostProcessSetting((int)LensFlaresSettingsOverride.Distortion)") - float Distortion = 1.5f; + float Distortion = 1.5f; /// /// Input image brightness threshold. Added to input pixels. /// API_FIELD(Attributes="EditorOrder(6), PostProcessSetting((int)LensFlaresSettingsOverride.ThresholdBias)") - float ThresholdBias = -0.5f; + float ThresholdBias = -0.5f; /// /// Input image brightness threshold scale. Used to multiply input pixels. /// API_FIELD(Attributes="EditorOrder(7), PostProcessSetting((int)LensFlaresSettingsOverride.ThresholdScale)") - float ThresholdScale = 0.22f; + float ThresholdScale = 0.22f; /// /// Fullscreen lens dirt texture. /// API_FIELD(Attributes="DefaultValue(null), EditorOrder(8), PostProcessSetting((int)LensFlaresSettingsOverride.LensDirt)") - SoftAssetReference LensDirt; + SoftAssetReference LensDirt; /// /// Fullscreen lens dirt intensity parameter. Allows tuning dirt visibility. /// API_FIELD(Attributes="Limit(0, 100, 0.01f), EditorOrder(9), PostProcessSetting((int)LensFlaresSettingsOverride.LensDirtIntensity)") - float LensDirtIntensity = 1.0f; + float LensDirtIntensity = 1.0f; /// /// Custom lens color texture (1D) used for lens color spectrum. /// API_FIELD(Attributes="DefaultValue(null), EditorOrder(10), PostProcessSetting((int)LensFlaresSettingsOverride.LensColor)") - SoftAssetReference LensColor; + SoftAssetReference LensColor; /// /// Custom lens star texture sampled by lens flares. /// API_FIELD(Attributes="DefaultValue(null), EditorOrder(11), PostProcessSetting((int)LensFlaresSettingsOverride.LensStar)") - SoftAssetReference LensStar; + SoftAssetReference LensStar; public: /// @@ -1421,103 +1443,103 @@ API_STRUCT() struct FLAXENGINE_API DepthOfFieldSettings : ISerializable /// The flags for overriden properties. /// API_FIELD(Attributes="HideInEditor") - DepthOfFieldSettingsOverride OverrideFlags = Override::None; + DepthOfFieldSettingsOverride OverrideFlags = Override::None; /// /// If checked, the depth of field effect will be visible. /// API_FIELD(Attributes="EditorOrder(0), PostProcessSetting((int)DepthOfFieldSettingsOverride.Enabled)") - bool Enabled = false; + bool Enabled = false; /// /// The blur intensity in the out-of-focus areas. Allows reducing the blur amount by scaling down the Gaussian Blur radius. Normalized to range 0-1. /// API_FIELD(Attributes="Limit(0, 1, 0.01f), EditorOrder(1), PostProcessSetting((int)DepthOfFieldSettingsOverride.BlurStrength)") - float BlurStrength = 1.0f; + float BlurStrength = 1.0f; /// /// The distance in World Units from the camera that acts as the center of the region where the scene is perfectly in focus and no blurring occurs. /// API_FIELD(Attributes="Limit(0), EditorOrder(2), PostProcessSetting((int)DepthOfFieldSettingsOverride.FocalDistance)") - float FocalDistance = 1700.0f; + float FocalDistance = 1700.0f; /// /// The distance in World Units beyond the focal distance where the scene is perfectly in focus and no blurring occurs. /// API_FIELD(Attributes="Limit(0), EditorOrder(3), PostProcessSetting((int)DepthOfFieldSettingsOverride.FocalRegion)") - float FocalRegion = 3000.0f; + float FocalRegion = 3000.0f; /// /// The distance in World Units from the focal region on the side nearer to the camera over which the scene transitions from focused to blurred. /// API_FIELD(Attributes="Limit(0), EditorOrder(4), PostProcessSetting((int)DepthOfFieldSettingsOverride.NearTransitionRange)") - float NearTransitionRange = 300.0f; + float NearTransitionRange = 300.0f; /// /// The distance in World Units from the focal region on the side farther from the camera over which the scene transitions from focused to blurred. /// API_FIELD(Attributes="Limit(0), EditorOrder(5), PostProcessSetting((int)DepthOfFieldSettingsOverride.FarTransitionRange)") - float FarTransitionRange = 500.0f; + float FarTransitionRange = 500.0f; /// /// The distance in World Units which describes border after that there is no blur (useful to disable DoF on sky). Use 0 to disable that feature. /// API_FIELD(Attributes="Limit(0, float.MaxValue, 2), EditorOrder(6), PostProcessSetting((int)DepthOfFieldSettingsOverride.DepthLimit)") - float DepthLimit = 0.0f; + float DepthLimit = 0.0f; /// /// If checked, bokeh shapes will be rendered. /// API_FIELD(Attributes="EditorOrder(7), PostProcessSetting((int)DepthOfFieldSettingsOverride.BokehEnabled)") - bool BokehEnabled = true; + bool BokehEnabled = true; /// /// Controls size of the bokeh shapes. /// API_FIELD(Attributes="Limit(0, 200.0f, 0.1f), EditorOrder(8), PostProcessSetting((int)DepthOfFieldSettingsOverride.BokehSize)") - float BokehSize = 25.0f; + float BokehSize = 25.0f; /// /// Controls brightness of the bokeh shapes. Can be used to fade them or make more intense. /// API_FIELD(Attributes="Limit(0, 10.0f, 0.01f), EditorOrder(9), PostProcessSetting((int)DepthOfFieldSettingsOverride.BokehBrightness)") - float BokehBrightness = 1.0f; + float BokehBrightness = 1.0f; /// /// Defines the type of the bokeh shapes. /// API_FIELD(Attributes="EditorOrder(10), PostProcessSetting((int)DepthOfFieldSettingsOverride.BokehShape)") - BokehShapeType BokehShape = BokehShapeType::Octagon; + BokehShapeType BokehShape = BokehShapeType::Octagon; /// /// If BokehShape is set to Custom, then this texture will be used for the bokeh shapes. For best performance, use small, compressed, grayscale textures (for instance 32px). /// API_FIELD(Attributes="DefaultValue(null), EditorOrder(11), PostProcessSetting((int)DepthOfFieldSettingsOverride.BokehShapeCustom)") - SoftAssetReference BokehShapeCustom; + SoftAssetReference BokehShapeCustom; /// /// The minimum pixel brightness to create the bokeh. Pixels with lower brightness will be skipped. /// API_FIELD(Attributes="Limit(0, 10000.0f, 0.01f), EditorOrder(12), PostProcessSetting((int)DepthOfFieldSettingsOverride.BokehBrightnessThreshold)") - float BokehBrightnessThreshold = 3.0f; + float BokehBrightnessThreshold = 3.0f; /// /// Depth of Field bokeh shape blur threshold. /// API_FIELD(Attributes="Limit(0, 1.0f, 0.001f), EditorOrder(13), PostProcessSetting((int)DepthOfFieldSettingsOverride.BokehBlurThreshold)") - float BokehBlurThreshold = 0.05f; + float BokehBlurThreshold = 0.05f; /// /// Controls bokeh shape brightness falloff. Higher values reduce bokeh visibility. /// API_FIELD(Attributes="Limit(0, 2.0f, 0.001f), EditorOrder(14), PostProcessSetting((int)DepthOfFieldSettingsOverride.BokehFalloff)") - float BokehFalloff = 0.5f; + float BokehFalloff = 0.5f; /// /// Controls bokeh shape generation for depth discontinuities. /// API_FIELD(Attributes="Limit(0, 5.0f, 0.001f), EditorOrder(15), PostProcessSetting((int)DepthOfFieldSettingsOverride.BokehDepthCutoff)") - float BokehDepthCutoff = 1.5f; + float BokehDepthCutoff = 1.5f; public: /// @@ -1577,31 +1599,31 @@ API_STRUCT() struct FLAXENGINE_API MotionBlurSettings : ISerializable /// The flags for overriden properties. /// API_FIELD(Attributes="HideInEditor") - MotionBlurSettingsOverride OverrideFlags = Override::None; + MotionBlurSettingsOverride OverrideFlags = Override::None; /// /// If checked, the motion blur effect will be rendered. /// API_FIELD(Attributes="EditorOrder(0), PostProcessSetting((int)MotionBlurSettingsOverride.Enabled)") - bool Enabled = true; + bool Enabled = true; /// /// The blur effect strength. A value of 0 disables it, while higher values increase the effect. /// API_FIELD(Attributes="Limit(0, 5, 0.01f), EditorOrder(1), PostProcessSetting((int)MotionBlurSettingsOverride.Scale)") - float Scale = 0.5f; + float Scale = 0.5f; /// /// The amount of sample points used during motion blur rendering. It affects blur quality and performance. /// API_FIELD(Attributes="Limit(4, 32, 0.1f), EditorOrder(2), PostProcessSetting((int)MotionBlurSettingsOverride.SampleCount)") - int32 SampleCount = 10; + int32 SampleCount = 10; /// /// The motion vectors texture resolution. Motion blur uses a per-pixel motion vector buffer that contains an objects movement information. Use a lower resolution to improve performance. /// API_FIELD(Attributes="EditorOrder(3), PostProcessSetting((int)MotionBlurSettingsOverride.MotionVectorsResolution)") - ResolutionMode MotionVectorsResolution = ResolutionMode::Half; + ResolutionMode MotionVectorsResolution = ResolutionMode::Half; public: /// @@ -1721,103 +1743,103 @@ API_STRUCT() struct FLAXENGINE_API ScreenSpaceReflectionsSettings : ISerializabl /// The flags for overriden properties. /// API_FIELD(Attributes="HideInEditor") - ScreenSpaceReflectionsSettingsOverride OverrideFlags = Override::None; + ScreenSpaceReflectionsSettingsOverride OverrideFlags = Override::None; /// /// The effect intensity (normalized to range [0;1]). Use 0 to disable it. /// API_FIELD(Attributes="Limit(0, 5.0f, 0.01f), EditorOrder(0), PostProcessSetting((int)ScreenSpaceReflectionsSettingsOverride.Intensity)") - float Intensity = 1.0f; + float Intensity = 1.0f; /// /// The reflections tracing mode. /// API_FIELD(Attributes="EditorOrder(1), PostProcessSetting((int)ScreenSpaceReflectionsSettingsOverride.TraceMode)") - ReflectionsTraceMode TraceMode = ReflectionsTraceMode::ScreenTracing; + ReflectionsTraceMode TraceMode = ReflectionsTraceMode::ScreenTracing; /// /// The depth buffer downscale option to optimize raycast performance. Full gives better quality, but half improves performance. /// API_FIELD(Attributes="EditorOrder(2), PostProcessSetting((int)ScreenSpaceReflectionsSettingsOverride.DepthResolution)") - ResolutionMode DepthResolution = ResolutionMode::Half; + ResolutionMode DepthResolution = ResolutionMode::Half; /// /// The raycast resolution. Full gives better quality, but half improves performance. /// API_FIELD(Attributes="EditorOrder(3), PostProcessSetting((int)ScreenSpaceReflectionsSettingsOverride.RayTracePassResolution)") - ResolutionMode RayTracePassResolution = ResolutionMode::Half; + ResolutionMode RayTracePassResolution = ResolutionMode::Half; /// /// The reflection spread parameter. This value controls source roughness effect on reflections blur. Smaller values produce wider reflections spread but also introduce more noise. Higher values provide more mirror-like reflections. /// API_FIELD(Attributes="Limit(0, 1.0f, 0.01f), EditorOrder(10), PostProcessSetting((int)ScreenSpaceReflectionsSettingsOverride.BRDFBias), EditorDisplay(null, \"BRDF Bias\")") - float BRDFBias = 0.82f; + float BRDFBias = 0.82f; /// /// The maximum amount of roughness a material must have to reflect the scene. For example, if this value is set to 0.4, only materials with a roughness value of 0.4 or below reflect the scene. /// API_FIELD(Attributes="Limit(0, 1.0f, 0.01f), EditorOrder(15), PostProcessSetting((int)ScreenSpaceReflectionsSettingsOverride.RoughnessThreshold)") - float RoughnessThreshold = 0.45f; + float RoughnessThreshold = 0.45f; /// /// The offset of the raycast origin. Lower values produce more correct reflection placement, but produce more artifacts. We recommend values of 0.3 or lower. /// API_FIELD(Attributes="Limit(0, 10.0f, 0.01f), EditorOrder(20), PostProcessSetting((int)ScreenSpaceReflectionsSettingsOverride.WorldAntiSelfOcclusionBias)") - float WorldAntiSelfOcclusionBias = 0.1f; + float WorldAntiSelfOcclusionBias = 0.1f; /// /// The raycast resolution. Full gives better quality, but half improves performance. /// API_FIELD(Attributes="EditorOrder(25), PostProcessSetting((int)ScreenSpaceReflectionsSettingsOverride.ResolvePassResolution)") - ResolutionMode ResolvePassResolution = ResolutionMode::Full; + ResolutionMode ResolvePassResolution = ResolutionMode::Full; /// /// The number of rays used to resolve the reflection color. Higher values provide better quality but reduce effect performance. Use value of 1 for the best performance at cost of quality. /// API_FIELD(Attributes="Limit(1, 8), EditorOrder(26), PostProcessSetting((int)ScreenSpaceReflectionsSettingsOverride.ResolveSamples)") - int32 ResolveSamples = 4; + int32 ResolveSamples = 4; /// /// The point at which the far edges of the reflection begin to fade. Has no effect on performance. /// API_FIELD(Attributes="Limit(0, 1.0f, 0.02f), EditorOrder(30), PostProcessSetting((int)ScreenSpaceReflectionsSettingsOverride.EdgeFadeFactor)") - float EdgeFadeFactor = 0.1f; + float EdgeFadeFactor = 0.1f; /// /// The effect fade out end distance from camera (in world units). /// API_FIELD(Attributes="Limit(0), EditorOrder(31), PostProcessSetting((int)ScreenSpaceReflectionsSettingsOverride.FadeOutDistance)") - float FadeOutDistance = 5000.0f; + float FadeOutDistance = 5000.0f; /// /// The effect fade distance (in world units). Defines the size of the effect fade from fully visible to fully invisible at FadeOutDistance. /// API_FIELD(Attributes="Limit(0), EditorOrder(32), PostProcessSetting((int)ScreenSpaceReflectionsSettingsOverride.FadeDistance)") - float FadeDistance = 500.0f; + float FadeDistance = 500.0f; /// /// "The input color buffer downscale mode that uses blurred mipmaps when resolving the reflection color. Produces more realistic results by blurring distant parts of reflections in rough (low-gloss) materials. It also improves performance on most platforms but uses more memory. /// API_FIELD(Attributes="EditorOrder(40), PostProcessSetting((int)ScreenSpaceReflectionsSettingsOverride.UseColorBufferMips), EditorDisplay(null, \"Use Color Buffer Mips\")") - bool UseColorBufferMips = true; + bool UseColorBufferMips = true; /// /// If checked, enables the temporal pass. Reduces noise, but produces an animated "jittering" effect that's sometimes noticeable. If disabled, the properties below have no effect. /// API_FIELD(Attributes="EditorOrder(50), PostProcessSetting((int)ScreenSpaceReflectionsSettingsOverride.TemporalEffect), EditorDisplay(null, \"Enable Temporal Effect\")") - bool TemporalEffect = true; + bool TemporalEffect = true; /// /// The intensity of the temporal effect. Lower values produce reflections faster, but more noise. /// API_FIELD(Attributes="Limit(0, 20.0f, 0.5f), EditorOrder(55), PostProcessSetting((int)ScreenSpaceReflectionsSettingsOverride.TemporalScale)") - float TemporalScale = 8.0f; + float TemporalScale = 8.0f; /// /// Defines how quickly reflections blend between the reflection in the current frame and the history buffer. Lower values produce reflections faster, but with more jittering. If the camera in your game doesn't move much, we recommend values closer to 1. /// API_FIELD(Attributes="Limit(0.05f, 1.0f, 0.01f), EditorOrder(60), PostProcessSetting((int)ScreenSpaceReflectionsSettingsOverride.TemporalResponse)") - float TemporalResponse = 0.8f; + float TemporalResponse = 0.8f; public: /// @@ -1902,61 +1924,61 @@ API_STRUCT() struct FLAXENGINE_API AntiAliasingSettings : ISerializable /// The flags for overriden properties. /// API_FIELD(Attributes="HideInEditor") - AntiAliasingSettingsOverride OverrideFlags = Override::None; + AntiAliasingSettingsOverride OverrideFlags = Override::None; /// /// The anti-aliasing effect mode. /// API_FIELD(Attributes="EditorOrder(0), PostProcessSetting((int)AntiAliasingSettingsOverride.Mode)") - AntialiasingMode Mode = AntialiasingMode::FastApproximateAntialiasing; + AntialiasingMode Mode = AntialiasingMode::FastApproximateAntialiasing; /// /// The diameter (in texels) inside which jitter samples are spread. Smaller values result in crisper but more aliased output, while larger values result in more stable but blurrier output. /// API_FIELD(Attributes="Limit(0.1f, 1f, 0.001f), EditorOrder(1), PostProcessSetting((int)AntiAliasingSettingsOverride.TAA_JitterSpread), EditorDisplay(null, \"TAA Jitter Spread\"), VisibleIf(nameof(ShowTAASettings))") - float TAA_JitterSpread = 1.0f; + float TAA_JitterSpread = 1.0f; /// /// Controls the amount of sharpening applied to the color buffer. TAA can induce a slight loss of details in high frequency regions. Sharpening alleviates this issue. High values may introduce dark-border artifacts. /// API_FIELD(Attributes="Limit(0, 3f, 0.001f), EditorOrder(2), PostProcessSetting((int)AntiAliasingSettingsOverride.TAA_Sharpness), EditorDisplay(null, \"TAA Sharpness\"), VisibleIf(nameof(ShowTAASettings))") - float TAA_Sharpness = 0.1f; + float TAA_Sharpness = 0.1f; /// /// The blend coefficient for stationary fragments. Controls the percentage of history samples blended into the final color for fragments with minimal active motion. /// API_FIELD(Attributes="Limit(0, 0.99f, 0.001f), EditorOrder(3), PostProcessSetting((int)AntiAliasingSettingsOverride.TAA_StationaryBlending), EditorDisplay(null, \"TAA Stationary Blending\"), VisibleIf(nameof(ShowTAASettings))") - float TAA_StationaryBlending = 0.95f; + float TAA_StationaryBlending = 0.95f; /// /// The blending coefficient for moving fragments. Controls the percentage of history samples blended into the final color for fragments with significant active motion. /// API_FIELD(Attributes="Limit(0, 0.99f, 0.001f), EditorOrder(4), PostProcessSetting((int)AntiAliasingSettingsOverride.TAA_MotionBlending), EditorDisplay(null, \"TAA Motion Blending\"), VisibleIf(nameof(ShowTAASettings))") - float TAA_MotionBlending = 0.85f; + float TAA_MotionBlending = 0.85f; /// /// The sharpening strength for the Contrast Adaptive Sharpening (CAS) pass. Ignored when using TAA that contains own contrast filter. /// - API_FIELD(Attributes = "Limit(0, 10f, 0.001f), EditorOrder(10), PostProcessSetting((int)AntiAliasingSettingsOverride.CAS_SharpeningAmount), EditorDisplay(null, \"CAS Sharpening Amount\"), VisibleIf(nameof(ShowTAASettings), true)") - float CAS_SharpeningAmount = 0.0f; + API_FIELD(Attributes="Limit(0, 10f, 0.001f), EditorOrder(10), PostProcessSetting((int)AntiAliasingSettingsOverride.CAS_SharpeningAmount), EditorDisplay(null, \"CAS Sharpening Amount\"), VisibleIf(nameof(ShowTAASettings), true)") + float CAS_SharpeningAmount = 0.0f; /// /// The edge sharpening strength for the Contrast Adaptive Sharpening (CAS) pass. Ignored when using TAA that contains own contrast filter. /// - API_FIELD(Attributes = "Limit(0, 10f, 0.001f), EditorOrder(11), PostProcessSetting((int)AntiAliasingSettingsOverride.CAS_EdgeSharpening), EditorDisplay(null, \"CAS Edge Sharpening\"), VisibleIf(nameof(ShowTAASettings), true)") - float CAS_EdgeSharpening = 0.5f; + API_FIELD(Attributes="Limit(0, 10f, 0.001f), EditorOrder(11), PostProcessSetting((int)AntiAliasingSettingsOverride.CAS_EdgeSharpening), EditorDisplay(null, \"CAS Edge Sharpening\"), VisibleIf(nameof(ShowTAASettings), true)") + float CAS_EdgeSharpening = 0.5f; /// /// The minimum edge threshold for the Contrast Adaptive Sharpening (CAS) pass. Ignored when using TAA that contains own contrast filter. /// - API_FIELD(Attributes = "Limit(0, 10f, 0.001f), EditorOrder(12), PostProcessSetting((int)AntiAliasingSettingsOverride.CAS_MinEdgeThreshold), EditorDisplay(null, \"CAS Min Edge Threshold\"), VisibleIf(nameof(ShowTAASettings), true)") - float CAS_MinEdgeThreshold = 0.03f; + API_FIELD(Attributes="Limit(0, 10f, 0.001f), EditorOrder(12), PostProcessSetting((int)AntiAliasingSettingsOverride.CAS_MinEdgeThreshold), EditorDisplay(null, \"CAS Min Edge Threshold\"), VisibleIf(nameof(ShowTAASettings), true)") + float CAS_MinEdgeThreshold = 0.03f; /// /// The over-blur limit for the Contrast Adaptive Sharpening (CAS) pass. Ignored when using TAA that contains own contrast filter. /// - API_FIELD(Attributes = "Limit(0, 100f, 0.001f), EditorOrder(13), PostProcessSetting((int)AntiAliasingSettingsOverride.CAS_OverBlurLimit), EditorDisplay(null, \"CAS Over-blur Limit\"), VisibleIf(nameof(ShowTAASettings), true)") - float CAS_OverBlurLimit = 1.0f; + API_FIELD(Attributes="Limit(0, 100f, 0.001f), EditorOrder(13), PostProcessSetting((int)AntiAliasingSettingsOverride.CAS_OverBlurLimit), EditorDisplay(null, \"CAS Over-blur Limit\"), VisibleIf(nameof(ShowTAASettings), true)") + float CAS_OverBlurLimit = 1.0f; public: /// @@ -1979,7 +2001,7 @@ API_STRUCT() struct FLAXENGINE_API PostFxMaterialsSettings : ISerializable /// The post-process materials collection for rendering (fixed capacity). /// API_FIELD(Attributes="EditorDisplay(null, EditorDisplayAttribute.InlineStyle), Collection(MaxCount=8)") - Array, FixedAllocation> Materials; + Array, FixedAllocation> Materials; public: /// @@ -2001,79 +2023,79 @@ API_STRUCT() struct FLAXENGINE_API PostProcessSettings : ISerializable /// The ambient occlusion effect settings. /// API_FIELD(Attributes="EditorDisplay(\"Ambient Occlusion\"), EditorOrder(100), JsonProperty(\"AO\")") - AmbientOcclusionSettings AmbientOcclusion; + AmbientOcclusionSettings AmbientOcclusion; /// /// The global illumination effect settings. /// API_FIELD(Attributes="EditorDisplay(\"Global Illumination\"), EditorOrder(150), JsonProperty(\"GI\")") - GlobalIlluminationSettings GlobalIllumination; + GlobalIlluminationSettings GlobalIllumination; /// /// The bloom effect settings. /// API_FIELD(Attributes="EditorDisplay(\"Bloom\"), EditorOrder(200)") - BloomSettings Bloom; + BloomSettings Bloom; /// /// The tone mapping effect settings. /// API_FIELD(Attributes="EditorDisplay(\"Tone Mapping\"), EditorOrder(300)") - ToneMappingSettings ToneMapping; + ToneMappingSettings ToneMapping; /// /// The color grading effect settings. /// API_FIELD(Attributes="EditorDisplay(\"Color Grading\"), EditorOrder(400)") - ColorGradingSettings ColorGrading; + ColorGradingSettings ColorGrading; /// /// The eye adaptation effect settings. /// API_FIELD(Attributes="EditorDisplay(\"Eye Adaptation\"), EditorOrder(500)") - EyeAdaptationSettings EyeAdaptation; + EyeAdaptationSettings EyeAdaptation; /// /// The camera artifacts effect settings. /// API_FIELD(Attributes="EditorDisplay(\"Camera Artifacts\"), EditorOrder(600)") - CameraArtifactsSettings CameraArtifacts; + CameraArtifactsSettings CameraArtifacts; /// /// The lens flares effect settings. /// API_FIELD(Attributes="EditorDisplay(\"Lens Flares\"), EditorOrder(700)") - LensFlaresSettings LensFlares; + LensFlaresSettings LensFlares; /// /// The depth of field effect settings. /// API_FIELD(Attributes="EditorDisplay(\"Depth Of Field\"), EditorOrder(800)") - DepthOfFieldSettings DepthOfField; + DepthOfFieldSettings DepthOfField; /// /// The motion blur effect settings. /// API_FIELD(Attributes="EditorDisplay(\"Motion Blur\"), EditorOrder(900)") - MotionBlurSettings MotionBlur; + MotionBlurSettings MotionBlur; /// /// The screen space reflections effect settings. /// API_FIELD(Attributes="EditorDisplay(\"Screen Space Reflections\"), EditorOrder(1000), JsonProperty(\"SSR\")") - ScreenSpaceReflectionsSettings ScreenSpaceReflections; + ScreenSpaceReflectionsSettings ScreenSpaceReflections; /// /// The antialiasing effect settings. /// API_FIELD(Attributes="EditorDisplay(\"Anti Aliasing\"), EditorOrder(1100), JsonProperty(\"AA\")") - AntiAliasingSettings AntiAliasing; + AntiAliasingSettings AntiAliasing; /// /// The PostFx materials rendering settings. /// API_FIELD(Attributes="EditorDisplay(\"PostFx Materials\"), NoAnimate, EditorOrder(1200)") - PostFxMaterialsSettings PostFxMaterials; + PostFxMaterialsSettings PostFxMaterials; public: /// diff --git a/Source/Engine/Renderer/PostProcessingPass.cpp b/Source/Engine/Renderer/PostProcessingPass.cpp index 99831b430..f4d86ec21 100644 --- a/Source/Engine/Renderer/PostProcessingPass.cpp +++ b/Source/Engine/Renderer/PostProcessingPass.cpp @@ -11,8 +11,9 @@ PostProcessingPass::PostProcessingPass() : _shader(nullptr) - , _psThreshold(nullptr) - , _psScale(nullptr) + , _psBloomBrightPass(nullptr) + , _psBloomDownsample(nullptr) + , _psBloomDualFilterUpsample(nullptr) , _psBlurH(nullptr) , _psBlurV(nullptr) , _psGenGhosts(nullptr) @@ -30,8 +31,9 @@ String PostProcessingPass::ToString() const bool PostProcessingPass::Init() { // Create pipeline states - _psThreshold = GPUDevice::Instance->CreatePipelineState(); - _psScale = GPUDevice::Instance->CreatePipelineState(); + _psBloomBrightPass = GPUDevice::Instance->CreatePipelineState(); + _psBloomDownsample = GPUDevice::Instance->CreatePipelineState(); + _psBloomDualFilterUpsample = GPUDevice::Instance->CreatePipelineState(); _psBlurH = GPUDevice::Instance->CreatePipelineState(); _psBlurV = GPUDevice::Instance->CreatePipelineState(); _psGenGhosts = GPUDevice::Instance->CreatePipelineState(); @@ -69,16 +71,23 @@ bool PostProcessingPass::setupResources() // Create pipeline stages GPUPipelineState::Description psDesc = GPUPipelineState::Description::DefaultFullscreenTriangle; - if (!_psThreshold->IsValid()) + if (!_psBloomBrightPass->IsValid()) { - psDesc.PS = shader->GetPS("PS_Threshold"); - if (_psThreshold->Init(psDesc)) + psDesc.PS = shader->GetPS("PS_BloomBrightPass"); + if (_psBloomBrightPass->Init(psDesc)) return true; } - if (!_psScale->IsValid()) + if (!_psBloomDownsample->IsValid()) { - psDesc.PS = shader->GetPS("PS_Scale"); - if (_psScale->Init(psDesc)) + psDesc.PS = shader->GetPS("PS_BloomDownsample"); + if (_psBloomDownsample->Init(psDesc)) + return true; + } + + if (!_psBloomDualFilterUpsample->IsValid()) + { + psDesc.PS = shader->GetPS("PS_BloomDualFilterUpsample"); + if (_psBloomDualFilterUpsample->Init(psDesc)) return true; } if (!_psBlurH->IsValid()) @@ -167,8 +176,9 @@ void PostProcessingPass::Dispose() RendererPass::Dispose(); // Cleanup - SAFE_DELETE_GPU_RESOURCE(_psThreshold); - SAFE_DELETE_GPU_RESOURCE(_psScale); + SAFE_DELETE_GPU_RESOURCE(_psBloomBrightPass); + SAFE_DELETE_GPU_RESOURCE(_psBloomDownsample); + SAFE_DELETE_GPU_RESOURCE(_psBloomDualFilterUpsample); SAFE_DELETE_GPU_RESOURCE(_psBlurH); SAFE_DELETE_GPU_RESOURCE(_psBlurV); SAFE_DELETE_GPU_RESOURCE(_psGenGhosts); @@ -179,13 +189,32 @@ void PostProcessingPass::Dispose() _defaultLensStar = nullptr; } +float CalculateBloomMipCount(int32 width, int32 height) +{ + // Calculate the smallest dimension + int32 minDimension = Math::Min(width, height); + + // Calculate how many times we can half the dimension until we hit a minimum size + // (e.g., 16x16 pixels as the smallest mip) + const int32 MIN_MIP_SIZE = 16; + float mipCount = 1.0f; + + while (minDimension > MIN_MIP_SIZE) { + minDimension /= 2; + mipCount += 1.0f; + } + + + return mipCount; +} + void PostProcessingPass::Render(RenderContext& renderContext, GPUTexture* input, GPUTexture* output, GPUTexture* colorGradingLUT) { PROFILE_GPU_CPU("Post Processing"); auto device = GPUDevice::Instance; auto context = device->GetMainContext(); auto& view = renderContext.View; - + context->ResetRenderTarget(); PostProcessSettings& settings = renderContext.List->Settings; @@ -204,8 +233,10 @@ void PostProcessingPass::Render(RenderContext& renderContext, GPUTexture* input, int32 h4 = h2 >> 1; int32 h8 = h4 >> 1; + int32 bloomMipCount = CalculateBloomMipCount(w1, h1); + // Ensure to have valid data and if at least one effect should be applied - if (!(useBloom || useToneMapping || useCameraArtifacts) || checkIfSkipPass() || w8 == 0 || h8 ==0) + if (!(useBloom || useToneMapping || useCameraArtifacts) || checkIfSkipPass() || w8 == 0 || h8 == 0) { // Resources are missing. Do not perform rendering. Just copy raw frame context->SetViewportAndScissors((float)output->Width(), (float)output->Height()); @@ -245,14 +276,18 @@ void PostProcessingPass::Render(RenderContext& renderContext, GPUTexture* input, } if (useBloom) { - data.BloomMagnitude = settings.Bloom.Intensity; + data.BloomIntensity = settings.Bloom.Intensity; + data.BloomClamp = settings.Bloom.Clamp; data.BloomThreshold = settings.Bloom.Threshold; - data.BloomBlurSigma = Math::Max(settings.Bloom.BlurSigma, 0.0001f); - data.BloomLimit = settings.Bloom.Limit; + data.BloomThresholdKnee = settings.Bloom.ThresholdKnee; + data.BloomBaseMix = settings.Bloom.BaseMix; + data.BloomHighMix = settings.Bloom.HighMix; + data.BloomMipCount = bloomMipCount; + data.BloomLayer = 0.0f; } else { - data.BloomMagnitude = 0; + data.BloomIntensity = 0; } if (useLensFlares) { @@ -298,99 +333,83 @@ void PostProcessingPass::Render(RenderContext& renderContext, GPUTexture* input, //////////////////////////////////////////////////////////////////////////////////// // Bloom - auto tempDesc = GPUTextureDescription::New2D(w2, h2, 0, output->Format(), GPUTextureFlags::ShaderResource | GPUTextureFlags::RenderTarget | GPUTextureFlags::PerMipViews); - auto bloomTmp1 = RenderTargetPool::Get(tempDesc); - RENDER_TARGET_POOL_SET_NAME(bloomTmp1, "PostProcessing.Bloom"); - // TODO: bloomTmp2 could be quarter res because we don't use it's first mip - auto bloomTmp2 = RenderTargetPool::Get(tempDesc); - RENDER_TARGET_POOL_SET_NAME(bloomTmp2, "PostProcessing.Bloom"); + + auto tempDesc = GPUTextureDescription::New2D(w2, h2, bloomMipCount, output->Format(), GPUTextureFlags::ShaderResource | GPUTextureFlags::RenderTarget | GPUTextureFlags::PerMipViews); + auto bloomBuffer1 = RenderTargetPool::Get(tempDesc); + RENDER_TARGET_POOL_SET_NAME(bloomBuffer1, "PostProcessing.Bloom"); + auto bloomBuffer2 = RenderTargetPool::Get(tempDesc); + RENDER_TARGET_POOL_SET_NAME(bloomBuffer2, "PostProcessing.Bloom"); + + for (int32 mip = 0; mip < bloomMipCount; mip++) + { + context->Clear(bloomBuffer1->View(0, mip), Color::Transparent); + context->Clear(bloomBuffer2->View(0, mip), Color::Transparent); + } // Check if use bloom if (useBloom) { - // Bloom Threshold and downscale to 1/2 - context->SetRenderTarget(bloomTmp1->View(0, 0)); + + context->SetRenderTarget(bloomBuffer1->View(0, 0)); context->SetViewportAndScissors((float)w2, (float)h2); context->BindSR(0, input->View()); - context->SetState(_psThreshold); + context->SetState(_psBloomBrightPass); context->DrawFullscreenTriangle(); context->ResetRenderTarget(); - // Downscale to 1/4 - context->SetRenderTarget(bloomTmp1->View(0, 1)); - context->SetViewportAndScissors((float)w4, (float)h4); - context->BindSR(0, bloomTmp1->View(0, 0)); - context->SetState(_psScale); - context->DrawFullscreenTriangle(); - context->ResetRenderTarget(); - - // Downscale to 1/8 - context->SetRenderTarget(bloomTmp1->View(0, 2)); - context->SetViewportAndScissors((float)w8, (float)h8); - context->BindSR(0, bloomTmp1->View(0, 1)); - context->SetState(_psScale); - context->DrawFullscreenTriangle(); - context->ResetRenderTarget(); - - // TODO: perform blur when downscaling (13 tap) and when upscaling? (9 tap) - - // Gaussian Blur - GB_ComputeKernel(data.BloomBlurSigma, static_cast(w8), static_cast(h8)); - //int32 blurStages = (int)Rendering.Quality + 1; - int32 blurStages = 2; - for (int32 i = 0; i < blurStages; i++) + // Progressive downsamples + for (int32 mip = 1; mip < bloomMipCount; mip++) { - // Horizontal Bloom Blur - Platform::MemoryCopy(_gbData.GaussianBlurCache, GaussianBlurCacheH, sizeof(GaussianBlurCacheH)); - context->UpdateCB(cb1, &_gbData); - context->BindCB(1, cb1); - // - context->SetRenderTarget(bloomTmp2->View(0, 2)); - context->BindSR(0, bloomTmp1->View(0, 2)); - context->SetState(_psBlurH); + const float mipWidth = w2 >> mip; + const float mipHeight = h2 >> mip; + + context->SetRenderTarget(bloomBuffer1->View(0, mip)); + context->SetViewportAndScissors(mipWidth, mipHeight); + context->BindSR(0, bloomBuffer1->View(0, mip - 1)); + context->SetState(_psBloomDownsample); context->DrawFullscreenTriangle(); context->ResetRenderTarget(); - // Vertical Bloom Blur - Platform::MemoryCopy(_gbData.GaussianBlurCache, GaussianBlurCacheV, sizeof(GaussianBlurCacheV)); - context->UpdateCB(cb1, &_gbData); - context->BindCB(1, cb1); - // - context->SetRenderTarget(bloomTmp1->View(0, 2)); - context->BindSR(0, bloomTmp2->View(0, 2)); - context->SetState(_psBlurV); + } + + // Progressive upsamples + for (int32 mip = bloomMipCount - 2; mip >= 0; mip--) + { + auto upscalebuffer = bloomBuffer2; + if (mip == bloomMipCount - 2) + { + // if it's the first, copy the chain over. + upscalebuffer = bloomBuffer1; + + } + + const float mipWidth = w2 >> mip; + const float mipHeight = h2 >> mip; + + data.BloomLayer = static_cast(mip); // Set the current mip as bloom layer + context->UpdateCB(cb0, &data); // Update the constant buffer + + context->SetRenderTarget(bloomBuffer2->View(0, mip)); + context->SetViewportAndScissors(mipWidth, mipHeight); + context->BindSR(0, upscalebuffer->View(0, mip + 1)); + context->BindSR(1, bloomBuffer1->View(0, mip + 1)); + context->SetState(_psBloomDualFilterUpsample); context->DrawFullscreenTriangle(); context->ResetRenderTarget(); } - // Upscale to 1/4 (use second tmp target to cache that downscale thress data for lens flares) - context->SetRenderTarget(bloomTmp2->View(0, 1)); - context->SetViewportAndScissors((float)w4, (float)h4); - context->BindSR(0, bloomTmp1->View(0, 2)); - context->SetState(_psScale); - context->DrawFullscreenTriangle(); - context->ResetRenderTarget(); - - // Upscale to 1/2 - context->SetRenderTarget(bloomTmp1->View(0, 0)); - context->SetViewportAndScissors((float)w2, (float)h2); - context->BindSR(0, bloomTmp2->View(0, 1)); - context->SetState(_psScale); - context->DrawFullscreenTriangle(); - context->ResetRenderTarget(); - - // Set bloom - context->UnBindSR(0); - context->BindSR(2, bloomTmp1->View(0, 0)); + // Final composite + context->BindSR(1, bloomBuffer1); + context->BindSR(2, bloomBuffer2); } else { - // No bloom texture context->UnBindSR(2); } //////////////////////////////////////////////////////////////////////////////////// - // Lens Flares + //Lens Flares + // Check if use lens flares if (useLensFlares) @@ -399,10 +418,12 @@ void PostProcessingPass::Render(RenderContext& renderContext, GPUTexture* input, context->BindSR(5, getCustomOrDefault(settings.LensFlares.LensStar, _defaultLensStar, TEXT("Engine/Textures/DefaultLensStarburst"))); context->BindSR(6, getCustomOrDefault(settings.LensFlares.LensColor, _defaultLensColor, TEXT("Engine/Textures/DefaultLensColor"))); + // use bloomBuffer1's mip 1 as input for lens flares + // Render lens flares - context->SetRenderTarget(bloomTmp2->View(0, 1)); + context->SetRenderTarget(bloomBuffer2->View(0, 1)); context->SetViewportAndScissors((float)w4, (float)h4); - context->BindSR(3, bloomTmp1->View(0, 1)); + context->BindSR(3, bloomBuffer1->View(0, 1)); // Use mip 1 of bloomBuffer1 as source context->SetState(_psGenGhosts); context->DrawFullscreenTriangle(); context->ResetRenderTarget(); @@ -415,8 +436,8 @@ void PostProcessingPass::Render(RenderContext& renderContext, GPUTexture* input, Platform::MemoryCopy(_gbData.GaussianBlurCache, GaussianBlurCacheH, sizeof(GaussianBlurCacheH)); context->UpdateCB(cb1, &_gbData); context->BindCB(1, cb1); - context->SetRenderTarget(bloomTmp1->View(0, 1)); - context->BindSR(0, bloomTmp2->View(0, 1)); + context->SetRenderTarget(bloomBuffer1->View(0, 1)); + context->BindSR(0, bloomBuffer2->View(0, 1)); context->SetState(_psBlurH); context->DrawFullscreenTriangle(); context->ResetRenderTarget(); @@ -425,14 +446,14 @@ void PostProcessingPass::Render(RenderContext& renderContext, GPUTexture* input, Platform::MemoryCopy(_gbData.GaussianBlurCache, GaussianBlurCacheV, sizeof(GaussianBlurCacheV)); context->UpdateCB(cb1, &_gbData); context->BindCB(1, cb1); - context->SetRenderTarget(bloomTmp2->View(0, 1)); - context->BindSR(0, bloomTmp1->View(0, 1)); + context->SetRenderTarget(bloomBuffer2->View(0, 1)); + context->BindSR(0, bloomBuffer1->View(0, 1)); context->SetState(_psBlurV); context->DrawFullscreenTriangle(); context->ResetRenderTarget(); // Set lens flares output - context->BindSR(3, bloomTmp2->View(0, 1)); + context->BindSR(3, bloomBuffer2->View(0, 1)); } else { @@ -482,6 +503,6 @@ void PostProcessingPass::Render(RenderContext& renderContext, GPUTexture* input, context->DrawFullscreenTriangle(); // Cleanup - RenderTargetPool::Release(bloomTmp1); - RenderTargetPool::Release(bloomTmp2); + RenderTargetPool::Release(bloomBuffer1); + RenderTargetPool::Release(bloomBuffer2); } diff --git a/Source/Engine/Renderer/PostProcessingPass.h b/Source/Engine/Renderer/PostProcessingPass.h index 22ef5eafc..b7d73a5fd 100644 --- a/Source/Engine/Renderer/PostProcessingPass.h +++ b/Source/Engine/Renderer/PostProcessingPass.h @@ -15,11 +15,16 @@ class PostProcessingPass : public RendererPass { private: - GPU_CB_STRUCT(Data { - float BloomLimit; - float BloomThreshold; - float BloomMagnitude; - float BloomBlurSigma; + GPU_CB_STRUCT(Data{ + float BloomIntensity; // Overall bloom strength multiplier + float BloomClamp; // Maximum brightness limit for bloom + float BloomThreshold; // Luminance threshold where bloom begins + float BloomThresholdKnee; // Controls the threshold rolloff curve + float BloomBaseMix; // Base mip contribution + float BloomHighMix; // High mip contribution + float BloomMipCount; + float BloomLayer; + Float3 VignetteColor; float VignetteShapeFactor; @@ -56,7 +61,7 @@ private: Matrix LensFlareStarMat; }); - GPU_CB_STRUCT(GaussianBlurData { + GPU_CB_STRUCT(GaussianBlurData{ Float2 Size; float Dummy3; float Dummy4; @@ -65,8 +70,9 @@ private: // Post Processing AssetReference _shader; - GPUPipelineState* _psThreshold; - GPUPipelineState* _psScale; + GPUPipelineState* _psBloomBrightPass; + GPUPipelineState* _psBloomDownsample; + GPUPipelineState* _psBloomDualFilterUpsample; GPUPipelineState* _psBlurH; GPUPipelineState* _psBlurV; GPUPipelineState* _psGenGhosts; @@ -115,8 +121,9 @@ private: #if COMPILE_WITH_DEV_ENV void OnShaderReloading(Asset* obj) { - _psThreshold->ReleaseGPU(); - _psScale->ReleaseGPU(); + _psBloomBrightPass->ReleaseGPU(); + _psBloomDownsample->ReleaseGPU(); + _psBloomDualFilterUpsample->ReleaseGPU(); _psBlurH->ReleaseGPU(); _psBlurV->ReleaseGPU(); _psGenGhosts->ReleaseGPU(); diff --git a/Source/Shaders/PostProcessing.shader b/Source/Shaders/PostProcessing.shader index c54337b2e..70f5c6a0c 100644 --- a/Source/Shaders/PostProcessing.shader +++ b/Source/Shaders/PostProcessing.shader @@ -36,10 +36,17 @@ META_CB_BEGIN(0, Data) -float BloomLimit; -float BloomThreshold; -float BloomMagnitude; -float BloomBlurSigma; +// Bloom parameters +float BloomIntensity; +float BloomClamp; +float BloomThreshold; +float BloomThresholdKnee; + +float BloomBaseMix; +float BloomHighMix; +float BloomMipCount; +float BloomLayer; + float3 VignetteColor; float VignetteShapeFactor; @@ -253,34 +260,228 @@ float2 coordRot(in float2 tc, in float angle) } // Uses a lower exposure to produce a value suitable for a bloom pass + META_PS(true, FEATURE_LEVEL_ES2) -float4 PS_Threshold(Quad_VS2PS input) : SV_Target +float4 PS_BloomBrightPass(Quad_VS2PS input) : SV_Target { - float4 color = Input0.SampleLevel(SamplerLinearClamp, input.TexCoord, 0); - return clamp(color - BloomThreshold, 0, BloomLimit); + // Get dimensions for precise texel calculations + uint width, height; + Input0.GetDimensions(width, height); + float2 texelSize = 1.0 / float2(width, height); + // Use fixed 13-tap sample pattern for initial bright pass + float3 color = 0; + float totalWeight = 0; + + // Center sample with high weight for energy preservation + float3 center = Input0.Sample(SamplerLinearClamp, input.TexCoord).rgb; + + // Apply Karis average to prevent bright pixels from dominating + float centerLuma = max(dot(center, float3(0.2126, 0.7152, 0.0722)), 0.0001); + center = center / (1.0 + centerLuma); + + float centerWeight = 4.0; + color += center * centerWeight; + totalWeight += centerWeight; + // Inner ring - fixed offset at 1.0 texel distance + UNROLL + for (int i = 0; i < 4; i++) + { + float angle = i * (PI / 2.0); + float2 offset = float2(cos(angle), sin(angle)) * texelSize; + float3 sample = Input0.Sample(SamplerLinearClamp, input.TexCoord + offset).rgb; + + // Apply Karis average + float sampleLuma = max(dot(sample, float3(0.2126, 0.7152, 0.0722)), 0.0001); + sample = sample / (1.0 + sampleLuma); + + float weight = 2.0; + color += sample * weight; + totalWeight += weight; + } + // Outer ring - fixed offset at 1.4142 texel distance (diagonal) + UNROLL + for (int j = 0; j < 8; j++) + { + float angle = j * (PI / 4.0); + float2 offset = float2(cos(angle), sin(angle)) * texelSize * 1.4142; + float3 sample = Input0.Sample(SamplerLinearClamp, input.TexCoord + offset).rgb; + + // Apply Karis average + float sampleLuma = max(dot(sample, float3(0.2126, 0.7152, 0.0722)), 0.0001); + sample = sample / (1.0 + sampleLuma); + + float weight = 1.0; + color += sample * weight; + totalWeight += weight; + } + color /= totalWeight; + + // Un-apply Karis average to maintain energy + float finalLuma = max(dot(color, float3(0.2126, 0.7152, 0.0722)), 0.0001); + color = color * (1.0 + finalLuma); + + // Apply threshold with quadratic rolloff for smoother transition + float luminance = dot(color, float3(0.2126, 0.7152, 0.0722)); + float threshold = max(BloomThreshold, 0.2); + float knee = threshold * BloomThresholdKnee; + float soft_max = threshold + knee; + + float contribution = 0; + if (luminance > threshold) { + if (luminance < soft_max) { + // Quadratic softening between threshold and (threshold + knee) + float x = (luminance - threshold) / knee; + contribution = x * x * 0.5; + } else { + // Full contribution above soft_max + contribution = luminance - threshold; + } + } + + float testc = BloomClamp; + float3 clamped = (color * contribution); + clamped.r = min(clamped.r, testc); + clamped.g = min(clamped.g, testc); + clamped.b = min(clamped.b, testc); + + // Store threshold result in alpha for downsample chain + return float4(clamped, luminance); } -// Uses hw bilinear filtering for upscaling or downscaling META_PS(true, FEATURE_LEVEL_ES2) -float4 PS_Scale(Quad_VS2PS input) : SV_Target +float4 PS_BloomDownsample(Quad_VS2PS input) : SV_Target { - // TODO: we could use quality switch for bloom effect + uint width, height; + Input0.GetDimensions(width, height); + float2 texelSize = 1.0 / float2(width, height); - return Input0.SampleLevel(SamplerLinearClamp, input.TexCoord, 0); - /* - float3 color; - // TODO: use gather for dx11 and dx12?? - color = Input0.SampleLevel(SamplerLinearClamp, input.TexCoord, 0, int2( 0, 0)).rgb; - color += Input0.SampleLevel(SamplerLinearClamp, input.TexCoord, 0, int2( 0, 1)).rgb; - color += Input0.SampleLevel(SamplerLinearClamp, input.TexCoord, 0, int2( 0,-1)).rgb; - color += Input0.SampleLevel(SamplerLinearClamp, input.TexCoord, 0, int2(-1, 0)).rgb; - color += Input0.SampleLevel(SamplerLinearClamp, input.TexCoord, 0, int2( 1, 0)).rgb; - color *= (1.0f / 5.0f); + // 9-tap tent filter with fixed weights + float3 color = 0; + float totalWeight = 0; - return float4(color, 1); - */ + // Sample offsets (fixed) + const float2 offsets[9] = { + float2( 0, 0), // Center + float2(-1, -1), // Corners + float2( 1, -1), + float2(-1, 1), + float2( 1, 1), + float2( 0, -1), // Cross + float2(-1, 0), + float2( 1, 0), + float2( 0, 1) + }; + + // Sample weights (fixed) + const float weights[9] = { + 4.0, // Center + 1.0, // Corners + 1.0, + 1.0, + 1.0, + 2.0, // Cross + 2.0, + 2.0, + 2.0 + }; + + UNROLL + for (int i = 0; i < 9; i++) + { + float2 offset = offsets[i] * texelSize * 2.0; // Fixed scale factor for stability + float4 sample = Input0.Sample(SamplerLinearClamp, input.TexCoord + offset); + color += sample.rgb * weights[i]; + totalWeight += weights[i]; + } + + return float4(color / totalWeight, 1.0); } +META_PS(true, FEATURE_LEVEL_ES2) +float4 PS_BloomDualFilterUpsample(Quad_VS2PS input) : SV_Target +{ + float anisotropy = 1.0; + + uint width, height; + Input0.GetDimensions(width, height); + float2 texelSize = 1.0 / float2(width, height); + + // Maintain fixed scale through mip chain + float baseOffset = 1.0; + float offsetScale = (1.0) * baseOffset; + float3 color = 0; + float totalWeight = 0; + + // Center + float4 center = Input0.Sample(SamplerLinearClamp, input.TexCoord); + float centerWeight = 4.0; + color += center.rgb * centerWeight; + totalWeight += centerWeight; + + // Cross - fixed distance samples + float2 crossOffsets[4] = { + float2(offsetScale * anisotropy, 0), + float2(-offsetScale * anisotropy, 0), + float2(0, offsetScale), + float2(0, -offsetScale) + }; + + UNROLL + for (int i = 0; i < 4; i++) + { + float4 sample = Input0.Sample(SamplerLinearClamp, input.TexCoord + crossOffsets[i] * texelSize); + float weight = 2.0; + color += sample.rgb * weight; + totalWeight += weight; + } + + // Corners - fixed distance samples + float2 cornerOffsets[4] = { + float2(offsetScale * anisotropy, offsetScale), + float2(-offsetScale * anisotropy, offsetScale), + float2(offsetScale * anisotropy, -offsetScale), + float2(-offsetScale * anisotropy, -offsetScale) + }; + + UNROLL + for (int j = 0; j < 4; j++) + { + float4 sample = Input0.Sample(SamplerLinearClamp, input.TexCoord + cornerOffsets[j] * texelSize); + float weight = 1.0; + color += sample.rgb * weight; + totalWeight += weight; + } + + color /= totalWeight; + + uint width1, height1; + Input1.GetDimensions(width1, height1); + + // Calculate mip fade factor (0 = smallest mip, 1 = largest mip) + float mipFade = BloomLayer / (BloomMipCount - 1); + + // Muzz says: + // Lerp between your desired intensity values based on mip level + // setting both to 0.6 is a decent default, but playing with these numbers will let you dial in the blending between the lowest and highest mips. + // you can make some really ugly bloom if you go too far. + // note this does change the intensity of the bloom. + // This was my own invention + + float mipIntensity = lerp(BloomBaseMix, BloomHighMix, mipFade); + color *= mipIntensity; + + BRANCH + if (width1 > 0) + { + float3 previousMip = Input1.Sample(SamplerLinearClamp, input.TexCoord).rgb; + color += previousMip; + } + + return float4(color, 1.0); +} + + + // Horizontal gaussian blur META_PS(true, FEATURE_LEVEL_ES2) float4 PS_GaussainBlurH(Quad_VS2PS input) : SV_Target @@ -311,6 +512,8 @@ float4 PS_GaussainBlurV(Quad_VS2PS input) : SV_Target return color; } + + // Generate 'ghosts' for lens flare META_PS(true, FEATURE_LEVEL_ES2) float4 PS_Ghosts(Quad_VS2PS input) : SV_Target @@ -350,7 +553,8 @@ float4 PS_Ghosts(Quad_VS2PS input) : SV_Target Input3.Sample(SamplerLinearClamp, offset + ghostVecnNorm * distortion.r).r, Input3.Sample(SamplerLinearClamp, offset + ghostVecnNorm * distortion.g).g, Input3.Sample(SamplerLinearClamp, offset + ghostVecnNorm * distortion.b).b); - color = clamp(color + LensBias, 0, 10) * (LensScale * weight); + color = clamp((color * 1.0f) + LensBias, 0, 10) * (LensScale * weight); + // Accumulate color result += color; @@ -406,6 +610,8 @@ float nrand(float2 n) return frac(sin(dot(n.xy, float2(12.9898, 78.233)))* 43758.5453); } + + // Applies exposure, color grading and tone mapping to the input. // Combines it with the results of the bloom pass and other postFx. META_PS(true, FEATURE_LEVEL_ES2) @@ -452,7 +658,8 @@ float4 PS_Composite(Quad_VS2PS input) : SV_Target color = Input0.Sample(SamplerLinearClamp, uv); } - // Lens Flares + + // Lens Flaresf BRANCH if (LensFlareIntensity > 0) { @@ -470,19 +677,21 @@ float4 PS_Composite(Quad_VS2PS input) : SV_Target lensLight += lensFlares * 1.5f; color.rgb += lensFlares; } + - // Bloom - BRANCH - if (BloomMagnitude > 0) - { - // Sample the bloom - float3 bloom = Input2.SampleLevel(SamplerLinearClamp, uv, 0).rgb; - bloom = bloom * BloomMagnitude; +// In PS_Composite: +BRANCH +if (BloomIntensity > 0) +{ + // Sample the final bloom result + float3 bloom = Input2.Sample(SamplerLinearClamp, input.TexCoord).rgb; + bloom = bloom * BloomIntensity; - // Accumulate final bloom lght - lensLight += max(0, bloom * 3.0f + (- 1.0f * 3.0f)); - color.rgb += bloom; - } + + + lensLight += max(0, bloom * 3.0f + (- 1.0f * 3.0f)); + color.rgb += bloom; +} // Lens Dirt float3 lensDirt = LensDirt.SampleLevel(SamplerLinearClamp, uv, 0).rgb; From 1fac78f48f954b19a77cf2b98275e543e71e112a Mon Sep 17 00:00:00 2001 From: Muzz Date: Tue, 25 Feb 2025 14:49:59 +1000 Subject: [PATCH 2/2] attributes fix --- Source/Engine/Graphics/PostProcessSettings.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Engine/Graphics/PostProcessSettings.h b/Source/Engine/Graphics/PostProcessSettings.h index f2297f240..a8e73f752 100644 --- a/Source/Engine/Graphics/PostProcessSettings.h +++ b/Source/Engine/Graphics/PostProcessSettings.h @@ -464,7 +464,7 @@ API_STRUCT() struct FLAXENGINE_API BloomSettings : ISerializable /// /// Overall bloom effect strength. Higher values create a stronger glow effect. /// - API_FIELD(Attributes "Limit(0, 100.0f, 0.001f), EditorOrder(1), PostProcessSetting((int)BloomSettingsOverride.Intensity)") + API_FIELD(Attributes="Limit(0, 100.0f, 0.001f), EditorOrder(1), PostProcessSetting((int)BloomSettingsOverride.Intensity)") float Intensity = 1.0f; ///