From 270184edcdf83a05086016a50ce5bd946923a8a8 Mon Sep 17 00:00:00 2001 From: turanszkij Date: Sun, 22 Mar 2020 20:38:16 +0000 Subject: [PATCH] added multi scale ambient occlusion --- Documentation/ScriptingAPI-Documentation.md | 6 +- Editor/Editor.cpp | 2 +- Editor/PostprocessWindow.cpp | 66 +-- Editor/PostprocessWindow.h | 8 +- README.md | 2 +- WickedEngine/RenderPath3D.cpp | 70 +-- WickedEngine/RenderPath3D.h | 42 +- WickedEngine/RenderPath3D_BindLua.cpp | 29 +- WickedEngine/RenderPath3D_BindLua.h | 3 +- WickedEngine/RenderPath3D_Deferred.cpp | 6 +- .../RenderPath3D_Deferred_BindLua.cpp | 3 +- WickedEngine/RenderPath3D_Forward.cpp | 4 +- WickedEngine/RenderPath3D_Forward_BindLua.cpp | 3 +- WickedEngine/RenderPath3D_TiledDeferred.cpp | 4 +- .../RenderPath3D_TiledDeferred_BindLua.cpp | 3 +- WickedEngine/RenderPath3D_TiledForward.cpp | 4 +- .../RenderPath3D_TiledForward_BindLua.cpp | 3 +- WickedEngine/ResourceMapping.h | 2 +- WickedEngine/ShaderInterop_Postprocess.h | 20 + WickedEngine/WickedEngine_SHADERS.vcxproj | 32 ++ .../WickedEngine_SHADERS.vcxproj.filters | 36 +- WickedEngine/environmentalLightPS.hlsl | 12 +- WickedEngine/hbaoCS.hlsl | 4 +- WickedEngine/lightCullingCS.hlsl | 4 +- WickedEngine/msaoCS.hlsl | 145 ++++++ WickedEngine/msao_blurupsampleCS.hlsl | 201 +++++++ .../msao_blurupsampleCS_blendout.hlsl | 2 + WickedEngine/msao_blurupsampleCS_premin.hlsl | 2 + .../msao_blurupsampleCS_premin_blendout.hlsl | 3 + WickedEngine/msao_interleaveCS.hlsl | 2 + WickedEngine/msao_preparedepthbuffers1CS.hlsl | 42 ++ WickedEngine/msao_preparedepthbuffers2CS.hlsl | 31 ++ WickedEngine/objectHF.hlsli | 5 +- WickedEngine/wiEnums.h | 10 + WickedEngine/wiRenderer.cpp | 489 +++++++++++++++++- WickedEngine/wiRenderer.h | 12 +- WickedEngine/wiVersion.cpp | 2 +- features.txt | 2 +- 38 files changed, 1139 insertions(+), 177 deletions(-) create mode 100644 WickedEngine/msaoCS.hlsl create mode 100644 WickedEngine/msao_blurupsampleCS.hlsl create mode 100644 WickedEngine/msao_blurupsampleCS_blendout.hlsl create mode 100644 WickedEngine/msao_blurupsampleCS_premin.hlsl create mode 100644 WickedEngine/msao_blurupsampleCS_premin_blendout.hlsl create mode 100644 WickedEngine/msao_interleaveCS.hlsl create mode 100644 WickedEngine/msao_preparedepthbuffers1CS.hlsl create mode 100644 WickedEngine/msao_preparedepthbuffers2CS.hlsl diff --git a/Documentation/ScriptingAPI-Documentation.md b/Documentation/ScriptingAPI-Documentation.md index ff4216ab5..c9d975e1b 100644 --- a/Documentation/ScriptingAPI-Documentation.md +++ b/Documentation/ScriptingAPI-Documentation.md @@ -626,7 +626,11 @@ It can hold Sprites and Fonts and can sort them by layers, update and render the A 3D scene can either be rendered by a Forward or Deferred render path, or path tracing. It inherits functions from RenderPath2D, so it can render a 2D overlay. - [void-constructor]RenderPath3D() -- SetSSAOEnabled(bool value) +- SetAO(int value) -- Sets up the ambient occlusion effect (possible values below) +- AO_DISABLED : int -- turn off AO computation (use in SetAO() function) +- AO_SSAO : int -- enable simple brute force screen space ambient occlusion (use in SetAO() function) +- AO_HBAO : int -- enable horizon based screen space ambient occlusion (use in SetAO() function) +- AO_MSAO : int -- enable multi scale screen space ambient occlusion (use in SetAO() function) - SetHBAOEnabled(bool value) - SetSSREnabled(bool value) - SetShadowsEnabled(bool value) diff --git a/Editor/Editor.cpp b/Editor/Editor.cpp index 96ba4d667..b9ad7cf20 100644 --- a/Editor/Editor.cpp +++ b/Editor/Editor.cpp @@ -112,7 +112,7 @@ void EditorComponent::ChangeRenderPath(RENDERPATH path) renderPath->setShadowsEnabled(true); renderPath->setReflectionsEnabled(true); - renderPath->setSSAOEnabled(false); + renderPath->setAO(RenderPath3D::AO_DISABLED); renderPath->setSSREnabled(false); renderPath->setMotionBlurEnabled(false); renderPath->setColorGradingEnabled(false); diff --git a/Editor/PostprocessWindow.cpp b/Editor/PostprocessWindow.cpp index 56eb303d0..c6837a6f1 100644 --- a/Editor/PostprocessWindow.cpp +++ b/Editor/PostprocessWindow.cpp @@ -51,55 +51,29 @@ PostprocessWindow::PostprocessWindow(wiGUI* gui, RenderPath3D* comp) : GUI(gui), }); ppWindow->AddWidget(lightShaftsCheckBox); - ssaoCheckBox = new wiCheckBox("SSAO: "); - ssaoCheckBox->SetTooltip("Enable Screen Space Ambient Occlusion."); - ssaoCheckBox->SetScriptTip("RenderPath3D::SetSSAOEnabled(bool value)"); - ssaoCheckBox->SetPos(XMFLOAT2(x, y += step)); - ssaoCheckBox->SetCheck(component->getSSAOEnabled()); - ssaoCheckBox->OnClick([&](wiEventArgs args) { - component->setSSAOEnabled(args.bValue); + aoComboBox = new wiComboBox("AO: "); + aoComboBox->SetTooltip("Choose Ambient Occlusion type"); + aoComboBox->SetScriptTip("RenderPath3D::SetSSAOEnabled(bool value)"); + aoComboBox->SetPos(XMFLOAT2(x, y += step)); + aoComboBox->AddItem("Disabled"); + aoComboBox->AddItem("SSAO"); + aoComboBox->AddItem("HBAO"); + aoComboBox->AddItem("MSAO"); + aoComboBox->SetSelected(component->getAO()); + aoComboBox->OnSelect([&](wiEventArgs args) { + component->setAO((RenderPath3D::AO)args.iValue); }); - ppWindow->AddWidget(ssaoCheckBox); + ppWindow->AddWidget(aoComboBox); - hbaoCheckBox = new wiCheckBox("HBAO: "); - hbaoCheckBox->SetTooltip("Special optimized version of Screen Space Ambient Occlusion. Range and Samplecount parameters don't apply."); - hbaoCheckBox->SetScriptTip("RenderPath3D::SetSSAOEnabled(bool value)"); - hbaoCheckBox->SetPos(XMFLOAT2(x + 100, y)); - hbaoCheckBox->SetCheck(component->getHBAOEnabled()); - hbaoCheckBox->OnClick([&](wiEventArgs args) { - component->setHBAOEnabled(args.bValue); + aoPowerSlider = new wiSlider(0.25f, 8.0f, 2, 1000, "Power: "); + aoPowerSlider->SetTooltip("Set SSAO Power. Higher values produce darker, more pronounced effect"); + aoPowerSlider->SetSize(XMFLOAT2(100, 20)); + aoPowerSlider->SetPos(XMFLOAT2(x + 100, y += step)); + aoPowerSlider->SetValue((float)component->getAOPower()); + aoPowerSlider->OnSlide([&](wiEventArgs args) { + component->setAOPower(args.fValue); }); - ppWindow->AddWidget(hbaoCheckBox); - - ssaoRangeSlider = new wiSlider(0, 2, 1, 1000, "Range: "); - ssaoRangeSlider->SetTooltip("Set SSAO Detection range."); - ssaoRangeSlider->SetSize(XMFLOAT2(100, 20)); - ssaoRangeSlider->SetPos(XMFLOAT2(x + 100, y += step)); - ssaoRangeSlider->SetValue(component->getSSAORange()); - ssaoRangeSlider->OnSlide([&](wiEventArgs args) { - component->setSSAORange(args.fValue); - }); - ppWindow->AddWidget(ssaoRangeSlider); - - ssaoSampleCountSlider = new wiSlider(9, 64, 16, 64-9, "SampleCount: "); - ssaoSampleCountSlider->SetTooltip("Set SSAO Sample Count. Higher values produce better quality, but slower to compute"); - ssaoSampleCountSlider->SetSize(XMFLOAT2(100, 20)); - ssaoSampleCountSlider->SetPos(XMFLOAT2(x + 100, y += step)); - ssaoSampleCountSlider->SetValue((float)component->getSSAOSampleCount()); - ssaoSampleCountSlider->OnSlide([&](wiEventArgs args) { - component->setSSAOSampleCount((UINT)args.iValue); - }); - ppWindow->AddWidget(ssaoSampleCountSlider); - - ssaoPowerSlider = new wiSlider(0.25f, 8.0f, 2, 1000, "Power: "); - ssaoPowerSlider->SetTooltip("Set SSAO Power. Higher values produce darker, more pronounced effect"); - ssaoPowerSlider->SetSize(XMFLOAT2(100, 20)); - ssaoPowerSlider->SetPos(XMFLOAT2(x + 100, y += step)); - ssaoPowerSlider->SetValue((float)component->getSSAOPower()); - ssaoPowerSlider->OnSlide([&](wiEventArgs args) { - component->setSSAOPower(args.fValue); - }); - ppWindow->AddWidget(ssaoPowerSlider); + ppWindow->AddWidget(aoPowerSlider); ssrCheckBox = new wiCheckBox("SSR: "); ssrCheckBox->SetTooltip("Enable Screen Space Reflections."); diff --git a/Editor/PostprocessWindow.h b/Editor/PostprocessWindow.h index 674912e40..a509f0164 100644 --- a/Editor/PostprocessWindow.h +++ b/Editor/PostprocessWindow.h @@ -8,6 +8,7 @@ class wiLabel; class wiCheckBox; class wiSlider; class wiButton; +class wiComboBox; class PostprocessWindow { @@ -22,11 +23,8 @@ public: wiSlider* exposureSlider; wiCheckBox* lensFlareCheckBox; wiCheckBox* lightShaftsCheckBox; - wiCheckBox* ssaoCheckBox; - wiCheckBox* hbaoCheckBox; - wiSlider* ssaoRangeSlider; - wiSlider* ssaoSampleCountSlider; - wiSlider* ssaoPowerSlider; + wiComboBox* aoComboBox; + wiSlider* aoPowerSlider; wiCheckBox* ssrCheckBox; wiCheckBox* sssCheckBox; wiCheckBox* eyeAdaptionCheckBox; diff --git a/README.md b/README.md index 818ba007d..5a14e188b 100644 --- a/README.md +++ b/README.md @@ -106,7 +106,7 @@ wiScene::Scene scene2; // create a separate scene wiScene::LoadModel(scene2, "myModel2.wiscene"); // Load model into a separate scene wiScene::GetScene().Merge(scene2); // Combine separate scene with global scene -myGame.setSSAOEnabled(true); // You can enable post process effects this way... +myGame.setFXAAEnabled(true); // You can enable post process effects this way... RenderPath2D myMenuScreen; // This is an other render path, but now a simple 2D one. It can only render 2D graphics by default (like a menu for example) main.ActivatePath(&myMenuScreen); // activate the menu, the previous path (myGame) will be stopped diff --git a/WickedEngine/RenderPath3D.cpp b/WickedEngine/RenderPath3D.cpp index 23eda137f..0642d16e3 100644 --- a/WickedEngine/RenderPath3D.cpp +++ b/WickedEngine/RenderPath3D.cpp @@ -100,12 +100,10 @@ void RenderPath3D::ResizeBuffers() TextureDesc desc; desc.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS; desc.Format = FORMAT_R8_UNORM; - desc.Width = wiRenderer::GetInternalResolution().x / 2; - desc.Height = wiRenderer::GetInternalResolution().y / 2; - device->CreateTexture(&desc, nullptr, &rtSSAO[0]); - device->SetName(&rtSSAO[0], "rtSSAO[0]"); - device->CreateTexture(&desc, nullptr, &rtSSAO[1]); - device->SetName(&rtSSAO[1], "rtSSAO[1]"); + desc.Width = wiRenderer::GetInternalResolution().x; + desc.Height = wiRenderer::GetInternalResolution().y; + device->CreateTexture(&desc, nullptr, &rtAO); + device->SetName(&rtAO, "rtAO"); } { TextureDesc desc; @@ -426,31 +424,45 @@ void RenderPath3D::RenderLinearDepth(CommandList cmd) const { wiRenderer::Postprocess_Lineardepth(depthBuffer_Copy, rtLinearDepth, rtLinearDepth_minmax, cmd); } -void RenderPath3D::RenderSSAO(CommandList cmd) const +void RenderPath3D::RenderAO(CommandList cmd) const { - if (getHBAOEnabled()) + wiRenderer::GetDevice()->UnbindResources(TEXSLOT_RENDERPATH_AO, 1, cmd); + + if (getAOEnabled()) { - wiRenderer::Postprocess_HBAO( - rtLinearDepth_minmax, - rtSSAO[1], - rtSSAO[0], - cmd, - getSSAOPower() - ); - } - else if(getSSAOEnabled()) - { - wiRenderer::Postprocess_SSAO( - depthBuffer_Copy, - rtLinearDepth, - rtLinearDepth_minmax, - rtSSAO[1], - rtSSAO[0], - cmd, - getSSAORange(), - getSSAOSampleCount(), - getSSAOPower() - ); + switch (getAO()) + { + case AO_SSAO: + wiRenderer::Postprocess_SSAO( + depthBuffer_Copy, + rtLinearDepth, + rtLinearDepth_minmax, + rtAO, + cmd, + getAORange(), + getAOSampleCount(), + getAOPower() + ); + break; + case AO_HBAO: + wiRenderer::Postprocess_HBAO( + rtLinearDepth, + rtLinearDepth_minmax, + rtAO, + cmd, + getAOPower() + ); + break; + case AO_MSAO: + wiRenderer::Postprocess_MSAO( + rtLinearDepth, + rtLinearDepth_minmax, + rtAO, + cmd, + getAOPower() + ); + break; + } } } void RenderPath3D::RenderSSR(const Texture& gbuffer1, const Texture& gbuffer2, CommandList cmd) const diff --git a/WickedEngine/RenderPath3D.h b/WickedEngine/RenderPath3D.h index a9582c7b0..523fd180d 100644 --- a/WickedEngine/RenderPath3D.h +++ b/WickedEngine/RenderPath3D.h @@ -9,6 +9,15 @@ class RenderPath3D : public RenderPath2D { +public: + enum AO + { + AO_DISABLED, // no ambient occlusion + AO_SSAO, // simple brute force screen space ambient occlusion + AO_HBAO, // horizon based screen space ambient occlusion + AO_MSAO, // multi scale screen space ambient occlusion + // Don't alter order! (bound to lua manually) + }; private: float exposure = 1.0f; float bloomThreshold = 1.0f; @@ -20,14 +29,13 @@ private: float outlineThreshold = 0.2f; float outlineThickness = 1.0f; XMFLOAT4 outlineColor = XMFLOAT4(0, 0, 0, 1); - float ssaoRange = 1.0f; - uint32_t ssaoSampleCount = 16; - float ssaoPower = 2.0f; + float aoRange = 1.0f; + uint32_t aoSampleCount = 16; + float aoPower = 2.0f; float chromaticAberrationAmount = 2.0f; + AO ao = AO_DISABLED; bool fxaaEnabled = false; - bool ssaoEnabled = false; - bool hbaoEnabled = false; bool ssrEnabled = false; bool reflectionsEnabled = true; bool shadowsEnabled = true; @@ -62,7 +70,7 @@ protected: wiGraphics::Texture rtTemporalAA[2]; // temporal AA history buffer wiGraphics::Texture rtBloom; // contains the bright parts of the image + mipchain wiGraphics::Texture rtBloom_tmp; // temporary for bloom downsampling - wiGraphics::Texture rtSSAO[2]; // ping-pong when rendering and blurring SSAO + wiGraphics::Texture rtAO; // full res AO wiGraphics::Texture rtSun[2]; // 0: sun render target used for lightshafts (can be MSAA), 1: radial blurred lightshafts wiGraphics::Texture rtSun_resolved; // sun render target, but the resolved version if MSAA is enabled @@ -103,7 +111,7 @@ protected: virtual void RenderShadows(wiGraphics::CommandList cmd) const; virtual void RenderLinearDepth(wiGraphics::CommandList cmd) const; - virtual void RenderSSAO(wiGraphics::CommandList cmd) const; + virtual void RenderAO(wiGraphics::CommandList cmd) const; virtual void RenderSSR(const wiGraphics::Texture& gbuffer1, const wiGraphics::Texture& gbuffer2, wiGraphics::CommandList cmd) const; virtual void DownsampleDepthBuffer(wiGraphics::CommandList cmd) const; virtual void RenderOutline(wiGraphics::CommandList cmd) const; @@ -126,14 +134,13 @@ public: constexpr float getOutlineThreshold() const { return outlineThreshold; } constexpr float getOutlineThickness() const { return outlineThickness; } constexpr XMFLOAT4 getOutlineColor() const { return outlineColor; } - constexpr float getSSAORange() const { return ssaoRange; } - constexpr uint32_t getSSAOSampleCount() const { return ssaoSampleCount; } - constexpr float getSSAOPower() const { return ssaoPower; } + constexpr float getAORange() const { return aoRange; } + constexpr uint32_t getAOSampleCount() const { return aoSampleCount; } + constexpr float getAOPower() const { return aoPower; } constexpr float getChromaticAberrationAmount() const { return chromaticAberrationAmount; } - constexpr bool getSSAOEnabled() const { return ssaoEnabled; } - constexpr bool getHBAOEnabled() const { return hbaoEnabled; } - constexpr bool getAOEnabled() const { return getSSAOEnabled() || getHBAOEnabled(); } + constexpr bool getAOEnabled() const { return ao != AO_DISABLED; } + constexpr AO getAO() const { return ao; } constexpr bool getSSREnabled() const { return ssrEnabled; } constexpr bool getShadowsEnabled() const { return shadowsEnabled; } constexpr bool getReflectionsEnabled() const { return reflectionsEnabled; } @@ -167,13 +174,12 @@ public: constexpr void setOutlineThreshold(float value) { outlineThreshold = value; } constexpr void setOutlineThickness(float value) { outlineThickness = value; } constexpr void setOutlineColor(const XMFLOAT4& value) { outlineColor = value; } - constexpr void setSSAORange(float value) { ssaoRange = value; } - constexpr void setSSAOSampleCount(uint32_t value) { ssaoSampleCount = value; } - constexpr void setSSAOPower(float value) { ssaoPower = value; } + constexpr void setAORange(float value) { aoRange = value; } + constexpr void setAOSampleCount(uint32_t value) { aoSampleCount = value; } + constexpr void setAOPower(float value) { aoPower = value; } constexpr void setChromaticAberrationAmount(float value) { chromaticAberrationAmount = value; } - constexpr void setSSAOEnabled(bool value) { ssaoEnabled = value; } - constexpr void setHBAOEnabled(bool value){ hbaoEnabled = value; } + constexpr void setAO(AO value) { ao = value; } constexpr void setSSREnabled(bool value){ ssrEnabled = value; } constexpr void setShadowsEnabled(bool value){ shadowsEnabled = value; } constexpr void setReflectionsEnabled(bool value){ reflectionsEnabled = value; } diff --git a/WickedEngine/RenderPath3D_BindLua.cpp b/WickedEngine/RenderPath3D_BindLua.cpp index 478f41ee1..41afd7f28 100644 --- a/WickedEngine/RenderPath3D_BindLua.cpp +++ b/WickedEngine/RenderPath3D_BindLua.cpp @@ -25,8 +25,7 @@ Luna::FunctionType RenderPath3D_BindLua::methods[] = { lunamethod(RenderPath_BindLua, GetLayerMask), lunamethod(RenderPath_BindLua, SetLayerMask), - lunamethod(RenderPath3D_BindLua, SetSSAOEnabled), - lunamethod(RenderPath3D_BindLua, SetHBAOEnabled), + lunamethod(RenderPath3D_BindLua, SetAO), lunamethod(RenderPath3D_BindLua, SetSSREnabled), lunamethod(RenderPath3D_BindLua, SetShadowsEnabled), lunamethod(RenderPath3D_BindLua, SetReflectionsEnabled), @@ -56,30 +55,21 @@ Luna::PropertyType RenderPath3D_BindLua::properties[] = { }; -int RenderPath3D_BindLua::SetSSAOEnabled(lua_State* L) +int RenderPath3D_BindLua::SetAO(lua_State* L) { if (component == nullptr) { - wiLua::SError(L, "SetSSAOEnabled(bool value) component is null!"); + wiLua::SError(L, "SetAO(AO value) component is null!"); return 0; } if (wiLua::SGetArgCount(L) > 0) - ((RenderPath3D*)component)->setSSAOEnabled(wiLua::SGetBool(L, 1)); - else - wiLua::SError(L, "SetSSAOEnabled(bool value) not enough arguments!"); - return 0; -} -int RenderPath3D_BindLua::SetHBAOEnabled(lua_State* L) -{ - if (component == nullptr) { - wiLua::SError(L, "SetHBAOEnabled(bool value) component is null!"); - return 0; + int value = wiLua::SGetInt(L, 1); + RenderPath3D::AO ao = (RenderPath3D::AO)value; + ((RenderPath3D*)component)->setAO(ao); } - if (wiLua::SGetArgCount(L) > 0) - ((RenderPath3D*)component)->setHBAOEnabled(wiLua::SGetBool(L, 1)); else - wiLua::SError(L, "SetHBAOEnabled(bool value) not enough arguments!"); + wiLua::SError(L, "SetAO(AO value) not enough arguments!"); return 0; } int RenderPath3D_BindLua::SetSSREnabled(lua_State* L) @@ -400,5 +390,10 @@ void RenderPath3D_BindLua::Bind() { initialized = true; Luna::Register(wiLua::GetGlobal()->GetLuaState()); + + wiLua::GetGlobal()->RunText("AO_DISABLED = 0"); + wiLua::GetGlobal()->RunText("AO_SSAO = 1"); + wiLua::GetGlobal()->RunText("AO_HBAO = 2"); + wiLua::GetGlobal()->RunText("AO_MSAO = 3"); } } diff --git a/WickedEngine/RenderPath3D_BindLua.h b/WickedEngine/RenderPath3D_BindLua.h index 767126548..28a01a00f 100644 --- a/WickedEngine/RenderPath3D_BindLua.h +++ b/WickedEngine/RenderPath3D_BindLua.h @@ -18,8 +18,7 @@ public: } RenderPath3D_BindLua(lua_State* L) {} - int SetSSAOEnabled(lua_State* L); - int SetHBAOEnabled(lua_State* L); + int SetAO(lua_State* L); int SetSSREnabled(lua_State* L); int SetShadowsEnabled(lua_State* L); int SetReflectionsEnabled(lua_State* L); diff --git a/WickedEngine/RenderPath3D_Deferred.cpp b/WickedEngine/RenderPath3D_Deferred.cpp index 798d08455..a1269c962 100644 --- a/WickedEngine/RenderPath3D_Deferred.cpp +++ b/WickedEngine/RenderPath3D_Deferred.cpp @@ -188,7 +188,7 @@ void RenderPath3D_Deferred::Render() const RenderLinearDepth(cmd); - RenderSSAO(cmd); + RenderAO(cmd); }); cmd = device->BeginCommandList(); @@ -208,7 +208,7 @@ void RenderPath3D_Deferred::Render() const vp.Height = (float)depthBuffer.GetDesc().Height; device->BindViewports(1, &vp, cmd); - device->BindResource(PS, getAOEnabled() ? &rtSSAO[0] : wiTextureHelper::getWhite(), TEXSLOT_RENDERPATH_SSAO, cmd); + device->BindResource(PS, getAOEnabled() ? &rtAO : wiTextureHelper::getWhite(), TEXSLOT_RENDERPATH_AO, cmd); device->BindResource(PS, getSSREnabled() ? &rtSSR : wiTextureHelper::getTransparent(), TEXSLOT_RENDERPATH_SSR, cmd); wiRenderer::DrawDeferredLights(wiRenderer::GetCamera(), depthBuffer_Copy, rtGBuffer[0], rtGBuffer[1], rtGBuffer[2], cmd); @@ -294,7 +294,7 @@ void RenderPath3D_Deferred::RenderDeferredComposition(CommandList cmd) const rtGBuffer[2], lightbuffer_diffuse, lightbuffer_specular, - getAOEnabled() ? rtSSAO[0] : *wiTextureHelper::getWhite(), + getAOEnabled() ? rtAO : *wiTextureHelper::getWhite(), rtLinearDepth, cmd ); diff --git a/WickedEngine/RenderPath3D_Deferred_BindLua.cpp b/WickedEngine/RenderPath3D_Deferred_BindLua.cpp index 7ef15d0da..3917939f5 100644 --- a/WickedEngine/RenderPath3D_Deferred_BindLua.cpp +++ b/WickedEngine/RenderPath3D_Deferred_BindLua.cpp @@ -24,8 +24,7 @@ Luna::FunctionType RenderPath3D_Deferred_BindLua: lunamethod(RenderPath_BindLua, GetLayerMask), lunamethod(RenderPath_BindLua, SetLayerMask), - lunamethod(RenderPath3D_BindLua, SetSSAOEnabled), - lunamethod(RenderPath3D_BindLua, SetHBAOEnabled), + lunamethod(RenderPath3D_BindLua, SetAO), lunamethod(RenderPath3D_BindLua, SetSSREnabled), lunamethod(RenderPath3D_BindLua, SetShadowsEnabled), lunamethod(RenderPath3D_BindLua, SetReflectionsEnabled), diff --git a/WickedEngine/RenderPath3D_Forward.cpp b/WickedEngine/RenderPath3D_Forward.cpp index 8c56c604f..860c2c193 100644 --- a/WickedEngine/RenderPath3D_Forward.cpp +++ b/WickedEngine/RenderPath3D_Forward.cpp @@ -150,7 +150,7 @@ void RenderPath3D_Forward::Render() const RenderLinearDepth(cmd); - RenderSSAO(cmd); + RenderAO(cmd); }); cmd = device->BeginCommandList(); @@ -170,7 +170,7 @@ void RenderPath3D_Forward::Render() const device->BindViewports(1, &vp, cmd); device->BindResource(PS, getReflectionsEnabled() ? &rtReflection : wiTextureHelper::getTransparent(), TEXSLOT_RENDERPATH_REFLECTION, cmd); - device->BindResource(PS, getAOEnabled() ? &rtSSAO[0] : wiTextureHelper::getWhite(), TEXSLOT_RENDERPATH_SSAO, cmd); + device->BindResource(PS, getAOEnabled() ? &rtAO : wiTextureHelper::getWhite(), TEXSLOT_RENDERPATH_AO, cmd); device->BindResource(PS, getSSREnabled() ? &rtSSR : wiTextureHelper::getTransparent(), TEXSLOT_RENDERPATH_SSR, cmd); wiRenderer::DrawScene(wiRenderer::GetCamera(), getTessellationEnabled(), cmd, RENDERPASS_FORWARD, true, true); wiRenderer::DrawSky(cmd); diff --git a/WickedEngine/RenderPath3D_Forward_BindLua.cpp b/WickedEngine/RenderPath3D_Forward_BindLua.cpp index 7ffa3c972..c519f65ae 100644 --- a/WickedEngine/RenderPath3D_Forward_BindLua.cpp +++ b/WickedEngine/RenderPath3D_Forward_BindLua.cpp @@ -24,8 +24,7 @@ Luna::FunctionType RenderPath3D_Forward_BindLua::m lunamethod(RenderPath_BindLua, GetLayerMask), lunamethod(RenderPath_BindLua, SetLayerMask), - lunamethod(RenderPath3D_BindLua, SetSSAOEnabled), - lunamethod(RenderPath3D_BindLua, SetHBAOEnabled), + lunamethod(RenderPath3D_BindLua, SetAO), lunamethod(RenderPath3D_BindLua, SetSSREnabled), lunamethod(RenderPath3D_BindLua, SetShadowsEnabled), lunamethod(RenderPath3D_BindLua, SetReflectionsEnabled), diff --git a/WickedEngine/RenderPath3D_TiledDeferred.cpp b/WickedEngine/RenderPath3D_TiledDeferred.cpp index b2f669349..7a7830f64 100644 --- a/WickedEngine/RenderPath3D_TiledDeferred.cpp +++ b/WickedEngine/RenderPath3D_TiledDeferred.cpp @@ -93,7 +93,7 @@ void RenderPath3D_TiledDeferred::Render() const RenderLinearDepth(cmd); - RenderSSAO(cmd); + RenderAO(cmd); }); cmd = device->BeginCommandList(); @@ -104,7 +104,7 @@ void RenderPath3D_TiledDeferred::Render() const RenderDecals(cmd); - device->BindResource(CS, getAOEnabled() ? &rtSSAO[0] : wiTextureHelper::getWhite(), TEXSLOT_RENDERPATH_SSAO, cmd); + device->BindResource(CS, getAOEnabled() ? &rtAO : wiTextureHelper::getWhite(), TEXSLOT_RENDERPATH_AO, cmd); device->BindResource(CS, getSSREnabled() ? &rtSSR : wiTextureHelper::getTransparent(), TEXSLOT_RENDERPATH_SSR, cmd); diff --git a/WickedEngine/RenderPath3D_TiledDeferred_BindLua.cpp b/WickedEngine/RenderPath3D_TiledDeferred_BindLua.cpp index 2824131c8..07afbcda8 100644 --- a/WickedEngine/RenderPath3D_TiledDeferred_BindLua.cpp +++ b/WickedEngine/RenderPath3D_TiledDeferred_BindLua.cpp @@ -24,8 +24,7 @@ Luna::FunctionType RenderPath3D_TiledDeferre lunamethod(RenderPath_BindLua, GetLayerMask), lunamethod(RenderPath_BindLua, SetLayerMask), - lunamethod(RenderPath3D_BindLua, SetSSAOEnabled), - lunamethod(RenderPath3D_BindLua, SetHBAOEnabled), + lunamethod(RenderPath3D_BindLua, SetAO), lunamethod(RenderPath3D_BindLua, SetSSREnabled), lunamethod(RenderPath3D_BindLua, SetShadowsEnabled), lunamethod(RenderPath3D_BindLua, SetReflectionsEnabled), diff --git a/WickedEngine/RenderPath3D_TiledForward.cpp b/WickedEngine/RenderPath3D_TiledForward.cpp index 02a1c2024..bc164cc6d 100644 --- a/WickedEngine/RenderPath3D_TiledForward.cpp +++ b/WickedEngine/RenderPath3D_TiledForward.cpp @@ -75,7 +75,7 @@ void RenderPath3D_TiledForward::Render() const RenderLinearDepth(cmd); - RenderSSAO(cmd); + RenderAO(cmd); }); cmd = device->BeginCommandList(); @@ -100,7 +100,7 @@ void RenderPath3D_TiledForward::Render() const device->BindViewports(1, &vp, cmd); device->BindResource(PS, getReflectionsEnabled() ? &rtReflection : wiTextureHelper::getTransparent(), TEXSLOT_RENDERPATH_REFLECTION, cmd); - device->BindResource(PS, getAOEnabled() ? &rtSSAO[0] : wiTextureHelper::getWhite(), TEXSLOT_RENDERPATH_SSAO, cmd); + device->BindResource(PS, getAOEnabled() ? &rtAO : wiTextureHelper::getWhite(), TEXSLOT_RENDERPATH_AO, cmd); device->BindResource(PS, getSSREnabled() ? &rtSSR : wiTextureHelper::getTransparent(), TEXSLOT_RENDERPATH_SSR, cmd); wiRenderer::DrawScene(wiRenderer::GetCamera(), getTessellationEnabled(), cmd, RENDERPASS_TILEDFORWARD, true, true); wiRenderer::DrawSky(cmd); diff --git a/WickedEngine/RenderPath3D_TiledForward_BindLua.cpp b/WickedEngine/RenderPath3D_TiledForward_BindLua.cpp index 71b8deba6..910902fe9 100644 --- a/WickedEngine/RenderPath3D_TiledForward_BindLua.cpp +++ b/WickedEngine/RenderPath3D_TiledForward_BindLua.cpp @@ -24,8 +24,7 @@ Luna::FunctionType RenderPath3D_TiledForward_ lunamethod(RenderPath_BindLua, GetLayerMask), lunamethod(RenderPath_BindLua, SetLayerMask), - lunamethod(RenderPath3D_BindLua, SetSSAOEnabled), - lunamethod(RenderPath3D_BindLua, SetHBAOEnabled), + lunamethod(RenderPath3D_BindLua, SetAO), lunamethod(RenderPath3D_BindLua, SetSSREnabled), lunamethod(RenderPath3D_BindLua, SetShadowsEnabled), lunamethod(RenderPath3D_BindLua, SetReflectionsEnabled), diff --git a/WickedEngine/ResourceMapping.h b/WickedEngine/ResourceMapping.h index 22cc326ca..52a3b9948 100644 --- a/WickedEngine/ResourceMapping.h +++ b/WickedEngine/ResourceMapping.h @@ -70,7 +70,7 @@ #define TEXSLOT_RENDERPATH_REFLECTION TEXSLOT_ONDEMAND6 #define TEXSLOT_RENDERPATH_REFRACTION TEXSLOT_ONDEMAND7 #define TEXSLOT_RENDERPATH_WATERRIPPLES TEXSLOT_ONDEMAND8 -#define TEXSLOT_RENDERPATH_SSAO TEXSLOT_ONDEMAND8 +#define TEXSLOT_RENDERPATH_AO TEXSLOT_ONDEMAND8 #define TEXSLOT_RENDERPATH_SSR TEXSLOT_ONDEMAND9 diff --git a/WickedEngine/ShaderInterop_Postprocess.h b/WickedEngine/ShaderInterop_Postprocess.h index 9ca319bbf..789fada42 100644 --- a/WickedEngine/ShaderInterop_Postprocess.h +++ b/WickedEngine/ShaderInterop_Postprocess.h @@ -30,6 +30,26 @@ static const uint POSTPROCESS_HBAO_THREADCOUNT = 320; #define hbao_uv_to_view_A xPPParams1.xy #define hbao_uv_to_view_B xPPParams1.zw +static const uint POSTPROCESS_MSAO_BLOCKSIZE = 16; +CBUFFER(MSAOCB, CBSLOT_RENDERER_POSTPROCESS) +{ + float4 xInvThicknessTable[3]; + float4 xSampleWeightTable[3]; + float2 xInvSliceDimension; + float xRejectFadeoff; + float xRcpAccentuation; +}; +//#define MSAO_SAMPLE_EXHAUSTIVELY +CBUFFER(MSAO_UPSAMPLECB, CBSLOT_RENDERER_POSTPROCESS) +{ + float2 InvLowResolution; + float2 InvHighResolution; + float NoiseFilterStrength; + float StepSize; + float kBlurTolerance; + float kUpsampleTolerance; +}; + static const uint MOTIONBLUR_TILESIZE = 32; #define motionblur_strength xPPParams0.x diff --git a/WickedEngine/WickedEngine_SHADERS.vcxproj b/WickedEngine/WickedEngine_SHADERS.vcxproj index 65b3d7ec9..d13b02fe4 100644 --- a/WickedEngine/WickedEngine_SHADERS.vcxproj +++ b/WickedEngine/WickedEngine_SHADERS.vcxproj @@ -455,6 +455,38 @@ Compute 5.0 + + Compute + 5.0 + + + Compute + 5.0 + + + Compute + 5.0 + + + Compute + 5.0 + + + Compute + 5.0 + + + Compute + 5.0 + + + Compute + 5.0 + + + Compute + 5.0 + Pixel diff --git a/WickedEngine/WickedEngine_SHADERS.vcxproj.filters b/WickedEngine/WickedEngine_SHADERS.vcxproj.filters index 310adc4c9..1a896b150 100644 --- a/WickedEngine/WickedEngine_SHADERS.vcxproj.filters +++ b/WickedEngine/WickedEngine_SHADERS.vcxproj.filters @@ -708,9 +708,6 @@ CS - - CS - CS @@ -873,9 +870,6 @@ PS - - CS - CS @@ -912,6 +906,36 @@ CS + + CS + + + CS + + + CS + + + CS + + + CS + + + CS + + + CS + + + CS + + + CS + + + CS + diff --git a/WickedEngine/environmentalLightPS.hlsl b/WickedEngine/environmentalLightPS.hlsl index 69a1c9299..b76657a70 100644 --- a/WickedEngine/environmentalLightPS.hlsl +++ b/WickedEngine/environmentalLightPS.hlsl @@ -1,6 +1,6 @@ #include "deferredLightHF.hlsli" -TEXTURE2D(texture_ssao, float, TEXSLOT_RENDERPATH_SSAO); +TEXTURE2D(texture_ao, float, TEXSLOT_RENDERPATH_AO); TEXTURE2D(texture_ssr, float4, TEXSLOT_RENDERPATH_SSR); @@ -16,15 +16,15 @@ LightOutputType main(VertexToPixel PSIn) float4 ssr = texture_ssr.SampleLevel(sampler_linear_clamp, ReprojectedScreenCoord, 0); lighting.indirect.specular = lerp(lighting.indirect.specular, ssr.rgb, ssr.a); - float ssao = texture_ssao.SampleLevel(sampler_linear_clamp, ScreenCoord, 0).r; - surface.occlusion = ssao; + float ao = texture_ao.SampleLevel(sampler_linear_clamp, ScreenCoord, 0).r; + surface.occlusion = ao; // Blend factor modulation: // Alpha is not written, but blending will multiply the dest rgb with 1-alpha // Modulate alpha to overwrite dest (which contains ambient and light map before this pass) - ssao = saturate(1 - ssao); - diffuse_alpha = max(vxgi_contribution.diffuse, ssao); - specular_alpha = max(max(vxgi_contribution.specular, ssr.a), ssao); + ao = saturate(1 - ao); + diffuse_alpha = max(vxgi_contribution.diffuse, ao); + specular_alpha = max(max(vxgi_contribution.specular, ssr.a), ao); DEFERREDLIGHT_RETURN } \ No newline at end of file diff --git a/WickedEngine/hbaoCS.hlsl b/WickedEngine/hbaoCS.hlsl index 636d6a9da..816300e05 100644 --- a/WickedEngine/hbaoCS.hlsl +++ b/WickedEngine/hbaoCS.hlsl @@ -7,9 +7,9 @@ TEXTURE2D(texture_horizontalpass, float, TEXSLOT_ONDEMAND1); RWTEXTURE2D(output, unorm float, 0); // Step size in number of pixels -#define STEP_SIZE 6 +#define STEP_SIZE 4 // Number of shared-memory samples per direction -#define NUM_STEPS 16 +#define NUM_STEPS 8 // The last sample has weight = exp(-KERNEL_FALLOFF) #define KERNEL_FALLOFF 3.0f #define TAN_ANGLE_BIAS 0 diff --git a/WickedEngine/lightCullingCS.hlsl b/WickedEngine/lightCullingCS.hlsl index 1c6f9bcb1..0503c314b 100644 --- a/WickedEngine/lightCullingCS.hlsl +++ b/WickedEngine/lightCullingCS.hlsl @@ -2,7 +2,7 @@ #include "cullingShaderHF.hlsli" #include "lightingHF.hlsli" -TEXTURE2D(texture_ssao, float, TEXSLOT_RENDERPATH_SSAO); +TEXTURE2D(texture_ao, float, TEXSLOT_RENDERPATH_AO); TEXTURE2D(texture_ssr, float4, TEXSLOT_RENDERPATH_SSR); STRUCTUREDBUFFER(in_Frustums, Frustum, SBSLOT_TILEFRUSTUMS); @@ -501,7 +501,7 @@ void main(uint3 Gid : SV_GroupID, uint3 DTid : SV_DispatchThreadID, uint3 GTid : float4 ssr = texture_ssr.SampleLevel(sampler_linear_clamp, ReprojectedScreenCoord, 0); lighting.indirect.specular = lerp(lighting.indirect.specular, ssr.rgb, ssr.a); - float ssao = texture_ssao.SampleLevel(sampler_linear_clamp, ScreenCoord, 0).r; + float ssao = texture_ao.SampleLevel(sampler_linear_clamp, ScreenCoord, 0).r; surface.occlusion *= ssao; LightingPart combined_lighting = CombineLighting(surface, lighting); diff --git a/WickedEngine/msaoCS.hlsl b/WickedEngine/msaoCS.hlsl new file mode 100644 index 000000000..1ea07db6e --- /dev/null +++ b/WickedEngine/msaoCS.hlsl @@ -0,0 +1,145 @@ +// This is a modified version of the SSAO from Microsoft MiniEngine at https://github.com/Microsoft/DirectX-Graphics-Samples + +#include "globals.hlsli" +#include "ShaderInterop_Postprocess.h" + +#ifdef INTERLEAVE_RESULT +TEXTURE2DARRAY(texture_lineardepth_deinterleaved, float, TEXSLOT_ONDEMAND0); +#else +TEXTURE2D(texture_lineardepth_interleaved, float, TEXSLOT_ONDEMAND0); +#define WIDE_SAMPLING 1 +#endif // INTERLEAVE_RESULT + +RWTEXTURE2D(output, unorm float, 0); + +#if WIDE_SAMPLING +// 32x32 cache size: the 16x16 in the center forms the area of focus with the 8-pixel perimeter used for wide gathering. +#define TILE_DIM 32 +#define THREAD_COUNT_X 16 +#define THREAD_COUNT_Y 16 +#else +// 16x16 cache size: the 8x8 in the center forms the area of focus with the 4-pixel perimeter used for gathering. +#define TILE_DIM 16 +#define THREAD_COUNT_X 8 +#define THREAD_COUNT_Y 8 +#endif // WIDE_SAMPLING + +groupshared float DepthSamples[TILE_DIM * TILE_DIM]; + +float TestSamplePair(float frontDepth, float invRange, uint base, int offset) +{ + // "Disocclusion" measures the penetration distance of the depth sample within the sphere. + // Disocclusion < 0 (full occlusion) -> the sample fell in front of the sphere + // Disocclusion > 1 (no occlusion) -> the sample fell behind the sphere + float disocclusion1 = DepthSamples[base + offset] * invRange - frontDepth; + float disocclusion2 = DepthSamples[base - offset] * invRange - frontDepth; + + float pseudoDisocclusion1 = saturate(xRejectFadeoff * disocclusion1); + float pseudoDisocclusion2 = saturate(xRejectFadeoff * disocclusion2); + + return saturate( + clamp(disocclusion1, pseudoDisocclusion2, 1.0) + + clamp(disocclusion2, pseudoDisocclusion1, 1.0) - + pseudoDisocclusion1 * pseudoDisocclusion2); +} + +float TestSamples(uint centerIdx, uint x, uint y, float invDepth, float invThickness) +{ +#if WIDE_SAMPLING + x <<= 1; + y <<= 1; +#endif // WIDE_SAMPLING + + float invRange = invThickness * invDepth; + float frontDepth = invThickness - 0.5; + + if (y == 0) + { + // Axial + return 0.5 * ( + TestSamplePair(frontDepth, invRange, centerIdx, x) + + TestSamplePair(frontDepth, invRange, centerIdx, x * TILE_DIM)); + } + else if (x == y) + { + // Diagonal + return 0.5 * ( + TestSamplePair(frontDepth, invRange, centerIdx, x * TILE_DIM - x) + + TestSamplePair(frontDepth, invRange, centerIdx, x * TILE_DIM + x)); + } + else + { + // L-Shaped + return 0.25 * ( + TestSamplePair(frontDepth, invRange, centerIdx, y * TILE_DIM + x) + + TestSamplePair(frontDepth, invRange, centerIdx, y * TILE_DIM - x) + + TestSamplePair(frontDepth, invRange, centerIdx, x * TILE_DIM + y) + + TestSamplePair(frontDepth, invRange, centerIdx, x * TILE_DIM - y)); + } +} + +[numthreads(THREAD_COUNT_X, THREAD_COUNT_Y, 1)] +void main(uint3 Gid : SV_GroupID, uint GI : SV_GroupIndex, uint3 GTid : SV_GroupThreadID, uint3 DTid : SV_DispatchThreadID) +{ +#if WIDE_SAMPLING + float2 QuadCenterUV = int2(DTid.xy + GTid.xy - 7) * xInvSliceDimension.xy; +#else + float2 QuadCenterUV = int2(DTid.xy + GTid.xy - 3) * xInvSliceDimension.xy; +#endif // WIDE_SAMPLING + + // Fetch four depths and store them in LDS +#ifdef INTERLEAVE_RESULT + float4 depths = texture_lineardepth_deinterleaved.Gather(sampler_linear_clamp, float3(QuadCenterUV, DTid.z)); +#else + float4 depths = texture_lineardepth_interleaved.Gather(sampler_linear_clamp, QuadCenterUV); +#endif // INTERLEAVE_RESULT + + int destIdx = GTid.x * 2 + GTid.y * 2 * TILE_DIM; + DepthSamples[destIdx] = depths.w; + DepthSamples[destIdx + 1] = depths.z; + DepthSamples[destIdx + TILE_DIM] = depths.x; + DepthSamples[destIdx + TILE_DIM + 1] = depths.y; + + GroupMemoryBarrierWithGroupSync(); + +#if WIDE_SAMPLING + uint thisIdx = GTid.x + GTid.y * TILE_DIM + 8 * TILE_DIM + 8; +#else + uint thisIdx = GTid.x + GTid.y * TILE_DIM + 4 * TILE_DIM + 4; +#endif // WIDE_SAMPLING + const float invThisDepth = 1.0 / DepthSamples[thisIdx]; + + float ao = 0.0; + +#ifdef MSAO_SAMPLE_EXHAUSTIVELY + // 68 samples: sample all cells in *within* a circular radius of 5 + ao += xSampleWeightTable[0].x * TestSamples(thisIdx, 1, 0, invThisDepth, xInvThicknessTable[0].x); + ao += xSampleWeightTable[0].y * TestSamples(thisIdx, 2, 0, invThisDepth, xInvThicknessTable[0].y); + ao += xSampleWeightTable[0].z * TestSamples(thisIdx, 3, 0, invThisDepth, xInvThicknessTable[0].z); + ao += xSampleWeightTable[0].w * TestSamples(thisIdx, 4, 0, invThisDepth, xInvThicknessTable[0].w); + ao += xSampleWeightTable[1].x * TestSamples(thisIdx, 1, 1, invThisDepth, xInvThicknessTable[1].x); + ao += xSampleWeightTable[2].x * TestSamples(thisIdx, 2, 2, invThisDepth, xInvThicknessTable[2].x); + ao += xSampleWeightTable[2].w * TestSamples(thisIdx, 3, 3, invThisDepth, xInvThicknessTable[2].w); + ao += xSampleWeightTable[1].y * TestSamples(thisIdx, 1, 2, invThisDepth, xInvThicknessTable[1].y); + ao += xSampleWeightTable[1].z * TestSamples(thisIdx, 1, 3, invThisDepth, xInvThicknessTable[1].z); + ao += xSampleWeightTable[1].w * TestSamples(thisIdx, 1, 4, invThisDepth, xInvThicknessTable[1].w); + ao += xSampleWeightTable[2].y * TestSamples(thisIdx, 2, 3, invThisDepth, xInvThicknessTable[2].y); + ao += xSampleWeightTable[2].z * TestSamples(thisIdx, 2, 4, invThisDepth, xInvThicknessTable[2].z); +#else // SAMPLE_CHECKER + // 36 samples: sample every-other cell in a checker board pattern + ao += xSampleWeightTable[0].y * TestSamples(thisIdx, 2, 0, invThisDepth, xInvThicknessTable[0].y); + ao += xSampleWeightTable[0].w * TestSamples(thisIdx, 4, 0, invThisDepth, xInvThicknessTable[0].w); + ao += xSampleWeightTable[1].x * TestSamples(thisIdx, 1, 1, invThisDepth, xInvThicknessTable[1].x); + ao += xSampleWeightTable[2].x * TestSamples(thisIdx, 2, 2, invThisDepth, xInvThicknessTable[2].x); + ao += xSampleWeightTable[2].w * TestSamples(thisIdx, 3, 3, invThisDepth, xInvThicknessTable[2].w); + ao += xSampleWeightTable[1].z * TestSamples(thisIdx, 1, 3, invThisDepth, xInvThicknessTable[1].z); + ao += xSampleWeightTable[2].z * TestSamples(thisIdx, 2, 4, invThisDepth, xInvThicknessTable[2].z); +#endif // MSAO_SAMPLE_EXHAUSTIVELY + +#ifdef INTERLEAVE_RESULT + uint2 OutPixel = DTid.xy << 2 | uint2(DTid.z & 3, DTid.z >> 2); +#else + uint2 OutPixel = DTid.xy; +#endif // INTERLEAVE_RESULT + output[OutPixel] = ao * xRcpAccentuation; +} diff --git a/WickedEngine/msao_blurupsampleCS.hlsl b/WickedEngine/msao_blurupsampleCS.hlsl new file mode 100644 index 000000000..f69ad13e7 --- /dev/null +++ b/WickedEngine/msao_blurupsampleCS.hlsl @@ -0,0 +1,201 @@ +// This is a modified version of the SSAO from Microsoft MiniEngine at https://github.com/Microsoft/DirectX-Graphics-Samples + +#include "globals.hlsli" +#include "ShaderInterop_Postprocess.h" + +TEXTURE2D(LoResDB, float, TEXSLOT_ONDEMAND0); +TEXTURE2D(HiResDB, float, TEXSLOT_ONDEMAND1); +TEXTURE2D(LoResAO1, float, TEXSLOT_ONDEMAND2); +#ifdef COMBINE_LOWER_RESOLUTIONS +TEXTURE2D(LoResAO2, float, TEXSLOT_ONDEMAND3); +#endif +#ifdef BLEND_WITH_HIGHER_RESOLUTION +TEXTURE2D(HiResAO, float, TEXSLOT_ONDEMAND4); +#endif + +RWTEXTURE2D(AoResult, unorm float, 0); + +groupshared float DepthCache[256]; +groupshared float AOCache1[256]; +groupshared float AOCache2[256]; + +void PrefetchData(uint index, float2 uv) +{ + float4 AO1 = LoResAO1.Gather(sampler_linear_clamp, uv); + +#ifdef COMBINE_LOWER_RESOLUTIONS + AO1 = min(AO1, LoResAO2.Gather(sampler_linear_clamp, uv)); +#endif + + AOCache1[index] = AO1.w; + AOCache1[index + 1] = AO1.z; + AOCache1[index + 16] = AO1.x; + AOCache1[index + 17] = AO1.y; + + float4 ID = 1.0 / LoResDB.Gather(sampler_linear_clamp, uv); + DepthCache[index] = ID.w; + DepthCache[index + 1] = ID.z; + DepthCache[index + 16] = ID.x; + DepthCache[index + 17] = ID.y; +} + +float SmartBlur(float a, float b, float c, float d, float e, bool Left, bool Middle, bool Right) +{ + b = Left | Middle ? b : c; + a = Left ? a : b; + d = Right | Middle ? d : c; + e = Right ? e : d; + return ((a + e) / 2.0 + b + c + d) / 4.0; +} + +bool CompareDeltas(float d1, float d2, float l1, float l2) +{ + float temp = d1 * d2 + StepSize; + return temp * temp > l1 * l2 * kBlurTolerance; +} + +void BlurHorizontally(uint leftMostIndex) +{ + float a0 = AOCache1[leftMostIndex]; + float a1 = AOCache1[leftMostIndex + 1]; + float a2 = AOCache1[leftMostIndex + 2]; + float a3 = AOCache1[leftMostIndex + 3]; + float a4 = AOCache1[leftMostIndex + 4]; + float a5 = AOCache1[leftMostIndex + 5]; + float a6 = AOCache1[leftMostIndex + 6]; + + float d0 = DepthCache[leftMostIndex]; + float d1 = DepthCache[leftMostIndex + 1]; + float d2 = DepthCache[leftMostIndex + 2]; + float d3 = DepthCache[leftMostIndex + 3]; + float d4 = DepthCache[leftMostIndex + 4]; + float d5 = DepthCache[leftMostIndex + 5]; + float d6 = DepthCache[leftMostIndex + 6]; + + float d01 = d1 - d0; + float d12 = d2 - d1; + float d23 = d3 - d2; + float d34 = d4 - d3; + float d45 = d5 - d4; + float d56 = d6 - d5; + + float l01 = d01 * d01 + StepSize; + float l12 = d12 * d12 + StepSize; + float l23 = d23 * d23 + StepSize; + float l34 = d34 * d34 + StepSize; + float l45 = d45 * d45 + StepSize; + float l56 = d56 * d56 + StepSize; + + bool c02 = CompareDeltas(d01, d12, l01, l12); + bool c13 = CompareDeltas(d12, d23, l12, l23); + bool c24 = CompareDeltas(d23, d34, l23, l34); + bool c35 = CompareDeltas(d34, d45, l34, l45); + bool c46 = CompareDeltas(d45, d56, l45, l56); + + AOCache2[leftMostIndex] = SmartBlur(a0, a1, a2, a3, a4, c02, c13, c24); + AOCache2[leftMostIndex + 1] = SmartBlur(a1, a2, a3, a4, a5, c13, c24, c35); + AOCache2[leftMostIndex + 2] = SmartBlur(a2, a3, a4, a5, a6, c24, c35, c46); +} + +void BlurVertically(uint topMostIndex) +{ + float a0 = AOCache2[topMostIndex]; + float a1 = AOCache2[topMostIndex + 16]; + float a2 = AOCache2[topMostIndex + 32]; + float a3 = AOCache2[topMostIndex + 48]; + float a4 = AOCache2[topMostIndex + 64]; + float a5 = AOCache2[topMostIndex + 80]; + + float d0 = DepthCache[topMostIndex + 2]; + float d1 = DepthCache[topMostIndex + 18]; + float d2 = DepthCache[topMostIndex + 34]; + float d3 = DepthCache[topMostIndex + 50]; + float d4 = DepthCache[topMostIndex + 66]; + float d5 = DepthCache[topMostIndex + 82]; + + float d01 = d1 - d0; + float d12 = d2 - d1; + float d23 = d3 - d2; + float d34 = d4 - d3; + float d45 = d5 - d4; + + float l01 = d01 * d01 + StepSize; + float l12 = d12 * d12 + StepSize; + float l23 = d23 * d23 + StepSize; + float l34 = d34 * d34 + StepSize; + float l45 = d45 * d45 + StepSize; + + bool c02 = CompareDeltas(d01, d12, l01, l12); + bool c13 = CompareDeltas(d12, d23, l12, l23); + bool c24 = CompareDeltas(d23, d34, l23, l34); + bool c35 = CompareDeltas(d34, d45, l34, l45); + + float aoResult1 = SmartBlur(a0, a1, a2, a3, a4, c02, c13, c24); + float aoResult2 = SmartBlur(a1, a2, a3, a4, a5, c13, c24, c35); + + AOCache1[topMostIndex] = aoResult1; + AOCache1[topMostIndex + 16] = aoResult2; +} + +// We essentially want 5 weights: 4 for each low-res pixel and 1 to blend in when none of the 4 really +// match. The filter strength is 1 / DeltaZTolerance. So a tolerance of 0.01 would yield a strength of 100. +// Note that a perfect match of low to high depths would yield a weight of 10^6, completely superceding any +// noise filtering. The noise filter is intended to soften the effects of shimmering when the high-res depth +// buffer has a lot of small holes in it causing the low-res depth buffer to inaccurately represent it. +float BilateralUpsample(float HiDepth, float HiAO, float4 LowDepths, float4 LowAO) +{ + float4 weights = float4(9, 3, 1, 3) / (abs(HiDepth - LowDepths) + kUpsampleTolerance); + float TotalWeight = dot(weights, 1) + NoiseFilterStrength; + float WeightedSum = dot(LowAO, weights) + NoiseFilterStrength;// * HiAO; + return HiAO * WeightedSum / TotalWeight; +} + +[numthreads(8, 8, 1)] +void main(uint3 Gid : SV_GroupID, uint GI : SV_GroupIndex, uint3 GTid : SV_GroupThreadID, uint3 DTid : SV_DispatchThreadID) +{ + // + // Load 4 pixels per thread into LDS to fill the 16x16 LDS cache with depth and AO + // + PrefetchData(GTid.x << 1 | GTid.y << 5, int2(DTid.xy + GTid.xy - 2) * InvLowResolution); + GroupMemoryBarrierWithGroupSync(); + + // Goal: End up with a 9x9 patch that is blurred so we can upsample. Blur radius is 2 pixels, so start with 13x13 area. + + // + // Horizontally blur the pixels. 13x13 -> 9x13 + // + if (GI < 39) + BlurHorizontally((GI / 3) * 16 + (GI % 3) * 3); + GroupMemoryBarrierWithGroupSync(); + + // + // Vertically blur the pixels. 9x13 -> 9x9 + // + if (GI < 45) + BlurVertically((GI / 9) * 32 + GI % 9); + GroupMemoryBarrierWithGroupSync(); + + // + // Bilateral upsample + // + uint Idx0 = GTid.x + GTid.y * 16; + float4 LoSSAOs = float4(AOCache1[Idx0 + 16], AOCache1[Idx0 + 17], AOCache1[Idx0 + 1], AOCache1[Idx0]); + + // We work on a quad of pixels at once because then we can gather 4 each of high and low-res depth values + float2 UV0 = DTid.xy * InvLowResolution; + float2 UV1 = DTid.xy * 2 * InvHighResolution; + +#ifdef BLEND_WITH_HIGHER_RESOLUTION + float4 HiSSAOs = HiResAO.Gather(sampler_linear_clamp, UV1); +#else + float4 HiSSAOs = 1.0; +#endif + float4 LoDepths = LoResDB.Gather(sampler_linear_clamp, UV0); + float4 HiDepths = HiResDB.Gather(sampler_linear_clamp, UV1); + + int2 OutST = DTid.xy << 1; + AoResult[OutST + int2(-1, 0)] = BilateralUpsample(HiDepths.x, HiSSAOs.x, LoDepths.xyzw, LoSSAOs.xyzw); + AoResult[OutST + int2(0, 0)] = BilateralUpsample(HiDepths.y, HiSSAOs.y, LoDepths.yzwx, LoSSAOs.yzwx); + AoResult[OutST + int2(0, -1)] = BilateralUpsample(HiDepths.z, HiSSAOs.z, LoDepths.zwxy, LoSSAOs.zwxy); + AoResult[OutST + int2(-1, -1)] = BilateralUpsample(HiDepths.w, HiSSAOs.w, LoDepths.wxyz, LoSSAOs.wxyz); +} diff --git a/WickedEngine/msao_blurupsampleCS_blendout.hlsl b/WickedEngine/msao_blurupsampleCS_blendout.hlsl new file mode 100644 index 000000000..edf8e9443 --- /dev/null +++ b/WickedEngine/msao_blurupsampleCS_blendout.hlsl @@ -0,0 +1,2 @@ +#define BLEND_WITH_HIGHER_RESOLUTION +#include "msao_blurupsampleCS.hlsl" diff --git a/WickedEngine/msao_blurupsampleCS_premin.hlsl b/WickedEngine/msao_blurupsampleCS_premin.hlsl new file mode 100644 index 000000000..524aae2cf --- /dev/null +++ b/WickedEngine/msao_blurupsampleCS_premin.hlsl @@ -0,0 +1,2 @@ +#define COMBINE_LOWER_RESOLUTIONS +#include "msao_blurupsampleCS.hlsl" diff --git a/WickedEngine/msao_blurupsampleCS_premin_blendout.hlsl b/WickedEngine/msao_blurupsampleCS_premin_blendout.hlsl new file mode 100644 index 000000000..240348eee --- /dev/null +++ b/WickedEngine/msao_blurupsampleCS_premin_blendout.hlsl @@ -0,0 +1,3 @@ +#define COMBINE_LOWER_RESOLUTIONS +#define BLEND_WITH_HIGHER_RESOLUTION +#include "msao_blurupsampleCS.hlsl" diff --git a/WickedEngine/msao_interleaveCS.hlsl b/WickedEngine/msao_interleaveCS.hlsl new file mode 100644 index 000000000..6b62198c8 --- /dev/null +++ b/WickedEngine/msao_interleaveCS.hlsl @@ -0,0 +1,2 @@ +#define INTERLEAVE_RESULT +#include "msaoCS.hlsl" diff --git a/WickedEngine/msao_preparedepthbuffers1CS.hlsl b/WickedEngine/msao_preparedepthbuffers1CS.hlsl new file mode 100644 index 000000000..1bd99c0ef --- /dev/null +++ b/WickedEngine/msao_preparedepthbuffers1CS.hlsl @@ -0,0 +1,42 @@ +// This is a modified version of the SSAO from Microsoft MiniEngine at https://github.com/Microsoft/DirectX-Graphics-Samples + +#include "globals.hlsli" +#include "ShaderInterop_Postprocess.h" + +RWTEXTURE2D(DS2x, float2, 0); +RWTEXTURE2DARRAY(DS2xAtlas, float, 1); +RWTEXTURE2D(DS4x, float2, 2); +RWTEXTURE2DARRAY(DS4xAtlas, float, 3); + +groupshared float g_CacheW[256]; + +[numthreads(8, 8, 1)] +void main(uint3 Gid : SV_GroupID, uint GI : SV_GroupIndex, uint3 GTid : SV_GroupThreadID, uint3 DTid : SV_DispatchThreadID) +{ + uint2 startST = Gid.xy << 4 | GTid.xy; + uint destIdx = GTid.y << 4 | GTid.x; + g_CacheW[destIdx + 0] = texture_lineardepth[startST | uint2(0, 0)]; + g_CacheW[destIdx + 8] = texture_lineardepth[startST | uint2(8, 0)]; + g_CacheW[destIdx + 128] = texture_lineardepth[startST | uint2(0, 8)]; + g_CacheW[destIdx + 136] = texture_lineardepth[startST | uint2(8, 8)]; + + GroupMemoryBarrierWithGroupSync(); + + uint ldsIndex = (GTid.x << 1) | (GTid.y << 5); + + float w1 = g_CacheW[ldsIndex]; + + uint2 st = DTid.xy; + uint slice = (st.x & 3) | ((st.y & 3) << 2); + DS2x[st] = w1; + DS2xAtlas[uint3(st >> 2, slice)] = w1; + + if ((GI & 011) == 0) + { + st = DTid.xy >> 1; + slice = (st.x & 3) | ((st.y & 3) << 2); + DS4x[st] = w1; + DS4xAtlas[uint3(st >> 2, slice)] = w1; + } + +} diff --git a/WickedEngine/msao_preparedepthbuffers2CS.hlsl b/WickedEngine/msao_preparedepthbuffers2CS.hlsl new file mode 100644 index 000000000..acfa4d25b --- /dev/null +++ b/WickedEngine/msao_preparedepthbuffers2CS.hlsl @@ -0,0 +1,31 @@ +// This is a modified version of the SSAO from Microsoft MiniEngine at https://github.com/Microsoft/DirectX-Graphics-Samples + +#include "globals.hlsli" +#include "ShaderInterop_Postprocess.h" + +TEXTURE2D(DS4x, float, TEXSLOT_ONDEMAND0); +RWTEXTURE2D(DS8x, float, 0); +RWTEXTURE2DARRAY(DS8xAtlas, float, 1); +RWTEXTURE2D(DS16x, float, 2); +RWTEXTURE2DARRAY(DS16xAtlas, float, 3); + +[numthreads(8, 8, 1)] +void main(uint3 Gid : SV_GroupID, uint GI : SV_GroupIndex, uint3 GTid : SV_GroupThreadID, uint3 DTid : SV_DispatchThreadID) +{ + float m1 = DS4x[DTid.xy << 1]; + + uint2 st = DTid.xy; + uint2 stAtlas = st >> 2; + uint stSlice = (st.x & 3) | ((st.y & 3) << 2); + DS8x[st] = m1; + DS8xAtlas[uint3(stAtlas, stSlice)] = m1; + + if ((GI & 011) == 0) + { + uint2 st = DTid.xy >> 1; + uint2 stAtlas = st >> 2; + uint stSlice = (st.x & 3) | ((st.y & 3) << 2); + DS16x[st] = m1; + DS16xAtlas[uint3(stAtlas, stSlice)] = m1; + } +} diff --git a/WickedEngine/objectHF.hlsli b/WickedEngine/objectHF.hlsli index e731495c5..e9d802af7 100644 --- a/WickedEngine/objectHF.hlsli +++ b/WickedEngine/objectHF.hlsli @@ -38,7 +38,7 @@ TEXTURE2D(texture_occlusionmap, float, TEXSLOT_RENDERER_OCCLUSIONMAP); // r: o TEXTURE2D(texture_reflection, float4, TEXSLOT_RENDERPATH_REFLECTION); // rgba: scene color from reflected camera angle TEXTURE2D(texture_refraction, float4, TEXSLOT_RENDERPATH_REFRACTION); // rgba: scene color from primary camera angle TEXTURE2D(texture_waterriples, float4, TEXSLOT_RENDERPATH_WATERRIPPLES); // rgb: snorm8 water ripple normal map -TEXTURE2D(texture_ssao, float, TEXSLOT_RENDERPATH_SSAO); // r: screen space ambient occlusion +TEXTURE2D(texture_ao, float, TEXSLOT_RENDERPATH_AO); // r: ambient occlusion TEXTURE2D(texture_ssr, float4, TEXSLOT_RENDERPATH_SSR); // rgb: screen space ray-traced reflections, a: reflection blend based on ray hit or miss @@ -818,8 +818,7 @@ GBUFFEROutputType_Thin main(PIXELINPUT input) #ifndef SIMPLE_INPUT #ifndef ENVMAPRENDERING #ifndef TRANSPARENT - const float ssao = texture_ssao.SampleLevel(sampler_linear_clamp, ScreenCoord, 0).r; - surface_occlusion_roughness_metallic_reflectance.r *= ssao; + surface_occlusion_roughness_metallic_reflectance.r *= texture_ao.SampleLevel(sampler_linear_clamp, ScreenCoord, 0).r; #endif // TRANSPARENT #endif // ENVMAPRENDERING #endif // SIMPLE_INPUT diff --git a/WickedEngine/wiEnums.h b/WickedEngine/wiEnums.h index 6da548693..ae5e67987 100644 --- a/WickedEngine/wiEnums.h +++ b/WickedEngine/wiEnums.h @@ -73,6 +73,8 @@ enum CBTYPES CBTYPE_COPYTEXTURE, CBTYPE_FORWARDENTITYMASK, CBTYPE_POSTPROCESS, + CBTYPE_POSTPROCESS_MSAO, + CBTYPE_POSTPROCESS_MSAO_UPSAMPLE, CBTYPE_LENSFLARE, CBTYPE_COUNT }; @@ -311,6 +313,14 @@ enum CSTYPES CSTYPE_POSTPROCESS_BLUR_BILATERAL_WIDE_UNORM4, CSTYPE_POSTPROCESS_SSAO, CSTYPE_POSTPROCESS_HBAO, + CSTYPE_POSTPROCESS_MSAO_PREPAREDEPTHBUFFERS1, + CSTYPE_POSTPROCESS_MSAO_PREPAREDEPTHBUFFERS2, + CSTYPE_POSTPROCESS_MSAO_INTERLEAVE, + CSTYPE_POSTPROCESS_MSAO, + CSTYPE_POSTPROCESS_MSAO_BLURUPSAMPLE, + CSTYPE_POSTPROCESS_MSAO_BLURUPSAMPLE_BLENDOUT, + CSTYPE_POSTPROCESS_MSAO_BLURUPSAMPLE_PREMIN, + CSTYPE_POSTPROCESS_MSAO_BLURUPSAMPLE_PREMIN_BLENDOUT, CSTYPE_POSTPROCESS_SSR_RAYTRACE, CSTYPE_POSTPROCESS_SSR_RESOLVE, CSTYPE_POSTPROCESS_SSR_TEMPORAL, diff --git a/WickedEngine/wiRenderer.cpp b/WickedEngine/wiRenderer.cpp index 0703b06f2..67b536dad 100644 --- a/WickedEngine/wiRenderer.cpp +++ b/WickedEngine/wiRenderer.cpp @@ -1345,6 +1345,14 @@ void LoadShaders() wiJobSystem::Execute(ctx, [] { LoadShader(CS, computeShaders[CSTYPE_POSTPROCESS_BLUR_BILATERAL_WIDE_UNORM4], "blur_bilateral_wide_unorm4CS.cso"); }); wiJobSystem::Execute(ctx, [] { LoadShader(CS, computeShaders[CSTYPE_POSTPROCESS_SSAO], "ssaoCS.cso"); }); wiJobSystem::Execute(ctx, [] { LoadShader(CS, computeShaders[CSTYPE_POSTPROCESS_HBAO], "hbaoCS.cso"); }); + wiJobSystem::Execute(ctx, [] { LoadShader(CS, computeShaders[CSTYPE_POSTPROCESS_MSAO_PREPAREDEPTHBUFFERS1], "msao_preparedepthbuffers1CS.cso"); }); + wiJobSystem::Execute(ctx, [] { LoadShader(CS, computeShaders[CSTYPE_POSTPROCESS_MSAO_PREPAREDEPTHBUFFERS2], "msao_preparedepthbuffers2CS.cso"); }); + wiJobSystem::Execute(ctx, [] { LoadShader(CS, computeShaders[CSTYPE_POSTPROCESS_MSAO_INTERLEAVE], "msao_interleaveCS.cso"); }); + wiJobSystem::Execute(ctx, [] { LoadShader(CS, computeShaders[CSTYPE_POSTPROCESS_MSAO], "msaoCS.cso"); }); + wiJobSystem::Execute(ctx, [] { LoadShader(CS, computeShaders[CSTYPE_POSTPROCESS_MSAO_BLURUPSAMPLE], "msao_blurupsampleCS.cso"); }); + wiJobSystem::Execute(ctx, [] { LoadShader(CS, computeShaders[CSTYPE_POSTPROCESS_MSAO_BLURUPSAMPLE_BLENDOUT], "msao_blurupsampleCS_blendout.cso"); }); + wiJobSystem::Execute(ctx, [] { LoadShader(CS, computeShaders[CSTYPE_POSTPROCESS_MSAO_BLURUPSAMPLE_PREMIN], "msao_blurupsampleCS_premin.cso"); }); + wiJobSystem::Execute(ctx, [] { LoadShader(CS, computeShaders[CSTYPE_POSTPROCESS_MSAO_BLURUPSAMPLE_PREMIN_BLENDOUT], "msao_blurupsampleCS_premin_blendout.cso"); }); wiJobSystem::Execute(ctx, [] { LoadShader(CS, computeShaders[CSTYPE_POSTPROCESS_SSR_RAYTRACE], "ssr_raytraceCS.cso"); }); wiJobSystem::Execute(ctx, [] { LoadShader(CS, computeShaders[CSTYPE_POSTPROCESS_SSR_RESOLVE], "ssr_resolveCS.cso"); }); wiJobSystem::Execute(ctx, [] { LoadShader(CS, computeShaders[CSTYPE_POSTPROCESS_SSR_TEMPORAL], "ssr_temporalCS.cso"); }); @@ -2153,6 +2161,14 @@ void LoadBuffers() device->CreateBuffer(&bd, nullptr, &constantBuffers[CBTYPE_POSTPROCESS]); device->SetName(&constantBuffers[CBTYPE_POSTPROCESS], "PostProcessCB"); + bd.ByteWidth = sizeof(MSAOCB); + device->CreateBuffer(&bd, nullptr, &constantBuffers[CBTYPE_POSTPROCESS_MSAO]); + device->SetName(&constantBuffers[CBTYPE_POSTPROCESS_MSAO], "MSAOCB"); + + bd.ByteWidth = sizeof(MSAO_UPSAMPLECB); + device->CreateBuffer(&bd, nullptr, &constantBuffers[CBTYPE_POSTPROCESS_MSAO_UPSAMPLE]); + device->SetName(&constantBuffers[CBTYPE_POSTPROCESS_MSAO_UPSAMPLE], "MSAO_UPSAMPLECB"); + bd.ByteWidth = sizeof(LensFlareCB); device->CreateBuffer(&bd, nullptr, &constantBuffers[CBTYPE_LENSFLARE]); device->SetName(&constantBuffers[CBTYPE_LENSFLARE], "LensFlareCB"); @@ -8773,7 +8789,6 @@ void Postprocess_SSAO( const Texture& depthbuffer, const Texture& lineardepth, const Texture& lineardepth_minmax, - const Texture& temp, const Texture& output, CommandList cmd, float range, @@ -8786,15 +8801,29 @@ void Postprocess_SSAO( device->EventBegin("Postprocess_SSAO", cmd); auto prof_range = wiProfiler::BeginRangeGPU("SSAO", cmd); - device->UnbindResources(TEXSLOT_RENDERPATH_SSAO, 1, cmd); + static TextureDesc saved_desc; + static Texture temp0; + static Texture temp1; + + const TextureDesc& lineardepth_desc = lineardepth.GetDesc(); + if (saved_desc.Width != lineardepth_desc.Width || saved_desc.Height != lineardepth_desc.Height) + { + saved_desc = lineardepth_desc; // <- this must already have SRV and UAV request flags set up! + + TextureDesc desc = saved_desc; + desc.Format = FORMAT_R8_UNORM; + desc.Width = (desc.Width + 1) / 2; + desc.Height = (desc.Height + 1) / 2; + device->CreateTexture(&desc, nullptr, &temp0); + device->CreateTexture(&desc, nullptr, &temp1); + } device->BindComputeShader(&computeShaders[CSTYPE_POSTPROCESS_SSAO], cmd); device->BindResource(CS, &depthbuffer, TEXSLOT_DEPTH, cmd); - device->BindResource(CS, &lineardepth, TEXSLOT_LINEARDEPTH, cmd); device->BindResource(CS, &lineardepth_minmax, TEXSLOT_ONDEMAND0, cmd); - const TextureDesc& desc = output.GetDesc(); + const TextureDesc& desc = temp0.GetDesc(); PostProcessCB cb; cb.xPPResolution.x = desc.Width; @@ -8808,7 +8837,7 @@ void Postprocess_SSAO( device->BindConstantBuffer(CS, &constantBuffers[CBTYPE_POSTPROCESS], CB_GETBINDSLOT(PostProcessCB), cmd); const GPUResource* uavs[] = { - &output, + &temp0, }; device->BindUAVs(CS, uavs, 0, arraysize(uavs), cmd); @@ -8822,14 +8851,15 @@ void Postprocess_SSAO( device->Barrier(&GPUBarrier::Memory(), 1, cmd); device->UnbindUAVs(0, arraysize(uavs), cmd); - Postprocess_Blur_Bilateral(output, lineardepth_minmax, temp, output, cmd, 1.2f, -1, -1, true); + Postprocess_Blur_Bilateral(temp0, lineardepth_minmax, temp1, temp0, cmd, 1.2f, -1, -1, true); + Postprocess_Upsample_Bilateral(temp0, lineardepth, lineardepth_minmax, output, cmd); wiProfiler::EndRange(prof_range); device->EventEnd(cmd); } void Postprocess_HBAO( + const Texture& lineardepth, const Texture& lineardepth_minmax, - const Texture& temp, const Texture& output, CommandList cmd, float power @@ -8840,13 +8870,28 @@ void Postprocess_HBAO( device->EventBegin("Postprocess_HBAO", cmd); auto prof_range = wiProfiler::BeginRangeGPU("HBAO", cmd); - device->UnbindResources(TEXSLOT_RENDERPATH_SSAO, 1, cmd); + static TextureDesc saved_desc; + static Texture temp0; + static Texture temp1; + + const TextureDesc& lineardepth_desc = lineardepth.GetDesc(); + if (saved_desc.Width != lineardepth_desc.Width || saved_desc.Height != lineardepth_desc.Height) + { + saved_desc = lineardepth_desc; // <- this must already have SRV and UAV request flags set up! + + TextureDesc desc = saved_desc; + desc.Format = FORMAT_R8_UNORM; + desc.Width = (desc.Width + 1) / 2; + desc.Height = (desc.Height + 1) / 2; + device->CreateTexture(&desc, nullptr, &temp0); + device->CreateTexture(&desc, nullptr, &temp1); + } device->BindComputeShader(&computeShaders[CSTYPE_POSTPROCESS_HBAO], cmd); device->BindResource(CS, &lineardepth_minmax, TEXSLOT_ONDEMAND0, cmd); - const TextureDesc& desc = output.GetDesc(); + const TextureDesc& desc = temp0.GetDesc(); PostProcessCB cb; cb.xPPResolution.x = desc.Width; @@ -8858,8 +8903,10 @@ void Postprocess_HBAO( cb.hbao_power = power; const CameraComponent& camera = GetCamera(); - const float FocalLenX = 1.0f / tanf(camera.fov * 0.5f) * ((float)cb.xPPResolution.y / (float)cb.xPPResolution.x); - const float FocalLenY = 1.0f / tanf(camera.fov * 0.5f); + // Load first element of projection matrix which is the cotangent of the horizontal FOV divided by 2. + const float TanHalfFovH = 1.0f / camera.Projection.m[0][0]; + const float FocalLenX = 1.0f / TanHalfFovH * ((float)cb.xPPResolution.y / (float)cb.xPPResolution.x); + const float FocalLenY = 1.0f / TanHalfFovH; const float InvFocalLenX = 1.0f / FocalLenX; const float InvFocalLenY = 1.0f / FocalLenY; const float UVToViewAX = 2.0f * InvFocalLenX; @@ -8878,7 +8925,7 @@ void Postprocess_HBAO( { device->BindResource(CS, wiTextureHelper::getWhite(), TEXSLOT_ONDEMAND1, cmd); const GPUResource* uavs[] = { - &temp, + &temp1, }; device->BindUAVs(CS, uavs, 0, arraysize(uavs), cmd); @@ -8900,9 +8947,9 @@ void Postprocess_HBAO( device->UpdateBuffer(&constantBuffers[CBTYPE_POSTPROCESS], &cb, cmd); device->BindConstantBuffer(CS, &constantBuffers[CBTYPE_POSTPROCESS], CB_GETBINDSLOT(PostProcessCB), cmd); - device->BindResource(CS, &temp, TEXSLOT_ONDEMAND1, cmd); + device->BindResource(CS, &temp1, TEXSLOT_ONDEMAND1, cmd); const GPUResource* uavs[] = { - &output, + &temp0, }; device->BindUAVs(CS, uavs, 0, arraysize(uavs), cmd); @@ -8918,7 +8965,419 @@ void Postprocess_HBAO( device->UnbindResources(TEXSLOT_ONDEMAND1, 1, cmd); } - Postprocess_Blur_Bilateral(output, lineardepth_minmax, temp, output, cmd, 1.2f, -1, -1, true); + Postprocess_Blur_Bilateral(temp0, lineardepth_minmax, temp1, temp0, cmd, 1.2f, -1, -1, true); + Postprocess_Upsample_Bilateral(temp0, lineardepth, lineardepth_minmax, output, cmd); + + wiProfiler::EndRange(prof_range); + device->EventEnd(cmd); +} +void Postprocess_MSAO( + const Texture& lineardepth, + const Texture& lineardepth_minmax, + const Texture& output, + CommandList cmd, + float power + ) +{ + GraphicsDevice* device = GetDevice(); + + device->EventBegin("Postprocess_MSAO", cmd); + auto prof_range = wiProfiler::BeginRangeGPU("MSAO", cmd); + + static TextureDesc saved_desc; + static Texture texture_lineardepth_downsize1; + static Texture texture_lineardepth_tiled1; + static Texture texture_lineardepth_downsize2; + static Texture texture_lineardepth_tiled2; + static Texture texture_lineardepth_downsize3; + static Texture texture_lineardepth_tiled3; + static Texture texture_lineardepth_downsize4; + static Texture texture_lineardepth_tiled4; + static Texture texture_ao_merged1; + static Texture texture_ao_hq1; + static Texture texture_ao_smooth1; + static Texture texture_ao_merged2; + static Texture texture_ao_hq2; + static Texture texture_ao_smooth2; + static Texture texture_ao_merged3; + static Texture texture_ao_hq3; + static Texture texture_ao_smooth3; + static Texture texture_ao_merged4; + static Texture texture_ao_hq4; + + const TextureDesc& lineardepth_desc = lineardepth.GetDesc(); + if (saved_desc.Width != lineardepth_desc.Width || saved_desc.Height != lineardepth_desc.Height) + { + saved_desc = lineardepth_desc; // <- this must already have SRV and UAV request flags set up! + + const uint32_t bufferWidth = saved_desc.Width; + const uint32_t bufferWidth1 = (bufferWidth + 1) / 2; + const uint32_t bufferWidth2 = (bufferWidth + 3) / 4; + const uint32_t bufferWidth3 = (bufferWidth + 7) / 8; + const uint32_t bufferWidth4 = (bufferWidth + 15) / 16; + const uint32_t bufferWidth5 = (bufferWidth + 31) / 32; + const uint32_t bufferWidth6 = (bufferWidth + 63) / 64; + const uint32_t bufferHeight = saved_desc.Height; + const uint32_t bufferHeight1 = (bufferHeight + 1) / 2; + const uint32_t bufferHeight2 = (bufferHeight + 3) / 4; + const uint32_t bufferHeight3 = (bufferHeight + 7) / 8; + const uint32_t bufferHeight4 = (bufferHeight + 15) / 16; + const uint32_t bufferHeight5 = (bufferHeight + 31) / 32; + const uint32_t bufferHeight6 = (bufferHeight + 63) / 64; + + TextureDesc desc = saved_desc; + desc.Width = bufferWidth1; + desc.Height = bufferHeight1; + device->CreateTexture(&desc, nullptr, &texture_lineardepth_downsize1); + desc.Width = bufferWidth3; + desc.Height = bufferHeight3; + desc.ArraySize = 16; + desc.Format = FORMAT_R16_FLOAT; + device->CreateTexture(&desc, nullptr, &texture_lineardepth_tiled1); + + desc = saved_desc; + desc.Width = bufferWidth2; + desc.Height = bufferHeight2; + device->CreateTexture(&desc, nullptr, &texture_lineardepth_downsize2); + desc.Width = bufferWidth4; + desc.Height = bufferHeight4; + desc.ArraySize = 16; + desc.Format = FORMAT_R16_FLOAT; + device->CreateTexture(&desc, nullptr, &texture_lineardepth_tiled2); + + desc = saved_desc; + desc.Width = bufferWidth3; + desc.Height = bufferHeight3; + device->CreateTexture(&desc, nullptr, &texture_lineardepth_downsize3); + desc.Width = bufferWidth5; + desc.Height = bufferHeight5; + desc.ArraySize = 16; + desc.Format = FORMAT_R16_FLOAT; + device->CreateTexture(&desc, nullptr, &texture_lineardepth_tiled3); + + desc = saved_desc; + desc.Width = bufferWidth4; + desc.Height = bufferHeight4; + device->CreateTexture(&desc, nullptr, &texture_lineardepth_downsize4); + desc.Width = bufferWidth6; + desc.Height = bufferHeight6; + desc.ArraySize = 16; + desc.Format = FORMAT_R16_FLOAT; + device->CreateTexture(&desc, nullptr, &texture_lineardepth_tiled4); + + desc = saved_desc; + desc.Format = FORMAT_R8_UNORM; + desc.Width = bufferWidth1; + desc.Height = bufferHeight1; + device->CreateTexture(&desc, nullptr, &texture_ao_merged1); + device->CreateTexture(&desc, nullptr, &texture_ao_hq1); + device->CreateTexture(&desc, nullptr, &texture_ao_smooth1); + desc.Width = bufferWidth2; + desc.Height = bufferHeight2; + device->CreateTexture(&desc, nullptr, &texture_ao_merged2); + device->CreateTexture(&desc, nullptr, &texture_ao_hq2); + device->CreateTexture(&desc, nullptr, &texture_ao_smooth2); + desc.Width = bufferWidth3; + desc.Height = bufferHeight3; + device->CreateTexture(&desc, nullptr, &texture_ao_merged3); + device->CreateTexture(&desc, nullptr, &texture_ao_hq3); + device->CreateTexture(&desc, nullptr, &texture_ao_smooth3); + desc.Width = bufferWidth4; + desc.Height = bufferHeight4; + device->CreateTexture(&desc, nullptr, &texture_ao_merged4); + device->CreateTexture(&desc, nullptr, &texture_ao_hq4); + } + + // Depth downsampling + deinterleaving pass1: + { + device->BindComputeShader(&computeShaders[CSTYPE_POSTPROCESS_MSAO_PREPAREDEPTHBUFFERS1], cmd); + + device->BindResource(CS, &lineardepth, TEXSLOT_LINEARDEPTH, cmd); + + const GPUResource* uavs[] = { + &texture_lineardepth_downsize1, + &texture_lineardepth_tiled1, + &texture_lineardepth_downsize2, + &texture_lineardepth_tiled2, + }; + device->BindUAVs(CS, uavs, 0, arraysize(uavs), cmd); + + const TextureDesc& desc = texture_lineardepth_tiled2.GetDesc(); + device->Dispatch(desc.Width, desc.Height, 1, cmd); + + device->Barrier(&GPUBarrier::Memory(), 1, cmd); + device->UnbindUAVs(0, arraysize(uavs), cmd); + } + + // Depth downsampling + deinterleaving pass2: + { + device->BindComputeShader(&computeShaders[CSTYPE_POSTPROCESS_MSAO_PREPAREDEPTHBUFFERS2], cmd); + + device->BindResource(CS, &texture_lineardepth_downsize2, TEXSLOT_ONDEMAND0, cmd); + + const GPUResource* uavs[] = { + &texture_lineardepth_downsize3, + &texture_lineardepth_tiled3, + &texture_lineardepth_downsize4, + &texture_lineardepth_tiled4, + }; + device->BindUAVs(CS, uavs, 0, arraysize(uavs), cmd); + + const TextureDesc& desc = texture_lineardepth_tiled4.GetDesc(); + device->Dispatch(desc.Width, desc.Height, 1, cmd); + + device->Barrier(&GPUBarrier::Memory(), 1, cmd); + device->UnbindUAVs(0, arraysize(uavs), cmd); + } + + + float SampleThickness[12]; + SampleThickness[0] = sqrt(1.0f - 0.2f * 0.2f); + SampleThickness[1] = sqrt(1.0f - 0.4f * 0.4f); + SampleThickness[2] = sqrt(1.0f - 0.6f * 0.6f); + SampleThickness[3] = sqrt(1.0f - 0.8f * 0.8f); + SampleThickness[4] = sqrt(1.0f - 0.2f * 0.2f - 0.2f * 0.2f); + SampleThickness[5] = sqrt(1.0f - 0.2f * 0.2f - 0.4f * 0.4f); + SampleThickness[6] = sqrt(1.0f - 0.2f * 0.2f - 0.6f * 0.6f); + SampleThickness[7] = sqrt(1.0f - 0.2f * 0.2f - 0.8f * 0.8f); + SampleThickness[8] = sqrt(1.0f - 0.4f * 0.4f - 0.4f * 0.4f); + SampleThickness[9] = sqrt(1.0f - 0.4f * 0.4f - 0.6f * 0.6f); + SampleThickness[10] = sqrt(1.0f - 0.4f * 0.4f - 0.8f * 0.8f); + SampleThickness[11] = sqrt(1.0f - 0.6f * 0.6f - 0.6f * 0.6f); + static float RejectionFalloff = 2.0f; + const float Accentuation = 0.1f * power; + + // The msao_compute will be called repeatedly, so create a local lambda for it: + auto msao_compute = [&](const Texture& write_result, const Texture& read_depth) + { + const TextureDesc& desc = read_depth.GetDesc(); + + MSAOCB cb; + + const CameraComponent& camera = GetCamera(); + + // Load first element of projection matrix which is the cotangent of the horizontal FOV divided by 2. + const float TanHalfFovH = 1.0f / camera.Projection.m[0][0]; + + // Here we compute multipliers that convert the center depth value into (the reciprocal of) + // sphere thicknesses at each sample location. This assumes a maximum sample radius of 5 + // units, but since a sphere has no thickness at its extent, we don't need to sample that far + // out. Only samples whole integer offsets with distance less than 25 are used. This means + // that there is no sample at (3, 4) because its distance is exactly 25 (and has a thickness of 0.) + + // The shaders are set up to sample a circular region within a 5-pixel radius. + const float ScreenspaceDiameter = 10.0f; + + // SphereDiameter = CenterDepth * ThicknessMultiplier. This will compute the thickness of a sphere centered + // at a specific depth. The ellipsoid scale can stretch a sphere into an ellipsoid, which changes the + // characteristics of the AO. + // TanHalfFovH: Radius of sphere in depth units if its center lies at Z = 1 + // ScreenspaceDiameter: Diameter of sample sphere in pixel units + // ScreenspaceDiameter / BufferWidth: Ratio of the screen width that the sphere actually covers + // Note about the "2.0f * ": Diameter = 2 * Radius + float ThicknessMultiplier = 2.0f * TanHalfFovH * ScreenspaceDiameter / desc.Width; + if (desc.ArraySize == 1) + { + ThicknessMultiplier *= 2.0f; + } + + // This will transform a depth value from [0, thickness] to [0, 1]. + float InverseRangeFactor = 1.0f / ThicknessMultiplier; + + // The thicknesses are smaller for all off-center samples of the sphere. Compute thicknesses relative + // to the center sample. + cb.xInvThicknessTable[0].x = InverseRangeFactor / SampleThickness[0]; + cb.xInvThicknessTable[0].y = InverseRangeFactor / SampleThickness[1]; + cb.xInvThicknessTable[0].z = InverseRangeFactor / SampleThickness[2]; + cb.xInvThicknessTable[0].w = InverseRangeFactor / SampleThickness[3]; + cb.xInvThicknessTable[1].x = InverseRangeFactor / SampleThickness[4]; + cb.xInvThicknessTable[1].y = InverseRangeFactor / SampleThickness[5]; + cb.xInvThicknessTable[1].z = InverseRangeFactor / SampleThickness[6]; + cb.xInvThicknessTable[1].w = InverseRangeFactor / SampleThickness[7]; + cb.xInvThicknessTable[2].x = InverseRangeFactor / SampleThickness[8]; + cb.xInvThicknessTable[2].y = InverseRangeFactor / SampleThickness[9]; + cb.xInvThicknessTable[2].z = InverseRangeFactor / SampleThickness[10]; + cb.xInvThicknessTable[2].w = InverseRangeFactor / SampleThickness[11]; + + // These are the weights that are multiplied against the samples because not all samples are + // equally important. The farther the sample is from the center location, the less they matter. + // We use the thickness of the sphere to determine the weight. The scalars in front are the number + // of samples with this weight because we sum the samples together before multiplying by the weight, + // so as an aggregate all of those samples matter more. After generating this table, the weights + // are normalized. + cb.xSampleWeightTable[0].x = 4.0f * SampleThickness[0]; // Axial + cb.xSampleWeightTable[0].y = 4.0f * SampleThickness[1]; // Axial + cb.xSampleWeightTable[0].z = 4.0f * SampleThickness[2]; // Axial + cb.xSampleWeightTable[0].w = 4.0f * SampleThickness[3]; // Axial + cb.xSampleWeightTable[1].x = 4.0f * SampleThickness[4]; // Diagonal + cb.xSampleWeightTable[1].y = 8.0f * SampleThickness[5]; // L-shaped + cb.xSampleWeightTable[1].z = 8.0f * SampleThickness[6]; // L-shaped + cb.xSampleWeightTable[1].w = 8.0f * SampleThickness[7]; // L-shaped + cb.xSampleWeightTable[2].x = 4.0f * SampleThickness[8]; // Diagonal + cb.xSampleWeightTable[2].y = 8.0f * SampleThickness[9]; // L-shaped + cb.xSampleWeightTable[2].z = 8.0f * SampleThickness[10]; // L-shaped + cb.xSampleWeightTable[2].w = 4.0f * SampleThickness[11]; // Diagonal + + // If we aren't using all of the samples, delete their weights before we normalize. +#ifndef MSAO_SAMPLE_EXHAUSTIVELY + cb.xSampleWeightTable[0].x = 0.0f; + cb.xSampleWeightTable[0].z = 0.0f; + cb.xSampleWeightTable[1].y = 0.0f; + cb.xSampleWeightTable[1].w = 0.0f; + cb.xSampleWeightTable[2].y = 0.0f; +#endif + + // Normalize the weights by dividing by the sum of all weights + float totalWeight = 0.0f; + totalWeight += cb.xSampleWeightTable[0].x; + totalWeight += cb.xSampleWeightTable[0].y; + totalWeight += cb.xSampleWeightTable[0].z; + totalWeight += cb.xSampleWeightTable[0].w; + totalWeight += cb.xSampleWeightTable[1].x; + totalWeight += cb.xSampleWeightTable[1].y; + totalWeight += cb.xSampleWeightTable[1].z; + totalWeight += cb.xSampleWeightTable[1].w; + totalWeight += cb.xSampleWeightTable[2].x; + totalWeight += cb.xSampleWeightTable[2].y; + totalWeight += cb.xSampleWeightTable[2].z; + totalWeight += cb.xSampleWeightTable[2].w; + cb.xSampleWeightTable[0].x /= totalWeight; + cb.xSampleWeightTable[0].y /= totalWeight; + cb.xSampleWeightTable[0].z /= totalWeight; + cb.xSampleWeightTable[0].w /= totalWeight; + cb.xSampleWeightTable[1].x /= totalWeight; + cb.xSampleWeightTable[1].y /= totalWeight; + cb.xSampleWeightTable[1].z /= totalWeight; + cb.xSampleWeightTable[1].w /= totalWeight; + cb.xSampleWeightTable[2].x /= totalWeight; + cb.xSampleWeightTable[2].y /= totalWeight; + cb.xSampleWeightTable[2].z /= totalWeight; + cb.xSampleWeightTable[2].w /= totalWeight; + + cb.xInvSliceDimension.x = 1.0f / desc.Width; + cb.xInvSliceDimension.y = 1.0f / desc.Height; + cb.xRejectFadeoff = 1.0f / -RejectionFalloff; + cb.xRcpAccentuation = 1.0f / (1.0f + Accentuation); + + device->UpdateBuffer(&constantBuffers[CBTYPE_POSTPROCESS_MSAO], &cb, cmd); + device->BindConstantBuffer(CS, &constantBuffers[CBTYPE_POSTPROCESS_MSAO], CB_GETBINDSLOT(MSAOCB), cmd); + + device->BindResource(CS, &read_depth, TEXSLOT_ONDEMAND0, cmd); + + const GPUResource* uavs[] = { + &write_result, + }; + device->BindUAVs(CS, uavs, 0, arraysize(uavs), cmd); + + if (desc.ArraySize == 1) + { + device->BindComputeShader(&computeShaders[CSTYPE_POSTPROCESS_MSAO], cmd); + device->Dispatch((desc.Width + 15) / 16, (desc.Height + 15) / 16, 1, cmd); + } + else + { + device->BindComputeShader(&computeShaders[CSTYPE_POSTPROCESS_MSAO_INTERLEAVE], cmd); + device->Dispatch((desc.Width + 7) / 8, (desc.Height + 7) / 8, desc.ArraySize, cmd); + } + + device->Barrier(&GPUBarrier::Memory(), 1, cmd); + device->UnbindUAVs(0, arraysize(uavs), cmd); + }; // end of lambda: msao_compute + + msao_compute(texture_ao_merged4, texture_lineardepth_tiled4); + msao_compute(texture_ao_hq4, texture_lineardepth_downsize4); + + msao_compute(texture_ao_merged3, texture_lineardepth_tiled3); + msao_compute(texture_ao_hq3, texture_lineardepth_downsize3); + + msao_compute(texture_ao_merged2, texture_lineardepth_tiled2); + msao_compute(texture_ao_hq2, texture_lineardepth_downsize2); + + msao_compute(texture_ao_merged1, texture_lineardepth_tiled1); + msao_compute(texture_ao_hq1, texture_lineardepth_downsize1); + + auto blur_and_upsample = [&](const Texture& Destination, const Texture& HiResDepth, const Texture& LoResDepth, + const Texture* InterleavedAO, const Texture* HighQualityAO, const Texture* HiResAO) + { + const uint32_t LoWidth = LoResDepth.GetDesc().Width; + const uint32_t LoHeight = LoResDepth.GetDesc().Height; + const uint32_t HiWidth = HiResDepth.GetDesc().Width; + const uint32_t HiHeight = HiResDepth.GetDesc().Height; + + if (HiResAO == nullptr) + { + if (HighQualityAO == nullptr) + { + device->BindComputeShader(&computeShaders[CSTYPE_POSTPROCESS_MSAO_BLURUPSAMPLE], cmd); + } + else + { + device->BindComputeShader(&computeShaders[CSTYPE_POSTPROCESS_MSAO_BLURUPSAMPLE_PREMIN], cmd); + } + } + else + { + if (HighQualityAO == nullptr) + { + device->BindComputeShader(&computeShaders[CSTYPE_POSTPROCESS_MSAO_BLURUPSAMPLE_BLENDOUT], cmd); + } + else + { + device->BindComputeShader(&computeShaders[CSTYPE_POSTPROCESS_MSAO_BLURUPSAMPLE_PREMIN_BLENDOUT], cmd); + } + } + + static float g_NoiseFilterTolerance = -3.0f; + static float g_BlurTolerance = -5.0f; + static float g_UpsampleTolerance = -7.0f; + + float kBlurTolerance = 1.0f - powf(10.0f, g_BlurTolerance) * 1920.0f / (float)LoWidth; + kBlurTolerance *= kBlurTolerance; + float kUpsampleTolerance = powf(10.0f, g_UpsampleTolerance); + float kNoiseFilterWeight = 1.0f / (powf(10.0f, g_NoiseFilterTolerance) + kUpsampleTolerance); + + MSAO_UPSAMPLECB cb; + cb.InvLowResolution = float2(1.0f / LoWidth, 1.0f / LoHeight); + cb.InvHighResolution = float2(1.0f / HiWidth, 1.0f / HiHeight); + cb.NoiseFilterStrength = kNoiseFilterWeight; + cb.StepSize = (float)lineardepth.GetDesc().Width / (float)LoWidth; + cb.kBlurTolerance = kBlurTolerance; + cb.kUpsampleTolerance = kUpsampleTolerance; + + device->UpdateBuffer(&constantBuffers[CBTYPE_POSTPROCESS_MSAO_UPSAMPLE], &cb, cmd); + device->BindConstantBuffer(CS, &constantBuffers[CBTYPE_POSTPROCESS_MSAO_UPSAMPLE], CB_GETBINDSLOT(MSAO_UPSAMPLECB), cmd); + + device->BindUAV(CS, &Destination, 0, cmd); + device->BindResource(CS, &LoResDepth, TEXSLOT_ONDEMAND0, cmd); + device->BindResource(CS, &HiResDepth, TEXSLOT_ONDEMAND1, cmd); + if (InterleavedAO != nullptr) + { + device->BindResource(CS, InterleavedAO, TEXSLOT_ONDEMAND2, cmd); + } + if (HighQualityAO != nullptr) + { + device->BindResource(CS, HighQualityAO, TEXSLOT_ONDEMAND3, cmd); + } + if (HiResAO != nullptr) + { + device->BindResource(CS, HiResAO, TEXSLOT_ONDEMAND4, cmd); + } + + device->Dispatch((HiWidth + 2 + 15) / 16, (HiHeight + 2 + 15) / 16, 1, cmd); + + }; + + blur_and_upsample(texture_ao_smooth3, texture_lineardepth_downsize3, texture_lineardepth_downsize4, &texture_ao_merged4, + &texture_ao_hq4, &texture_ao_merged3); + + blur_and_upsample(texture_ao_smooth2, texture_lineardepth_downsize2, texture_lineardepth_downsize3, &texture_ao_smooth3, + &texture_ao_hq3, &texture_ao_merged2); + + blur_and_upsample(texture_ao_smooth1, texture_lineardepth_downsize1, texture_lineardepth_downsize2, &texture_ao_smooth2, + &texture_ao_hq2, &texture_ao_merged1); + + blur_and_upsample(output, lineardepth, texture_lineardepth_downsize1, &texture_ao_smooth1, + &texture_ao_hq1, nullptr); wiProfiler::EndRange(prof_range); device->EventEnd(cmd); diff --git a/WickedEngine/wiRenderer.h b/WickedEngine/wiRenderer.h index 0c374d977..87adc8891 100644 --- a/WickedEngine/wiRenderer.h +++ b/WickedEngine/wiRenderer.h @@ -189,10 +189,9 @@ namespace wiRenderer bool wide = false ); void Postprocess_SSAO( - const wiGraphics::Texture& depthbuffer, + const wiGraphics::Texture& depthbuffer, const wiGraphics::Texture& lineardepth, const wiGraphics::Texture& lineardepth_minmax, - const wiGraphics::Texture& temp, const wiGraphics::Texture& output, wiGraphics::CommandList cmd, float range = 1.0f, @@ -200,8 +199,15 @@ namespace wiRenderer float power = 2.0f ); void Postprocess_HBAO( + const wiGraphics::Texture& lineardepth, + const wiGraphics::Texture& lineardepth_minmax, + const wiGraphics::Texture& output, + wiGraphics::CommandList cmd, + float power = 2.0f + ); + void Postprocess_MSAO( + const wiGraphics::Texture& lineardepth, const wiGraphics::Texture& lineardepth_minmax, - const wiGraphics::Texture& temp, const wiGraphics::Texture& output, wiGraphics::CommandList cmd, float power = 2.0f diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index 0d743c0fe..10d2edf76 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -9,7 +9,7 @@ namespace wiVersion // minor features, major updates const int minor = 38; // minor bug fixes, alterations, refactors, updates - const int revision = 24; + const int revision = 25; long GetVersion() diff --git a/features.txt b/features.txt index 4dd2a776f..bf8280384 100644 --- a/features.txt +++ b/features.txt @@ -49,7 +49,7 @@ Controller feedback (vibration, LED) Backlog: log,input,scripting Gamma correct, HDR rendering Resource Manager -Screen Space Ambient Occlusion (SSAO, HBAO) +Screen Space Ambient Occlusion (SSAO, HBAO, MSAO) Screen Space Reflections Skin shader (Subsurface scattering) Stencil layering