diff --git a/Content/Shaders/GI/DDGI.flax b/Content/Shaders/GI/DDGI.flax index 25b849638..9a21ebf60 100644 --- a/Content/Shaders/GI/DDGI.flax +++ b/Content/Shaders/GI/DDGI.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5d0a6384fca382ceb56dd0623dfef87eec29002f667b0608317f9519b492cfd1 -size 19388 +oid sha256:0cf42c544950dd16b46719bafbcb24ce8fe3a82992aa77c57f8f13c1cb37e72f +size 19671 diff --git a/Content/Shaders/GI/GlobalSurfaceAtlas.flax b/Content/Shaders/GI/GlobalSurfaceAtlas.flax index 8a5772f9e..e3d29362c 100644 --- a/Content/Shaders/GI/GlobalSurfaceAtlas.flax +++ b/Content/Shaders/GI/GlobalSurfaceAtlas.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c34156f4c30f14b6d6bae1505b640d186557060c13bfec5ccf75777ca929c033 -size 11800 +oid sha256:4987c395ab87cedb82dedcab53de0166865a5a2a718aedef8b5bc45060466c9f +size 11862 diff --git a/Source/Editor/CustomEditors/Dedicated/PostProcessSettingsEditor.cs b/Source/Editor/CustomEditors/Dedicated/PostProcessSettingsEditor.cs index 490268ebb..abde71340 100644 --- a/Source/Editor/CustomEditors/Dedicated/PostProcessSettingsEditor.cs +++ b/Source/Editor/CustomEditors/Dedicated/PostProcessSettingsEditor.cs @@ -110,6 +110,25 @@ namespace FlaxEditor.CustomEditors.Dedicated } } + /// + /// Editor for type. + /// + [CustomEditor(typeof(GlobalIlluminationSettings)), DefaultEditor] + sealed class GlobalIlluminationSettingsEditor : PostProcessSettingsEditor + { + /// + protected override int OverrideFlags + { + get => (int)((GlobalIlluminationSettings)Values[0]).OverrideFlags; + set + { + var settings = (GlobalIlluminationSettings)Values[0]; + settings.OverrideFlags = (GlobalIlluminationSettingsOverride)value; + SetValue(settings); + } + } + } + /// /// Editor for type. /// diff --git a/Source/Editor/Windows/GraphicsQualityWindow.cs b/Source/Editor/Windows/GraphicsQualityWindow.cs index 3442a4e7c..957d1af1a 100644 --- a/Source/Editor/Windows/GraphicsQualityWindow.cs +++ b/Source/Editor/Windows/GraphicsQualityWindow.cs @@ -72,6 +72,14 @@ namespace FlaxEditor.Windows set => Graphics.GlobalSDFQuality = value; } + [DefaultValue(Quality.High)] + [EditorOrder(1290), EditorDisplay("Quality"), Tooltip("The Global Illumination quality. Controls the quality of the GI effect.")] + public Quality GIQuality + { + get => Graphics.GIQuality; + set => Graphics.GIQuality = value; + } + [DefaultValue(Quality.Medium)] [EditorOrder(1300), EditorDisplay("Quality", "Shadows Quality"), Tooltip("The shadows quality.")] public Quality ShadowsQuality diff --git a/Source/Engine/Core/Config/GraphicsSettings.cpp b/Source/Engine/Core/Config/GraphicsSettings.cpp index f3e08b63b..654e671db 100644 --- a/Source/Engine/Core/Config/GraphicsSettings.cpp +++ b/Source/Engine/Core/Config/GraphicsSettings.cpp @@ -14,4 +14,5 @@ void GraphicsSettings::Apply() Graphics::ShadowMapsQuality = ShadowMapsQuality; Graphics::AllowCSMBlending = AllowCSMBlending; Graphics::GlobalSDFQuality = GlobalSDFQuality; + Graphics::GIQuality = GIQuality; } diff --git a/Source/Engine/Core/Config/GraphicsSettings.h b/Source/Engine/Core/Config/GraphicsSettings.h index 0ec2b26b1..85caf77d8 100644 --- a/Source/Engine/Core/Config/GraphicsSettings.h +++ b/Source/Engine/Core/Config/GraphicsSettings.h @@ -82,6 +82,12 @@ public: bool GenerateSDFOnModelImport = false; #endif + /// + /// The Global Illumination quality. Controls the quality of the GI effect. + /// + API_FIELD(Attributes="EditorOrder(2100), DefaultValue(Quality.High), EditorDisplay(\"Quality\")") + Quality GIQuality = Quality::High; + public: /// /// Gets the instance of the settings asset (default value if missing). Object returned by this method is always loaded with valid data to use. diff --git a/Source/Engine/Graphics/Graphics.cpp b/Source/Engine/Graphics/Graphics.cpp index 4cdbf9eb2..f1baee478 100644 --- a/Source/Engine/Graphics/Graphics.cpp +++ b/Source/Engine/Graphics/Graphics.cpp @@ -15,6 +15,7 @@ Quality Graphics::ShadowsQuality = Quality::Medium; Quality Graphics::ShadowMapsQuality = Quality::Medium; bool Graphics::AllowCSMBlending = false; Quality Graphics::GlobalSDFQuality = Quality::High; +Quality Graphics::GIQuality = Quality::High; #if GRAPHICS_API_NULL extern GPUDevice* CreateGPUDeviceNull(); diff --git a/Source/Engine/Graphics/Graphics.h b/Source/Engine/Graphics/Graphics.h index a39c89fd9..01fa60749 100644 --- a/Source/Engine/Graphics/Graphics.h +++ b/Source/Engine/Graphics/Graphics.h @@ -58,6 +58,11 @@ public: /// API_FIELD() static Quality GlobalSDFQuality; + /// + /// The Global Illumination quality. Controls the quality of the GI effect. + /// + API_FIELD() static Quality GIQuality; + public: /// diff --git a/Source/Engine/Graphics/PostProcessSettings.cpp b/Source/Engine/Graphics/PostProcessSettings.cpp index b15cb70d1..0ea38d354 100644 --- a/Source/Engine/Graphics/PostProcessSettings.cpp +++ b/Source/Engine/Graphics/PostProcessSettings.cpp @@ -8,6 +8,7 @@ #define BLEND_FLOAT(name) if ((((int32)other.OverrideFlags & (int32)Override::name) != 0)) name = Math::Lerp(name, other.name, weight) #define BLEND_INT(name) BLEND_FLOAT(name) #define BLEND_VEC3(name) if ((((int32)other.OverrideFlags & (int32)Override::name) != 0)) name = Vector3::Lerp(name, other.name, weight) +#define BLEND_COL(name) if ((((int32)other.OverrideFlags & (int32)Override::name) != 0)) name = Color::Lerp(name, other.name, weight) #define BLEND_ENUM(name) BLEND_BOOL(name) #define BLEND_PROPERTY(name) BLEND_BOOL(name) @@ -23,6 +24,16 @@ void AmbientOcclusionSettings::BlendWith(AmbientOcclusionSettings& other, float BLEND_FLOAT(FadeDistance); } +void GlobalIlluminationSettings::BlendWith(GlobalIlluminationSettings& other, float weight) +{ + const bool isHalf = weight >= 0.5f; + BLEND_BOOL(Mode); + BLEND_FLOAT(Intensity); + BLEND_FLOAT(TemporalResponse); + BLEND_FLOAT(Distance); + BLEND_COL(FallbackIrradiance); +} + void BloomSettings::BlendWith(BloomSettings& other, float weight) { const bool isHalf = weight >= 0.5f; @@ -209,6 +220,7 @@ void PostFxMaterialsSettings::BlendWith(PostFxMaterialsSettings& other, float we void PostProcessSettings::BlendWith(PostProcessSettings& other, float weight) { AmbientOcclusion.BlendWith(other.AmbientOcclusion, weight); + GlobalIllumination.BlendWith(other.GlobalIllumination, weight); Bloom.BlendWith(other.Bloom, weight); ToneMapping.BlendWith(other.ToneMapping, weight); ColorGrading.BlendWith(other.ColorGrading, weight); @@ -251,6 +263,9 @@ void PostProcessSettings::Serialize(SerializeStream& stream, const void* otherOb stream.JKEY("AO"); stream.Object(&AmbientOcclusion, other ? &other->AmbientOcclusion : nullptr); + + stream.JKEY("GI"); + stream.Object(&GlobalIllumination, other ? &other->GlobalIllumination : nullptr); stream.JKEY("Bloom"); stream.Object(&Bloom, other ? &other->Bloom : nullptr); @@ -289,6 +304,7 @@ void PostProcessSettings::Serialize(SerializeStream& stream, const void* otherOb void PostProcessSettings::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) { AmbientOcclusion.DeserializeIfExists(stream, "AO", modifier); + GlobalIllumination.DeserializeIfExists(stream, "GI", modifier); Bloom.DeserializeIfExists(stream, "Bloom", modifier); ToneMapping.DeserializeIfExists(stream, "ToneMapping", modifier); ColorGrading.DeserializeIfExists(stream, "ColorGrading", modifier); diff --git a/Source/Engine/Graphics/PostProcessSettings.h b/Source/Engine/Graphics/PostProcessSettings.h index f1c9a353f..4afa62835 100644 --- a/Source/Engine/Graphics/PostProcessSettings.h +++ b/Source/Engine/Graphics/PostProcessSettings.h @@ -9,6 +9,27 @@ #include "Engine/Content/Assets/Texture.h" #include "Engine/Content/Assets/MaterialBase.h" +/// +/// Global Illumination effect rendering modes. +/// +API_ENUM() enum class GlobalIlluminationMode +{ + /// + /// Disabled GI effect. + /// + None = 0, + + /// + /// Dynamic Diffuse Global Illumination algorithm with scrolling probes volume (with cascades). Uses software raytracing - requires Global SDF and Global Surface Atlas. + /// + DDGI = 1, + + /// + /// The custom GI algorithm - plugged-in externally. + /// + Custom = 2, +}; + /// /// Tone mapping effect rendering modes. /// @@ -183,8 +204,8 @@ API_ENUM(Attributes="Flags") enum class AmbientOcclusionSettingsOverride : int32 /// API_STRUCT() struct FLAXENGINE_API AmbientOcclusionSettings : ISerializable { -API_AUTO_SERIALIZATION(); -DECLARE_SCRIPTING_TYPE_NO_SPAWN(AmbientOcclusionSettings); + API_AUTO_SERIALIZATION(); + DECLARE_SCRIPTING_TYPE_NO_SPAWN(AmbientOcclusionSettings); typedef AmbientOcclusionSettingsOverride Override; /// @@ -230,7 +251,6 @@ DECLARE_SCRIPTING_TYPE_NO_SPAWN(AmbientOcclusionSettings); float FadeDistance = 500.0f; public: - /// /// Blends the settings using given weight. /// @@ -239,6 +259,101 @@ public: void BlendWith(AmbientOcclusionSettings& other, float weight); }; +/// +/// The structure members override flags. +/// +API_ENUM(Attributes="Flags") enum class GlobalIlluminationSettingsOverride : int32 +{ + /// + /// None properties. + /// + None = 0, + + /// + /// Overrides property. + /// + Mode = 1 << 0, + + /// + /// Overrides property. + /// + Intensity = 1 << 1, + + /// + /// Overrides property. + /// + TemporalResponse = 1 << 2, + + /// + /// Overrides property. + /// + Distance = 1 << 3, + + /// + /// Overrides property. + /// + FallbackIrradiance = 1 << 4, + + /// + /// All properties. + /// + All = Mode | Intensity | TemporalResponse | Distance | FallbackIrradiance, +}; + +/// +/// Contains settings for Global Illumination effect rendering. +/// +API_STRUCT() struct FLAXENGINE_API GlobalIlluminationSettings : ISerializable +{ + API_AUTO_SERIALIZATION(); + DECLARE_SCRIPTING_TYPE_NO_SPAWN(GlobalIlluminationSettings); + typedef GlobalIlluminationSettingsOverride Override; + + /// + /// The flags for overriden properties. + /// + API_FIELD(Attributes="HideInEditor") + GlobalIlluminationSettingsOverride OverrideFlags = Override::None; + + /// + /// The Global Illumination mode to use. + /// + API_FIELD(Attributes="EditorOrder(0), PostProcessSetting((int)GlobalIlluminationSettingsOverride.Mode)") + 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; + + /// + /// Defines how quickly GI blends between the 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.8f; + + /// + /// 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; + + /// + /// 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; + +public: + /// + /// Blends the settings using given weight. + /// + /// The other settings. + /// The blend weight. + void BlendWith(GlobalIlluminationSettings& other, float weight); +}; + /// /// The structure members override flags. /// @@ -285,8 +400,8 @@ API_ENUM(Attributes="Flags") enum class BloomSettingsOverride : int32 /// API_STRUCT() struct FLAXENGINE_API BloomSettings : ISerializable { -API_AUTO_SERIALIZATION(); -DECLARE_SCRIPTING_TYPE_NO_SPAWN(BloomSettings); + API_AUTO_SERIALIZATION(); + DECLARE_SCRIPTING_TYPE_NO_SPAWN(BloomSettings); typedef BloomSettingsOverride Override; /// @@ -326,7 +441,6 @@ DECLARE_SCRIPTING_TYPE_NO_SPAWN(BloomSettings); float Limit = 10.0f; public: - /// /// Blends the settings using given weight. /// @@ -371,8 +485,8 @@ API_ENUM(Attributes="Flags") enum class ToneMappingSettingsOverride : int32 /// API_STRUCT() struct FLAXENGINE_API ToneMappingSettings : ISerializable { -API_AUTO_SERIALIZATION(); -DECLARE_SCRIPTING_TYPE_NO_SPAWN(ToneMappingSettings); + API_AUTO_SERIALIZATION(); + DECLARE_SCRIPTING_TYPE_NO_SPAWN(ToneMappingSettings); typedef ToneMappingSettingsOverride Override; /// @@ -400,7 +514,6 @@ DECLARE_SCRIPTING_TYPE_NO_SPAWN(ToneMappingSettings); ToneMappingMode Mode = ToneMappingMode::ACES; public: - /// /// Blends the settings using given weight. /// @@ -550,8 +663,8 @@ API_ENUM(Attributes="Flags") enum class ColorGradingSettingsOverride : int32 /// API_STRUCT() struct FLAXENGINE_API ColorGradingSettings : ISerializable { -API_AUTO_SERIALIZATION(); -DECLARE_SCRIPTING_TYPE_NO_SPAWN(ColorGradingSettings); + API_AUTO_SERIALIZATION(); + DECLARE_SCRIPTING_TYPE_NO_SPAWN(ColorGradingSettings); typedef ColorGradingSettingsOverride Override; /// @@ -717,7 +830,6 @@ DECLARE_SCRIPTING_TYPE_NO_SPAWN(ColorGradingSettings); float LutWeight = 1.0f; public: - /// /// Blends the settings using given weight. /// @@ -792,8 +904,8 @@ API_ENUM(Attributes="Flags") enum class EyeAdaptationSettingsOverride : int32 /// API_STRUCT() struct FLAXENGINE_API EyeAdaptationSettings : ISerializable { -API_AUTO_SERIALIZATION(); -DECLARE_SCRIPTING_TYPE_NO_SPAWN(EyeAdaptationSettings); + API_AUTO_SERIALIZATION(); + DECLARE_SCRIPTING_TYPE_NO_SPAWN(EyeAdaptationSettings); typedef EyeAdaptationSettingsOverride Override; /// @@ -857,7 +969,6 @@ DECLARE_SCRIPTING_TYPE_NO_SPAWN(EyeAdaptationSettings); float HistogramHighPercent = 98.0f; public: - /// /// Blends the settings using given weight. /// @@ -927,8 +1038,8 @@ API_ENUM(Attributes="Flags") enum class CameraArtifactsSettingsOverride : int32 /// API_STRUCT() struct FLAXENGINE_API CameraArtifactsSettings : ISerializable { -API_AUTO_SERIALIZATION(); -DECLARE_SCRIPTING_TYPE_NO_SPAWN(CameraArtifactsSettings); + API_AUTO_SERIALIZATION(); + DECLARE_SCRIPTING_TYPE_NO_SPAWN(CameraArtifactsSettings); typedef CameraArtifactsSettingsOverride Override; /// @@ -986,7 +1097,6 @@ DECLARE_SCRIPTING_TYPE_NO_SPAWN(CameraArtifactsSettings); Color ScreenFadeColor = Color::Transparent; public: - /// /// Blends the settings using given weight. /// @@ -1076,8 +1186,8 @@ API_ENUM(Attributes="Flags") enum class LensFlaresSettingsOverride : int32 /// API_STRUCT() struct FLAXENGINE_API LensFlaresSettings : ISerializable { -API_AUTO_SERIALIZATION(); -DECLARE_SCRIPTING_TYPE_NO_SPAWN(LensFlaresSettings); + API_AUTO_SERIALIZATION(); + DECLARE_SCRIPTING_TYPE_NO_SPAWN(LensFlaresSettings); typedef LensFlaresSettingsOverride Override; /// @@ -1159,7 +1269,6 @@ DECLARE_SCRIPTING_TYPE_NO_SPAWN(LensFlaresSettings); AssetReference LensStar; public: - /// /// Blends the settings using given weight. /// @@ -1269,8 +1378,8 @@ API_ENUM(Attributes="Flags") enum class DepthOfFieldSettingsOverride : int32 /// API_STRUCT() struct FLAXENGINE_API DepthOfFieldSettings : ISerializable { -API_AUTO_SERIALIZATION(); -DECLARE_SCRIPTING_TYPE_NO_SPAWN(DepthOfFieldSettings); + API_AUTO_SERIALIZATION(); + DECLARE_SCRIPTING_TYPE_NO_SPAWN(DepthOfFieldSettings); typedef DepthOfFieldSettingsOverride Override; /// @@ -1376,7 +1485,6 @@ DECLARE_SCRIPTING_TYPE_NO_SPAWN(DepthOfFieldSettings); float BokehDepthCutoff = 1.5f; public: - /// /// Blends the settings using given weight. /// @@ -1426,8 +1534,8 @@ API_ENUM(Attributes="Flags") enum class MotionBlurSettingsOverride : int32 /// API_STRUCT() struct FLAXENGINE_API MotionBlurSettings : ISerializable { -API_AUTO_SERIALIZATION(); -DECLARE_SCRIPTING_TYPE_NO_SPAWN(MotionBlurSettings); + API_AUTO_SERIALIZATION(); + DECLARE_SCRIPTING_TYPE_NO_SPAWN(MotionBlurSettings); typedef MotionBlurSettingsOverride Override; /// @@ -1461,7 +1569,6 @@ DECLARE_SCRIPTING_TYPE_NO_SPAWN(MotionBlurSettings); ResolutionMode MotionVectorsResolution = ResolutionMode::Half; public: - /// /// Blends the settings using given weight. /// @@ -1566,8 +1673,8 @@ API_ENUM(Attributes="Flags") enum class ScreenSpaceReflectionsSettingsOverride : /// API_STRUCT() struct FLAXENGINE_API ScreenSpaceReflectionsSettings : ISerializable { -API_AUTO_SERIALIZATION(); -DECLARE_SCRIPTING_TYPE_NO_SPAWN(ScreenSpaceReflectionsSettings); + API_AUTO_SERIALIZATION(); + DECLARE_SCRIPTING_TYPE_NO_SPAWN(ScreenSpaceReflectionsSettings); typedef ScreenSpaceReflectionsSettingsOverride Override; /// @@ -1667,7 +1774,6 @@ DECLARE_SCRIPTING_TYPE_NO_SPAWN(ScreenSpaceReflectionsSettings); float TemporalResponse = 0.8f; public: - /// /// Blends the settings using given weight. /// @@ -1722,8 +1828,8 @@ API_ENUM(Attributes="Flags") enum class AntiAliasingSettingsOverride : int32 /// API_STRUCT() struct FLAXENGINE_API AntiAliasingSettings : ISerializable { -API_AUTO_SERIALIZATION(); -DECLARE_SCRIPTING_TYPE_NO_SPAWN(AntiAliasingSettings); + API_AUTO_SERIALIZATION(); + DECLARE_SCRIPTING_TYPE_NO_SPAWN(AntiAliasingSettings); typedef AntiAliasingSettingsOverride Override; /// @@ -1763,7 +1869,6 @@ DECLARE_SCRIPTING_TYPE_NO_SPAWN(AntiAliasingSettings); float TAA_MotionBlending = 0.4f; public: - /// /// Blends the settings using given weight. /// @@ -1777,8 +1882,8 @@ public: /// API_STRUCT() struct FLAXENGINE_API PostFxMaterialsSettings : ISerializable { -API_AUTO_SERIALIZATION(); -DECLARE_SCRIPTING_TYPE_NO_SPAWN(PostFxMaterialsSettings); + API_AUTO_SERIALIZATION(); + DECLARE_SCRIPTING_TYPE_NO_SPAWN(PostFxMaterialsSettings); /// /// The post-process materials collection for rendering (fixed capacity). @@ -1787,7 +1892,6 @@ DECLARE_SCRIPTING_TYPE_NO_SPAWN(PostFxMaterialsSettings); Array, FixedAllocation> Materials; public: - /// /// Blends the settings using given weight. /// @@ -1801,7 +1905,7 @@ public: /// API_STRUCT() struct FLAXENGINE_API PostProcessSettings : ISerializable { -DECLARE_SCRIPTING_TYPE_NO_SPAWN(PostProcessSettings); + DECLARE_SCRIPTING_TYPE_NO_SPAWN(PostProcessSettings); /// /// The ambient occlusion effect settings. @@ -1809,6 +1913,12 @@ DECLARE_SCRIPTING_TYPE_NO_SPAWN(PostProcessSettings); API_FIELD() AmbientOcclusionSettings AmbientOcclusion; + /// + /// The global illumination effect settings. + /// + API_FIELD() + GlobalIlluminationSettings GlobalIllumination; + /// /// The bloom effect settings. /// @@ -1876,7 +1986,6 @@ DECLARE_SCRIPTING_TYPE_NO_SPAWN(PostProcessSettings); PostFxMaterialsSettings PostFxMaterials; public: - /// /// Blends the settings using given weight. /// @@ -1891,13 +2000,13 @@ public: bool HasContentLoaded() const; public: - // [ISerializable] void Serialize(SerializeStream& stream, const void* otherObj) override; void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override; }; DECLARE_ENUM_OPERATORS(AmbientOcclusionSettingsOverride); +DECLARE_ENUM_OPERATORS(GlobalIlluminationSettingsOverride); DECLARE_ENUM_OPERATORS(BloomSettingsOverride); DECLARE_ENUM_OPERATORS(ToneMappingSettingsOverride); DECLARE_ENUM_OPERATORS(ColorGradingSettingsOverride); diff --git a/Source/Engine/Level/Actors/PostFxVolume.cpp b/Source/Engine/Level/Actors/PostFxVolume.cpp index c66d3fc45..52abe59e5 100644 --- a/Source/Engine/Level/Actors/PostFxVolume.cpp +++ b/Source/Engine/Level/Actors/PostFxVolume.cpp @@ -43,6 +43,7 @@ void PostFxVolume::Collect(RenderContext& renderContext) void PostFxVolume::Blend(PostProcessSettings& other, float weight) { other.AmbientOcclusion.BlendWith(AmbientOcclusion, weight); + other.GlobalIllumination.BlendWith(GlobalIllumination, weight); other.Bloom.BlendWith(Bloom, weight); other.ToneMapping.BlendWith(ToneMapping, weight); other.ColorGrading.BlendWith(ColorGrading, weight); @@ -118,6 +119,9 @@ void PostFxVolume::Serialize(SerializeStream& stream, const void* otherObj) stream.JKEY("AO"); stream.Object(&AmbientOcclusion, other ? &other->AmbientOcclusion : nullptr); + stream.JKEY("GI"); + stream.Object(&GlobalIllumination, other ? &other->GlobalIllumination : nullptr); + stream.JKEY("Bloom"); stream.Object(&Bloom, other ? &other->Bloom : nullptr); @@ -169,6 +173,7 @@ void PostFxVolume::Deserialize(DeserializeStream& stream, ISerializeModifier* mo { auto& settingsStream = settingsMember->value; AmbientOcclusion.DeserializeIfExists(settingsStream, "AO", modifier); + GlobalIllumination.DeserializeIfExists(settingsStream, "GI", modifier); Bloom.DeserializeIfExists(settingsStream, "Bloom", modifier); ToneMapping.DeserializeIfExists(settingsStream, "ToneMapping", modifier); ColorGrading.DeserializeIfExists(settingsStream, "ColorGrading", modifier); diff --git a/Source/Engine/Level/Actors/PostFxVolume.h b/Source/Engine/Level/Actors/PostFxVolume.h index 2b5d0b9f6..b7764ce3b 100644 --- a/Source/Engine/Level/Actors/PostFxVolume.h +++ b/Source/Engine/Level/Actors/PostFxVolume.h @@ -27,6 +27,12 @@ public: API_FIELD(Attributes="EditorDisplay(\"Ambient Occlusion\"), EditorOrder(100)") AmbientOcclusionSettings AmbientOcclusion; + /// + /// The Global Illumination effect settings. + /// + API_FIELD(Attributes="EditorDisplay(\"Global Illumination\"), EditorOrder(150)") + GlobalIlluminationSettings GlobalIllumination; + /// /// The bloom effect settings. /// diff --git a/Source/Engine/Renderer/GI/DynamicDiffuseGlobalIllumination.cpp b/Source/Engine/Renderer/GI/DynamicDiffuseGlobalIllumination.cpp index 0e2a9ce7a..7bf9a7cfc 100644 --- a/Source/Engine/Renderer/GI/DynamicDiffuseGlobalIllumination.cpp +++ b/Source/Engine/Renderer/GI/DynamicDiffuseGlobalIllumination.cpp @@ -14,6 +14,7 @@ #include "Engine/Debug/DebugDraw.h" #include "Engine/Engine/Time.h" #include "Engine/Graphics/GPUDevice.h" +#include "Engine/Graphics/Graphics.h" #include "Engine/Graphics/RenderTask.h" #include "Engine/Graphics/RenderBuffers.h" #include "Engine/Graphics/RenderTargetPool.h" @@ -45,10 +46,9 @@ PACK_STRUCT(struct Data0 GlobalSignDistanceFieldPass::ConstantsData GlobalSDF; GlobalSurfaceAtlasPass::ConstantsData GlobalSurfaceAtlas; GBufferData GBuffer; + Vector2 Padding0; float ResetBlend; float TemporalTime; - float IndirectLightingIntensity; - float Padding0; }); PACK_STRUCT(struct Data1 @@ -266,22 +266,52 @@ bool DynamicDiffuseGlobalIlluminationPass::Render(RenderContext& renderContext, ddgiData.LastFrameUsed = currentFrame; PROFILE_GPU_CPU("Dynamic Diffuse Global Illumination"); - // TODO: configurable via graphics settings - const Quality quality = Quality::Ultra; + // Setup options + auto& settings = renderContext.List->Settings.GlobalIllumination; + // TODO: implement GI Quality to affect cascades update rate, probes spacing and rays count per probe + const float probesSpacing = 100.0f; // GI probes placement spacing nearby camera (for closest cascade; gets automatically reduced for further cascades) + switch (Graphics::GIQuality) + { + case Quality::Low: + break; + case Quality::Medium: + break; + case Quality::High: + break; + case Quality::Ultra: + default: + break; + } bool debugProbes = false; // TODO: add debug option to draw probes locations -> in Graphics window - Editor-only - // TODO: configurable via postFx settings (maybe use Global SDF distance?) - const float indirectLightingIntensity = 1.0f; - const float probeHistoryWeight = 0.8f; - const int32 cascadesCount = 4; // in range 1-4 - // TODO: use GI.Distance as a easier to adjust total distance and automatically calculate distanceExtent from it - const float distance = 20000.0f; // GI distance around the view (in each direction) + const float indirectLightingIntensity = settings.Intensity; + const float probeHistoryWeight = Math::Clamp(settings.TemporalResponse, 0.0f, 0.98f); + const float distance = settings.Distance; + const Color fallbackIrradiance = settings.FallbackIrradiance; + const int32 probeRaysCount = Math::Min(Math::AlignUp(256, DDGI_TRACE_RAYS_GROUP_SIZE_X), DDGI_TRACE_RAYS_LIMIT); // TODO: make it based on the GI Quality + + // Automatically calculate amount of cascades to cover the GI distance at the current probes spacing + const int32 idealProbesCount = 20; // Ideal amount of probes per-cascade to try to fit in order to cover whole distance + int32 cascadesCount = 1; + float idealDistance = idealProbesCount * probesSpacing; + while (cascadesCount < 4 && idealDistance < distance) + { + idealDistance *= 2; + cascadesCount++; + } + + // Calculate the probes count based on the amount of cascades and the distance to cover const float cascadesDistanceScales[] = { 1.0f, 3.0f, 6.0f, 10.0f }; // Scales each cascade further away from the camera origin const float distanceExtent = distance / cascadesDistanceScales[cascadesCount - 1]; const float verticalRangeScale = 0.8f; // Scales the probes volume size at Y axis (horizontal aspect ratio makes the DDGI use less probes vertically to cover whole screen) - const float probesSpacing = 200.0f; // GI probes placement spacing nearby camera (for closest cascade; gets automatically reduced for further cascades) - const Color fallbackIrradiance = Color::Black; // Irradiance lighting outside the DDGI range used as a fallback to prevent pure-black scene outside the GI range - const Int3 probesCounts(Vector3::Ceil(Vector3(distanceExtent, distanceExtent * verticalRangeScale, distanceExtent) / probesSpacing)); - const int32 probeRaysCount = Math::Min(Math::AlignUp(256, DDGI_TRACE_RAYS_GROUP_SIZE_X), DDGI_TRACE_RAYS_LIMIT); // TODO: make it based on the GI Quality + Int3 probesCounts(Vector3::Ceil(Vector3(distanceExtent, distanceExtent * verticalRangeScale, distanceExtent) / probesSpacing)); + const int32 maxProbeSize = Math::Max(DDGI_PROBE_RESOLUTION_IRRADIANCE, DDGI_PROBE_RESOLUTION_DISTANCE) + 2; + const int32 maxTextureSize = Math::Min(GPUDevice::Instance->Limits.MaximumTexture2DSize, GPU_MAX_TEXTURE_SIZE); + while (probesCounts.X * probesCounts.Y * maxProbeSize > maxTextureSize + || probesCounts.Z * cascadesCount * maxProbeSize > maxTextureSize) + { + // Decrease quality to ensure the probes texture won't overflow + probesCounts -= 1; + } // Initialize cascades float probesSpacings[4]; @@ -417,6 +447,7 @@ bool DynamicDiffuseGlobalIlluminationPass::Render(RenderContext& renderContext, ddgiData.Result.Constants.RaysCount = probeRaysCount; ddgiData.Result.Constants.ProbeHistoryWeight = probeHistoryWeight; ddgiData.Result.Constants.IrradianceGamma = 5.0f; + ddgiData.Result.Constants.IndirectLightingIntensity = indirectLightingIntensity; ddgiData.Result.Constants.FallbackIrradiance = fallbackIrradiance.ToVector3() * fallbackIrradiance.A; ddgiData.Result.ProbesState = ddgiData.ProbesState->View(); ddgiData.Result.ProbesDistance = ddgiData.ProbesDistance->View(); @@ -446,7 +477,6 @@ bool DynamicDiffuseGlobalIlluminationPass::Render(RenderContext& renderContext, { data.TemporalTime = 0.0f; } - data.IndirectLightingIntensity = indirectLightingIntensity; GBufferPass::SetInputs(renderContext.View, data.GBuffer); context->UpdateCB(_cb0, &data); context->BindCB(0, _cb0); diff --git a/Source/Engine/Renderer/GI/DynamicDiffuseGlobalIllumination.h b/Source/Engine/Renderer/GI/DynamicDiffuseGlobalIllumination.h index 35158a7bc..09e6b7bd6 100644 --- a/Source/Engine/Renderer/GI/DynamicDiffuseGlobalIllumination.h +++ b/Source/Engine/Renderer/GI/DynamicDiffuseGlobalIllumination.h @@ -23,12 +23,12 @@ public: float IrradianceGamma; float ProbeHistoryWeight; float RayMaxDistance; - float Padding0; + float IndirectLightingIntensity; Vector4 RaysRotation; Vector3 ViewDir; uint32 RaysCount; Vector3 FallbackIrradiance; - float Padding1; + float Padding0; }); // Binding data for the GPU. diff --git a/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp b/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp index 446981076..9ede2ca62 100644 --- a/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp +++ b/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp @@ -343,11 +343,12 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co surfaceAtlasData.LastFrameUsed = currentFrame; PROFILE_GPU_CPU("Global Surface Atlas"); + // Setup options // TODO: configurable via graphics settings const int32 resolution = 2048; const float resolutionInv = 1.0f / resolution; - // TODO: configurable via postFx settings (use GI distance) - const float distance = 20000.0f; + auto& giSettings = renderContext.List->Settings.GlobalIllumination; + const float distance = giSettings.Distance; // Initialize buffers bool noCache = surfaceAtlasData.Resolution != resolution; @@ -847,32 +848,36 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co } if (renderContext.View.Flags & ViewFlags::GI) { - // TODO: add option to PostFx Volume for realtime GI type (None, DDGI) - DynamicDiffuseGlobalIlluminationPass::BindingData bindingDataDDGI; - if (!DynamicDiffuseGlobalIlluminationPass::Instance()->Get(renderContext.Buffers, bindingDataDDGI)) + // Draw draw indirect light from Global Illumination + switch (renderContext.List->Settings.GlobalIllumination.Mode) { - // Collect tiles to shade - _vertexBuffer->Clear(); - for (const auto& e : surfaceAtlasData.Objects) + case GlobalIlluminationMode::DDGI: + { + DynamicDiffuseGlobalIlluminationPass::BindingData bindingDataDDGI; + if (!DynamicDiffuseGlobalIlluminationPass::Instance()->Get(renderContext.Buffers, bindingDataDDGI)) { - const auto& object = e.Value; - for (int32 tileIndex = 0; tileIndex < 6; tileIndex++) + _vertexBuffer->Clear(); + for (const auto& e : surfaceAtlasData.Objects) { - auto* tile = object.Tiles[tileIndex]; - if (!tile) - continue; - VB_WRITE_TILE(tile); + const auto& object = e.Value; + for (int32 tileIndex = 0; tileIndex < 6; tileIndex++) + { + auto* tile = object.Tiles[tileIndex]; + if (!tile) + continue; + VB_WRITE_TILE(tile); + } } + data.DDGI = bindingDataDDGI.Constants; + context->BindSR(5, bindingDataDDGI.ProbesState); + context->BindSR(6, bindingDataDDGI.ProbesDistance); + context->BindSR(7, bindingDataDDGI.ProbesIrradiance); + context->UpdateCB(_cb0, &data); + context->SetState(_psIndirectLighting); + VB_DRAW(); } - - // Draw draw indirect light - data.DDGI = bindingDataDDGI.Constants; - context->BindSR(5, bindingDataDDGI.ProbesState); - context->BindSR(6, bindingDataDDGI.ProbesDistance); - context->BindSR(7, bindingDataDDGI.ProbesIrradiance); - context->UpdateCB(_cb0, &data); - context->SetState(_psIndirectLighting); - VB_DRAW(); + break; + } } } @@ -888,11 +893,15 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co void GlobalSurfaceAtlasPass::RenderDebug(RenderContext& renderContext, GPUContext* context, GPUTexture* output) { - // Render all dependant effects + // Render all dependant effects before if (renderContext.View.Flags & ViewFlags::GI) { - // TODO: add option to PostFx Volume for realtime GI type (None, DDGI) - DynamicDiffuseGlobalIlluminationPass::Instance()->Render(renderContext, context, nullptr); + switch (renderContext.List->Settings.GlobalIllumination.Mode) + { + case GlobalIlluminationMode::DDGI: + DynamicDiffuseGlobalIlluminationPass::Instance()->Render(renderContext, context, nullptr); + break; + } } GlobalSignDistanceFieldPass::BindingData bindingDataSDF; BindingData bindingData; diff --git a/Source/Engine/Renderer/GlobalSignDistanceFieldPass.cpp b/Source/Engine/Renderer/GlobalSignDistanceFieldPass.cpp index 3f566c45b..b80fc7a0a 100644 --- a/Source/Engine/Renderer/GlobalSignDistanceFieldPass.cpp +++ b/Source/Engine/Renderer/GlobalSignDistanceFieldPass.cpp @@ -416,7 +416,8 @@ bool GlobalSignDistanceFieldPass::Render(RenderContext& renderContext, GPUContex break; } const int32 resolutionMip = Math::DivideAndRoundUp(resolution, GLOBAL_SDF_RASTERIZE_MIP_FACTOR); - const float distance = true ? 20000.0f : 16000.0f; // TODO: switch based if using GI, then use GI range + auto& giSettings = renderContext.List->Settings.GlobalIllumination; + const float distance = giSettings.Mode == GlobalIlluminationMode::DDGI ? giSettings.Distance : 15000.0f; const float cascadesDistanceScales[] = { 1.0f, 2.5f, 5.0f, 10.0f }; const float distanceExtent = distance / cascadesDistanceScales[cascadesCount - 1]; diff --git a/Source/Engine/Renderer/Renderer.cpp b/Source/Engine/Renderer/Renderer.cpp index ea3d127f0..e59694ecd 100644 --- a/Source/Engine/Renderer/Renderer.cpp +++ b/Source/Engine/Renderer/Renderer.cpp @@ -401,8 +401,12 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext) LightPass::Instance()->RenderLight(renderContext, *lightBuffer); if (renderContext.View.Flags & ViewFlags::GI) { - // TODO: add option to PostFx Volume for realtime GI type (None, DDGI) - DynamicDiffuseGlobalIlluminationPass::Instance()->Render(renderContext, context, *lightBuffer); + switch (renderContext.List->Settings.GlobalIllumination.Mode) + { + case GlobalIlluminationMode::DDGI: + DynamicDiffuseGlobalIlluminationPass::Instance()->Render(renderContext, context, *lightBuffer); + break; + } } if (renderContext.View.Mode == ViewMode::LightBuffer) { diff --git a/Source/Shaders/GI/DDGI.hlsl b/Source/Shaders/GI/DDGI.hlsl index 7aaf6527b..c40e414f3 100644 --- a/Source/Shaders/GI/DDGI.hlsl +++ b/Source/Shaders/GI/DDGI.hlsl @@ -30,12 +30,12 @@ struct DDGIData float IrradianceGamma; float ProbeHistoryWeight; float RayMaxDistance; - float Padding0; + float IndirectLightingIntensity; float4 RaysRotation; float3 ViewDir; uint RaysCount; float3 FallbackIrradiance; - float Padding1; + float Padding0; }; uint GetDDGIProbeIndex(DDGIData data, uint3 probeCoords) diff --git a/Source/Shaders/GI/DDGI.shader b/Source/Shaders/GI/DDGI.shader index 70cb92834..cb3aaaf04 100644 --- a/Source/Shaders/GI/DDGI.shader +++ b/Source/Shaders/GI/DDGI.shader @@ -27,10 +27,9 @@ DDGIData DDGI; GlobalSDFData GlobalSDF; GlobalSurfaceAtlasData GlobalSurfaceAtlas; GBufferData GBuffer; +float2 Padding0; float ResetBlend; float TemporalTime; -float IndirectLightingIntensity; -float2 Padding0; META_CB_END META_CB_BEGIN(1, Data1) @@ -343,7 +342,7 @@ void CS_UpdateProbes(uint3 GroupThreadId : SV_GroupThreadID, uint3 GroupId : SV_ if (ResetBlend || dot(previous, previous) == 0) historyWeight = 0.0f; #if DDGI_PROBE_UPDATE_MODE == 0 - result *= IndirectLightingIntensity; + result *= DDGI.IndirectLightingIntensity; #if DDGI_SRGB_BLENDING result.rgb = pow(result.rgb, 1.0f / DDGI.IrradianceGamma); #endif diff --git a/Source/Shaders/GI/GlobalSurfaceAtlas.shader b/Source/Shaders/GI/GlobalSurfaceAtlas.shader index 30f455675..7ae54ed83 100644 --- a/Source/Shaders/GI/GlobalSurfaceAtlas.shader +++ b/Source/Shaders/GI/GlobalSurfaceAtlas.shader @@ -120,6 +120,7 @@ float4 PS_Lighting(AtlasVertexOutput input) : SV_Target // Sample irradiance float bias = 1.0f; float3 irradiance = SampleDDGIIrradiance(DDGI, ProbesState, ProbesDistance, ProbesIrradiance, gBuffer.WorldPos, gBuffer.Normal, bias); + irradiance /= DDGI.IndirectLightingIntensity; //irradiance = 0; // Calculate lighting