From 61bf472426008690fd9e76369a2b4f2edad5fd2c Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Thu, 24 Jun 2021 22:27:57 -0700 Subject: [PATCH] VSM blur is now specified as a width in pixels This is a lot more intuitive than using the standard deviation. --- .../src/main/cpp/LightManager.cpp | 4 +-- .../google/android/filament/LightManager.java | 16 +++------- filament/include/filament/LightManager.h | 12 ++----- filament/src/ShadowMapManager.cpp | 11 ++++--- filament/src/components/LightManager.cpp | 31 +++++++++++-------- filament/src/components/LightManager.h | 3 +- libs/viewer/src/Settings.cpp | 6 ++-- libs/viewer/src/SimpleViewer.cpp | 2 +- 8 files changed, 40 insertions(+), 45 deletions(-) diff --git a/android/filament-android/src/main/cpp/LightManager.cpp b/android/filament-android/src/main/cpp/LightManager.cpp index 228393ff13..db19de6f2d 100644 --- a/android/filament-android/src/main/cpp/LightManager.cpp +++ b/android/filament-android/src/main/cpp/LightManager.cpp @@ -77,7 +77,7 @@ Java_com_google_android_filament_LightManager_nBuilderShadowOptions(JNIEnv* env, jlong nativeBuilder, jint mapSize, jint cascades, jfloatArray splitPositions, jfloat constantBias, jfloat normalBias, jfloat shadowFar, jfloat shadowNearHint, jfloat shadowFarHint, jboolean stable, jboolean screenSpaceContactShadows, jint stepCount, - jfloat maxShadowDistance, jint vsmMsaaSamples, jfloat blurStandardDeviation) { + jfloat maxShadowDistance, jint vsmMsaaSamples, jfloat blurWidth) { LightManager::Builder *builder = (LightManager::Builder *) nativeBuilder; LightManager::ShadowOptions shadowOptions { .mapSize = (uint32_t)mapSize, @@ -93,7 +93,7 @@ Java_com_google_android_filament_LightManager_nBuilderShadowOptions(JNIEnv* env, .maxShadowDistance = maxShadowDistance, .vsm = { .msaaSamples = (uint8_t) vsmMsaaSamples, - .blurStandardDeviation = blurStandardDeviation + .blurWidth = blurWidth } }; jfloat *nativeSplits = env->GetFloatArrayElements(splitPositions, NULL); diff --git a/android/filament-android/src/main/java/com/google/android/filament/LightManager.java b/android/filament-android/src/main/java/com/google/android/filament/LightManager.java index 02acc99e4f..4330397653 100644 --- a/android/filament-android/src/main/java/com/google/android/filament/LightManager.java +++ b/android/filament-android/src/main/java/com/google/android/filament/LightManager.java @@ -328,16 +328,10 @@ public class LightManager { public int vsmMsaaSamples = 1; /** - * Standard deviation of the VSM blur. Zero do disable. - * The maximum value is 21, which corresponds to a gaussian blur filter width - * of 125 pixels. The relation between the filter width and the standard deviation - * is roughly: stddev = (kernelWidth + 1) / 6. - * Some common values for blurStandardDeviation: - * 3x3 gaussian : 0.6667 - * 5x5 gaussian : 1.0 - * 9x9 gaussian : 1.6667 + * Blur width for the VSM blur. Zero do disable. + * The maximum value is 125. */ - public float blurStandardDeviation = 0.0f; + public float blurWidth = 0.0f; } public static class ShadowCascades { @@ -467,7 +461,7 @@ public class LightManager { options.constantBias, options.normalBias, options.shadowFar, options.shadowNearHint, options.shadowFarHint, options.stable, options.screenSpaceContactShadows, options.stepCount, options.maxShadowDistance, options.vsmMsaaSamples, - options.blurStandardDeviation); + options.blurWidth); return this; } @@ -1101,7 +1095,7 @@ public class LightManager { private static native void nDestroyBuilder(long nativeBuilder); private static native boolean nBuilderBuild(long nativeBuilder, long nativeEngine, int entity); private static native void nBuilderCastShadows(long nativeBuilder, boolean enable); - private static native void nBuilderShadowOptions(long nativeBuilder, int mapSize, int cascades, float[] splitPositions, float constantBias, float normalBias, float shadowFar, float shadowNearHint, float shadowFarhint, boolean stable, boolean screenSpaceContactShadows, int stepCount, float maxShadowDistance, int vsmMsaaSamples, float blurStandardDeviation); + private static native void nBuilderShadowOptions(long nativeBuilder, int mapSize, int cascades, float[] splitPositions, float constantBias, float normalBias, float shadowFar, float shadowNearHint, float shadowFarhint, boolean stable, boolean screenSpaceContactShadows, int stepCount, float maxShadowDistance, int vsmMsaaSamples, float blurWidth); private static native void nBuilderCastLight(long nativeBuilder, boolean enabled); private static native void nBuilderPosition(long nativeBuilder, float x, float y, float z); private static native void nBuilderDirection(long nativeBuilder, float x, float y, float z); diff --git a/filament/include/filament/LightManager.h b/filament/include/filament/LightManager.h index bd70d7a42b..b7535154cf 100644 --- a/filament/include/filament/LightManager.h +++ b/filament/include/filament/LightManager.h @@ -327,16 +327,10 @@ public: uint8_t msaaSamples = 1; /** - * Standard deviation of the VSM blur. Zero do disable. - * The maximum value is 21, which corresponds to a gaussian blur filter width - * of 125 pixels. The relation between the filter width and the standard deviation - * is roughly: stddev = (kernelWidth + 1) / 6. - * Some common values for blurStandardDeviation: - * 3x3 gaussian : 0.6667 - * 5x5 gaussian : 1.0 - * 9x9 gaussian : 1.6667 + * Blur width for the VSM blur. Zero do disable. + * The maximum value is 125. */ - float blurStandardDeviation = 0.0f; + float blurWidth = 0.0f; } vsm; }; diff --git a/filament/src/ShadowMapManager.cpp b/filament/src/ShadowMapManager.cpp index 223fcf9755..7db30254f1 100644 --- a/filament/src/ShadowMapManager.cpp +++ b/filament/src/ShadowMapManager.cpp @@ -165,7 +165,7 @@ void ShadowMapManager::render(FrameGraph& fg, FEngine& engine, FView& view, auto& shadowPass = fg.addPass("Shadow Pass", [&](FrameGraph::Builder& builder, auto& data) { - const bool blur = view.hasVsm() && options->vsm.blurStandardDeviation > 0.0f; + const bool blur = view.hasVsm() && options->vsm.blurWidth > 0.0f; FrameGraphRenderPass::Descriptor renderTargetDesc{}; @@ -234,7 +234,7 @@ void ShadowMapManager::render(FrameGraph& fg, FEngine& engine, FView& view, auto const& data, DriverApi& driver) mutable { const auto& options = layout.options; - const bool blur = view.hasVsm() && options->vsm.blurStandardDeviation > 0.0f; + const bool blur = view.hasVsm() && options->vsm.blurWidth > 0.0f; // TODO: camera is already set inside 'pass', we could get it from there FCamera const& camera = map->getShadowMap().getCamera(); @@ -277,9 +277,10 @@ void ShadowMapManager::render(FrameGraph& fg, FEngine& engine, FView& view, // now emit the blurring passes if (view.hasVsm()) { - const float sigma = options->vsm.blurStandardDeviation; - if (sigma > 0.0f) { - size_t kernelWidth = std::ceil(((sigma * 6.0f - 1.0f) - 5.0f) / 4.0f); + const float blurWidth = options->vsm.blurWidth; + if (blurWidth > 0.0f) { + const float sigma = (blurWidth + 1.0f) / 6.0f; + size_t kernelWidth = std::ceil((blurWidth - 5.0f) / 4.0f); kernelWidth = kernelWidth * 4 + 5; const float ratio = (kernelWidth + 1.0f) / sigma; ppm.gaussianBlurPass(fg, diff --git a/filament/src/components/LightManager.cpp b/filament/src/components/LightManager.cpp index c0f95dab80..8f49d9764e 100644 --- a/filament/src/components/LightManager.cpp +++ b/filament/src/components/LightManager.cpp @@ -172,19 +172,24 @@ void FLightManager::create(const FLightManager::Builder& builder, utils::Entity lightType.lightCaster = builder->mCastLight; ShadowParams& shadowParams = manager[i].shadowParams; - shadowParams.options.mapSize = clamp(builder->mShadowOptions.mapSize, 0u, 2048u); - shadowParams.options.shadowCascades = clamp(builder->mShadowOptions.shadowCascades, 1, CONFIG_MAX_SHADOW_CASCADES); - shadowParams.options.constantBias = clamp(builder->mShadowOptions.constantBias, 0.0f, 2.0f); - shadowParams.options.normalBias = clamp(builder->mShadowOptions.normalBias, 0.0f, 3.0f); - shadowParams.options.shadowFar = std::max(builder->mShadowOptions.shadowFar, 0.0f); - shadowParams.options.shadowNearHint = std::max(builder->mShadowOptions.shadowNearHint, 0.0f); - shadowParams.options.shadowFarHint = std::max(builder->mShadowOptions.shadowFarHint, 0.0f); - shadowParams.options.stable = builder->mShadowOptions.stable; - shadowParams.options.polygonOffsetConstant = builder->mShadowOptions.polygonOffsetConstant; - shadowParams.options.polygonOffsetSlope = builder->mShadowOptions.polygonOffsetSlope; - shadowParams.options.screenSpaceContactShadows = builder->mShadowOptions.screenSpaceContactShadows; - shadowParams.options.stepCount = builder->mShadowOptions.stepCount; - shadowParams.options.maxShadowDistance = builder->mShadowOptions.maxShadowDistance; + shadowParams.options = builder->mShadowOptions; + + // validate all shadow options + shadowParams.options.mapSize = clamp(shadowParams.options.mapSize, 0u, 2048u); + shadowParams.options.shadowCascades = clamp(shadowParams.options.shadowCascades, 1, CONFIG_MAX_SHADOW_CASCADES); + shadowParams.options.constantBias = clamp(shadowParams.options.constantBias, 0.0f, 2.0f); + shadowParams.options.normalBias = clamp(shadowParams.options.normalBias, 0.0f, 3.0f); + shadowParams.options.shadowFar = std::max(shadowParams.options.shadowFar, 0.0f); + shadowParams.options.shadowNearHint = std::max(shadowParams.options.shadowNearHint, 0.0f); + shadowParams.options.shadowFarHint = std::max(shadowParams.options.shadowFarHint, 0.0f); + shadowParams.options.stable = shadowParams.options.stable; + shadowParams.options.polygonOffsetConstant = shadowParams.options.polygonOffsetConstant; + shadowParams.options.polygonOffsetSlope = shadowParams.options.polygonOffsetSlope; + shadowParams.options.screenSpaceContactShadows = shadowParams.options.screenSpaceContactShadows; + shadowParams.options.stepCount = shadowParams.options.stepCount; + shadowParams.options.maxShadowDistance = shadowParams.options.maxShadowDistance; + shadowParams.options.vsm.msaaSamples = std::max(uint8_t(0), shadowParams.options.vsm.msaaSamples); + shadowParams.options.vsm.blurWidth = std::max(0.0f, shadowParams.options.vsm.blurWidth); // set default values by calling the setters setLocalPosition(i, builder->mPosition); diff --git a/filament/src/components/LightManager.h b/filament/src/components/LightManager.h index 049e4e4d28..110591fadc 100644 --- a/filament/src/components/LightManager.h +++ b/filament/src/components/LightManager.h @@ -222,7 +222,8 @@ public: } void setShadowOptions(Instance i, ShadowOptions const& options) noexcept { - static_cast(mManager[i].shadowParams).options = options; + ShadowParams& params = mManager[i].shadowParams; + params.options = options; } private: diff --git a/libs/viewer/src/Settings.cpp b/libs/viewer/src/Settings.cpp index a7a1c0edab..e67c7cbf37 100644 --- a/libs/viewer/src/Settings.cpp +++ b/libs/viewer/src/Settings.cpp @@ -729,8 +729,8 @@ static int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, CHECK_KEY(tok); if (compare(tok, jsonChunk, "msaaSamples") == 0) { i = parse(tokens, i + 1, jsonChunk, &out->msaaSamples); - } else if (compare(tok, jsonChunk, "blurStandardDeviation") == 0) { - i = parse(tokens, i + 1, jsonChunk, &out->blurStandardDeviation); + } else if (compare(tok, jsonChunk, "blurWidth") == 0) { + i = parse(tokens, i + 1, jsonChunk, &out->blurWidth); } else { slog.w << "Invalid shadow options VSM key: '" << STR(tok, jsonChunk) << "'" << io::endl; i = parse(tokens, i + 1); @@ -1171,7 +1171,7 @@ static std::ostream& operator<<(std::ostream& out, const LightManager::ShadowOpt return out << "{\n" << "\"vsm\": {\n" << "\"msaaSamples\": " << int(in.vsm.msaaSamples) << ",\n" - << "\"blurStandardDeviation\": " << in.vsm.blurStandardDeviation << "\n" + << "\"blurWidth\": " << in.vsm.blurWidth << "\n" << "},\n" << "\"screenSpaceContactShadows\": " << to_string(in.screenSpaceContactShadows) << ",\n" << "\"shadowCascades\": " << int(in.shadowCascades) << ",\n" diff --git a/libs/viewer/src/SimpleViewer.cpp b/libs/viewer/src/SimpleViewer.cpp index de6a82dcd5..fa45661324 100644 --- a/libs/viewer/src/SimpleViewer.cpp +++ b/libs/viewer/src/SimpleViewer.cpp @@ -688,7 +688,7 @@ void SimpleViewer::updateUserInterface() { ImGui::SliderInt("VSM anisotropy", &vsmAnisotropy, 0, 3, label); mSettings.view.vsmShadowOptions.anisotropy = vsmAnisotropy; ImGui::Checkbox("VSM mipmapping", &mSettings.view.vsmShadowOptions.mipmapping); - ImGui::SliderFloat("VSM blur", &light.shadowOptions.vsm.blurStandardDeviation, 0.0, 21.0f); + ImGui::SliderFloat("VSM blur", &light.shadowOptions.vsm.blurWidth, 0.0f, 125.0f); // These are not very useful in practice (defaults are good), but we keep them here for debugging //ImGui::SliderFloat("VSM exponent", &mSettings.view.vsmShadowOptions.exponent, 0.0, 6.0f);