From 011daa952e885778cca3ab6e21f458b7c729b564 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Tue, 7 May 2019 18:35:54 -0700 Subject: [PATCH] Add API for controlling SSAO --- .../filament-android/src/main/cpp/View.cpp | 20 ++++++++ .../com/google/android/filament/View.java | 37 +++++++++++++++ filament/include/filament/View.h | 46 +++++++++++++++++++ filament/src/PostProcessManager.cpp | 14 ++++-- filament/src/PostProcessManager.h | 4 +- filament/src/Renderer.cpp | 21 +++++---- filament/src/View.cpp | 17 +++++++ filament/src/details/Engine.h | 3 -- filament/src/details/View.h | 23 ++++++++++ libs/gltfio/include/gltfio/SimpleViewer.h | 3 ++ samples/material_sandbox.cpp | 10 ++-- samples/material_sandbox.h | 3 ++ 12 files changed, 178 insertions(+), 23 deletions(-) diff --git a/android/filament-android/src/main/cpp/View.cpp b/android/filament-android/src/main/cpp/View.cpp index 5bf8f17009..c0f3a099df 100644 --- a/android/filament-android/src/main/cpp/View.cpp +++ b/android/filament-android/src/main/cpp/View.cpp @@ -219,3 +219,23 @@ Java_com_google_android_filament_View_nIsFrontFaceWindingInverted(JNIEnv*, View* view = (View*) nativeView; return static_cast(view->isFrontFaceWindingInverted()); } + +extern "C" JNIEXPORT void JNICALL +Java_com_google_android_filament_View_nSetSSAO(JNIEnv*, jclass, jlong nativeView, jint ordinal) { + View* view = (View*) nativeView; + view->setSSAO((View::SSAO)ordinal); +} + +extern "C" JNIEXPORT jint JNICALL +Java_com_google_android_filament_View_nGetSSAO(JNIEnv*, jclass, jlong nativeView) { + View* view = (View*) nativeView; + return (jint)view->getSSAO(); +} + +extern "C" JNIEXPORT void JNICALL +Java_com_google_android_filament_View_nSetSSAOOptions(JNIEnv*, jclass, + jlong nativeView, jfloat radius, jfloat bias, jfloat power) { + View* view = (View*) nativeView; + View::SSAOOptions options = { .radius = radius, .bias = bias, .power = power}; + view->setSSAOOptions(options); +} diff --git a/android/filament-android/src/main/java/com/google/android/filament/View.java b/android/filament-android/src/main/java/com/google/android/filament/View.java index 573c057761..00057abc60 100644 --- a/android/filament-android/src/main/java/com/google/android/filament/View.java +++ b/android/filament-android/src/main/java/com/google/android/filament/View.java @@ -32,6 +32,7 @@ public class View { private DynamicResolutionOptions mDynamicResolution; private RenderQuality mRenderQuality; private DepthPrepass mDepthPrepass = DepthPrepass.DEFAULT; + private SSAOOptions mSSAOOptions; public static class DynamicResolutionOptions { public boolean enabled = false; @@ -44,6 +45,12 @@ public class View { public int history = 9; } + public static class SSAOOptions { + public float radius = 0.3f; + public float bias = 0.005f; + public float power = 0.0f; + } + public enum QualityLevel { LOW, MEDIUM, @@ -55,6 +62,11 @@ public class View { public QualityLevel hdrColorBuffer = QualityLevel.HIGH; } + public enum SSAO { + NONE, + SSAO + } + public enum AntiAliasing { NONE, FXAA @@ -252,6 +264,28 @@ public class View { nSetDynamicLightingOptions(getNativeObject(), zLightNear, zLightFar); } + public void setSSAO(@NonNull SSAO ssao) { + nSetSSAO(getNativeObject(), ssao.ordinal()); + } + + @NonNull + public SSAO getSSAO() { + return SSAO.values()[nGetSSAO(getNativeObject())]; + } + + public void setSSAOOptions(@NonNull SSAOOptions options) { + mSSAOOptions = options; + nSetSSAOOptions(getNativeObject(), options.radius, options.bias, options.power); + } + + @NonNull + public SSAOOptions getSSAOOptions() { + if (mSSAOOptions == null) { + mSSAOOptions = new SSAOOptions(); + } + return mSSAOOptions; + } + long getNativeObject() { if (mNativeObject == 0) { throw new IllegalStateException("Calling method on destroyed View"); @@ -300,4 +334,7 @@ public class View { private static native boolean nIsPostProcessingEnabled(long nativeView); private static native void nSetFrontFaceWindingInverted(long nativeView, boolean inverted); private static native boolean nIsFrontFaceWindingInverted(long nativeView); + private static native void nSetSSAO(long nativeView, int ordinal); + private static native int nGetSSAO(long nativeView); + private static native void nSetSSAOOptions(long nativeView, float radius, float bias, float power); } diff --git a/filament/include/filament/View.h b/filament/include/filament/View.h index 5269bcee1b..211294d6d3 100644 --- a/filament/include/filament/View.h +++ b/filament/include/filament/View.h @@ -139,6 +139,24 @@ public: QualityLevel hdrColorBuffer = QualityLevel::HIGH; //!< quality of the color buffer }; + /** + * Options for Screen Space Ambient Occlusion (SSAO) + * @see setSSAO() + */ + struct SSAOOptions { + float radius = 0.3f; //!< SSAO radius in meters, between 0 and ~5. + float bias = 0.005f; //!< Self-occlusion bias in meters. Use to avoid self-occlusion. Between 0 and a few mm. + float power = 0.0f; //!< Controls ambient occlusion's contrast. Between 0 (linear) and 1 (squared) + }; + + /** + * List of available SSAO techniques + */ + enum class SSAO : uint8_t { + NONE = 0, //!< No SSAO + SSAO = 1 //!< Basic, sampling SSAO + }; + /** * List of available post-processing anti-aliasing techniques. * @see setAntiAliasing, getAntiAliasing @@ -171,6 +189,34 @@ public: ACES = 1, //!< ACES tone mapping }; + /** + * Activates or deactivates SSAO. + * + * @param ssao Type of SSAO to use. + */ + void setSSAO(SSAO ssao) noexcept; + + /** + * Query the type of SSAO active for this View. + * + * @return SSAO type. + */ + SSAO getSSAO() const noexcept; + + /** + * Sets SSAO options. + * + * @param options Options for SSAO. + */ + void setSSAOOptions(SSAOOptions const& options) noexcept; + + /** + * Gets the SSAO options. + * + * @return SSAO options currently set. + */ + SSAOOptions const& getSSAOOptions() const noexcept; + /** * Sets whether this view is rendered with or without a depth pre-pass. * diff --git a/filament/src/PostProcessManager.cpp b/filament/src/PostProcessManager.cpp index 1873e40d8d..e4026a3cf1 100644 --- a/filament/src/PostProcessManager.cpp +++ b/filament/src/PostProcessManager.cpp @@ -285,7 +285,8 @@ FrameGraphResource PostProcessManager::dynamicScaling(FrameGraph& fg, } -FrameGraphResource PostProcessManager::ssao(FrameGraph& fg, FrameGraphResource depth) noexcept { +FrameGraphResource PostProcessManager::ssao(FrameGraph& fg, FrameGraphResource depth, + View::SSAOOptions const& options) noexcept { FEngine* engine = mEngine; Handle fullScreenRenderPrimitive = engine->getFullScreenRenderPrimitive(); @@ -293,10 +294,13 @@ FrameGraphResource PostProcessManager::ssao(FrameGraph& fg, FrameGraphResource d struct SSAOPassData { FrameGraphResource depth; FrameGraphResource ssao; + View::SSAOOptions options; }; auto& SSAODepthPass = fg.addPass("SSAO Pass", - [depth](FrameGraph::Builder& builder, SSAOPassData& data) { + [depth, &options](FrameGraph::Builder& builder, SSAOPassData& data) { + + data.options = options; auto const& desc = builder.getDescriptor(depth); data.depth = builder.read(depth); @@ -316,9 +320,9 @@ FrameGraphResource PostProcessManager::ssao(FrameGraph& fg, FrameGraphResource d SamplerParams params; FMaterialInstance* const pInstance = mSSAOMaterialInstance; pInstance->setParameter("depth", depth, params); - pInstance->setParameter("radius", mEngine->debug.ssao.radius); - pInstance->setParameter("bias", mEngine->debug.ssao.bias); - pInstance->setParameter("power", mEngine->debug.ssao.power); + pInstance->setParameter("radius", data.options.radius); + pInstance->setParameter("bias", data.options.bias); + pInstance->setParameter("power", data.options.power); pInstance->commit(driver); pInstance->use(driver); diff --git a/filament/src/PostProcessManager.h b/filament/src/PostProcessManager.h index de2b9b5d07..8c322ea839 100644 --- a/filament/src/PostProcessManager.h +++ b/filament/src/PostProcessManager.h @@ -24,6 +24,7 @@ #include "fg/FrameGraphResource.h" #include +#include namespace filament { @@ -57,7 +58,8 @@ public: FrameGraph& fg, FrameGraphResource input) noexcept; - FrameGraphResource ssao(FrameGraph& fg, FrameGraphResource depth) noexcept; + FrameGraphResource ssao(FrameGraph& fg, FrameGraphResource depth, + View::SSAOOptions const& options) noexcept; backend::Handle getNoSSAOTexture() const { return mNoSSAOTexture; diff --git a/filament/src/Renderer.cpp b/filament/src/Renderer.cpp index f9e6b9fdbb..47d267ef35 100644 --- a/filament/src/Renderer.cpp +++ b/filament/src/Renderer.cpp @@ -59,9 +59,6 @@ FRenderer::FRenderer(FEngine& engine) : { FDebugRegistry& debugRegistry = engine.getDebugRegistry(); debugRegistry.registerProperty("d.ssao.enabled", &engine.debug.ssao.enabled); - debugRegistry.registerProperty("d.ssao.radius", &engine.debug.ssao.radius); - debugRegistry.registerProperty("d.ssao.bias", &engine.debug.ssao.bias); - debugRegistry.registerProperty("d.ssao.power", &engine.debug.ssao.power); } void FRenderer::init() noexcept { @@ -260,15 +257,19 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) { RenderPass::CommandTypeFlags commandType = getCommandType(view.getDepthPrepass()); - bool USE_SSAO = engine.debug.ssao.enabled; + // It's unclear if it's always better to reuse the depth pass, as it has to be saved and + // reloaded from memory -- as opposed to just regenerating it. Skinning is not an added concern, + // because either way, we have to go through the geometry twice. constexpr bool REUSE_SSAO_DEPTH = true; + + const bool useSSAO = view.getSSAO() != View::SSAO::NONE; Command const* depthPassBegin = nullptr; Command const* depthPassEnd = nullptr; Command const* colorPassBegin = nullptr; Command const* colorPassEnd = nullptr; - const bool sharedDepthBuffer = USE_SSAO && REUSE_SSAO_DEPTH && msaa <= 1; - if (USE_SSAO && commandType == RenderPass::CommandTypeFlags::COLOR) { + const bool sharedDepthBuffer = useSSAO && REUSE_SSAO_DEPTH && msaa <= 1; + if (useSSAO && commandType == RenderPass::CommandTypeFlags::COLOR) { // We don't have a depth prepass, so we need to generate the depth for the SSAO pass depthPassBegin = commands.end(); depthPassEnd = pass.appendSortedCommands(RenderPass::CommandTypeFlags::DEPTH); @@ -278,7 +279,7 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) { colorPassBegin = commands.end(); colorPassEnd = pass.appendSortedCommands(commandType); - if (USE_SSAO && commandType == RenderPass::CommandTypeFlags::DEPTH_AND_COLOR) { + if (useSSAO && commandType == RenderPass::CommandTypeFlags::DEPTH_AND_COLOR) { // We have a depth prepass, isolate the depth-only commands depthPassBegin = commands.begin(); depthPassEnd = std::partition_point(commands.begin(), commands.end(), @@ -321,7 +322,7 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) { FrameGraphResource depth = ssaoDepthPass.getData().depth; // SSAO pass -- automatically culled if not used - FrameGraphResource ssao = ppm.ssao(fg, depth); + FrameGraphResource ssao = ppm.ssao(fg, depth, view.getSSAOOptions()); // -------------------------------------------------------------------------------------------- @@ -338,10 +339,10 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) { }; auto& colorPass = fg.addPass("Color Pass", - [&svp, hdrFormat, colorPassNeedsDepthBuffer, msaa, clearFlags, depth, USE_SSAO, ssao, sharedDepthBuffer] + [&svp, hdrFormat, colorPassNeedsDepthBuffer, msaa, clearFlags, depth, useSSAO, ssao, sharedDepthBuffer] (FrameGraph::Builder& builder, ColorPassData& data) { - if (USE_SSAO) { + if (useSSAO) { data.ssao = builder.read(ssao); } diff --git a/filament/src/View.cpp b/filament/src/View.cpp index b1fb93c168..28a966e8ca 100644 --- a/filament/src/View.cpp +++ b/filament/src/View.cpp @@ -41,6 +41,7 @@ #include + using namespace filament::math; using namespace utils; @@ -921,5 +922,21 @@ void View::setDynamicLightingOptions(float zLightNear, float zLightFar) noexcept upcast(this)->setDynamicLightingOptions(zLightNear, zLightFar); } +void View::setSSAO(View::SSAO ssao) noexcept { + upcast(this)->setSSAO(ssao); +} + +View::SSAO View::getSSAO() const noexcept { + return upcast(this)->getSSAO(); +} + +void View::setSSAOOptions(View::SSAOOptions const& options) noexcept { + upcast(this)->setSSAOOptions(options); +} + +View::SSAOOptions const& View::getSSAOOptions() const noexcept { + return upcast(this)->getSSAOOptions(); +} + } // namespace filament diff --git a/filament/src/details/Engine.h b/filament/src/details/Engine.h index f0910e8a83..4027d5425d 100644 --- a/filament/src/details/Engine.h +++ b/filament/src/details/Engine.h @@ -362,9 +362,6 @@ public: } shadowmap; struct { bool enabled = true; - float radius = 0.3f; - float bias = 0.005; - float power = 0.5; } ssao; struct { bool camera_at_origin = true; diff --git a/filament/src/details/View.h b/filament/src/details/View.h index 0232562341..4be87846c9 100644 --- a/filament/src/details/View.h +++ b/filament/src/details/View.h @@ -39,6 +39,8 @@ #include #include +#include + #include namespace utils { @@ -225,6 +227,25 @@ public: return mDepthPrepass; } + void setSSAO(SSAO ssao) noexcept { + mSSAOType = ssao; + } + + SSAO getSSAO() const noexcept { + return mSSAOType; + } + + void setSSAOOptions(SSAOOptions const& options) noexcept { + mSSAOOptions = options; + mSSAOOptions.radius = math::clamp(0.0f, 10.0f, mSSAOOptions.radius); + mSSAOOptions.bias = math::clamp(0.0f, 0.1f, mSSAOOptions.bias); + mSSAOOptions.power = math::clamp(0.0f, 1.0f, mSSAOOptions.power); + } + + SSAOOptions const& getSSAOOptions() const noexcept { + return mSSAOOptions; + } + Range const& getVisibleRenderables() const noexcept { return mVisibleRenderables; } @@ -311,6 +332,8 @@ private: bool mShadowingEnabled = true; bool mHasPostProcessPass = true; DepthPrepass mDepthPrepass = DepthPrepass::DEFAULT; + SSAO mSSAOType = SSAO::NONE; + SSAOOptions mSSAOOptions{}; using duration = std::chrono::duration; DynamicResolutionOptions mDynamicResolution; diff --git a/libs/gltfio/include/gltfio/SimpleViewer.h b/libs/gltfio/include/gltfio/SimpleViewer.h index d905be35f3..4b8aeb5885 100644 --- a/libs/gltfio/include/gltfio/SimpleViewer.h +++ b/libs/gltfio/include/gltfio/SimpleViewer.h @@ -143,6 +143,7 @@ private: bool mEnablePrepass = true; bool mEnableFxaa = true; bool mEnableMsaa = true; + bool mEnableSsao = true; int mSidebarWidth = INITIAL_SIDEBAR_WIDTH; }; @@ -349,6 +350,7 @@ void SimpleViewer::updateUserInterface() { ImGui::Checkbox("Depth prepass", &mEnablePrepass); ImGui::Checkbox("FXAA", &mEnableFxaa); ImGui::Checkbox("MSAA 4x", &mEnableMsaa); + ImGui::Checkbox("SSAO", &mEnableSsao); } mView->setDepthPrepass( @@ -356,6 +358,7 @@ void SimpleViewer::updateUserInterface() { mView->setDithering(mEnableDithering ? View::Dithering::TEMPORAL : View::Dithering::NONE); mView->setAntiAliasing(mEnableFxaa ? View::AntiAliasing::FXAA : View::AntiAliasing::NONE); mView->setSampleCount(mEnableMsaa ? 4 : 1); + mView->setSSAO(mEnableSsao ? View::SSAO::SSAO : View::SSAO::NONE); if (ImGui::CollapsingHeader("Light", ImGuiTreeNodeFlags_DefaultOpen)) { ImGui::SliderFloat("IBL intensity", &mIblIntensity, 0.0f, 100000.0f); diff --git a/samples/material_sandbox.cpp b/samples/material_sandbox.cpp index 704595a9b9..63a855f3b5 100644 --- a/samples/material_sandbox.cpp +++ b/samples/material_sandbox.cpp @@ -329,10 +329,10 @@ static void gui(filament::Engine* engine, filament::View*) { ImGuiExt::DirectionWidget("direction", ¶ms.lightDirection.x); if (ImGui::CollapsingHeader("SSAO")) { DebugRegistry& debug = engine->getDebugRegistry(); - ImGui::Checkbox("enabled###ssao", debug.getPropertyAddress("d.ssao.enabled")); - ImGui::SliderFloat("radius", debug.getPropertyAddress("d.ssao.radius"), 0.1f, 10.0f); - ImGui::SliderFloat("bias", debug.getPropertyAddress("d.ssao.bias"), 0.0f, 0.1f); - ImGui::SliderFloat("power", debug.getPropertyAddress("d.ssao.power"), 0.0f, 1.0f); + ImGui::Checkbox("enabled###ssao", ¶ms.ssao); + ImGui::SliderFloat("radius", ¶ms.ssaoOptions.radius, 0.05f, 5.0f); + ImGui::SliderFloat("bias", ¶ms.ssaoOptions.bias, 0.0f, 0.1f); + ImGui::SliderFloat("power", ¶ms.ssaoOptions.power, 0.0f, 1.0f); } } @@ -426,6 +426,8 @@ static void preRender(filament::Engine*, filament::View* view, filament::Scene*, view->setToneMapping(g_params.tonemapping ? View::ToneMapping::ACES : View::ToneMapping::LINEAR); view->setDithering(g_params.dithering ? View::Dithering::TEMPORAL : View::Dithering::NONE); view->setSampleCount((uint8_t) (g_params.msaa ? 4 : 1)); + view->setSSAO(g_params.ssao ? View::SSAO::SSAO : View::SSAO::NONE); + view->setSSAOOptions(g_params.ssaoOptions); } int main(int argc, char* argv[]) { diff --git a/samples/material_sandbox.h b/samples/material_sandbox.h index 37fc7e5af5..56f3151e3d 100644 --- a/samples/material_sandbox.h +++ b/samples/material_sandbox.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -89,6 +90,8 @@ struct SandboxParameters { float constantBias = 0.001; float polygonOffsetConstant = 0.5; float polygonOffsetSlope = 2.0; + bool ssao = false; + filament::View::SSAOOptions ssaoOptions; }; inline void createInstances(SandboxParameters& params, filament::Engine& engine) {