diff --git a/android/filament-android/src/main/cpp/View.cpp b/android/filament-android/src/main/cpp/View.cpp index b82d086cf7..68019b31d5 100644 --- a/android/filament-android/src/main/cpp/View.cpp +++ b/android/filament-android/src/main/cpp/View.cpp @@ -250,7 +250,7 @@ Java_com_google_android_filament_View_nSetAmbientOcclusionOptions(JNIEnv*, jclas extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_View_nSetBloomOptions(JNIEnv*, jclass, jlong nativeView, jfloat strength, jint resolution, jfloat anamorphism, jint levels, - jint blendMode, jboolean enabled) { + jint blendMode, jboolean threshold, jboolean enabled) { View* view = (View*) nativeView; View::BloomOptions options = { .strength = strength, @@ -258,6 +258,7 @@ Java_com_google_android_filament_View_nSetBloomOptions(JNIEnv*, jclass, .anamorphism = anamorphism, .levels = (uint8_t)levels, .blendMode = (View::BloomOptions::BlendMode)blendMode, + .threshold = (bool)threshold, .enabled = (bool)enabled }; view->setBloomOptions(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 88de60beba..735903235b 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 @@ -173,6 +173,8 @@ public class View { * blendMode: Whether the bloom effect is purely additive (false) or mixed with the original * image (true). * anamorphism: Bloom's aspect ratio (x/y), for artistic purposes. + * threshold: When enabled, a threshold at 1.0 is applied on the source image, this is + * useful for artistic reasons. * * @see setBloomOptions */ @@ -208,6 +210,11 @@ public class View { */ public BlendingMode blendingMode = BlendingMode.ADD; + /** + * Whether to threshold the source + */ + public boolean threshold = true; + /** * enable or disable bloom */ @@ -797,7 +804,7 @@ public class View { mBloomOptions = options; nSetBloomOptions(getNativeObject(), options.strength, options.resolution, options.anamorphism, options.levels, options.blendingMode.ordinal(), - options.enabled); + options.threshold, options.enabled); } /** @@ -855,5 +862,5 @@ public class View { private static native void nSetAmbientOcclusion(long nativeView, int ordinal); private static native int nGetAmbientOcclusion(long nativeView); private static native void nSetAmbientOcclusionOptions(long nativeView, float radius, float bias, float power, float resolution, float intensity); - private static native void nSetBloomOptions(long nativeView, float strength, int resolution, float anamorphism, int levels, int blendMode, boolean enabled); + private static native void nSetBloomOptions(long nativeView, float strength, int resolution, float anamorphism, int levels, int blendMode, boolean threshold, boolean enabled); } diff --git a/filament/include/filament/View.h b/filament/include/filament/View.h index c6fd3306b8..6b4c5531b0 100644 --- a/filament/include/filament/View.h +++ b/filament/include/filament/View.h @@ -139,6 +139,8 @@ public: * blendMode: Whether the bloom effect is purely additive (false) or mixed with the original * image (true). * anamorphism: Bloom's aspect ratio (x/y), for artistic purposes. + * threshold: When enabled, a threshold at 1.0 is applied on the source image, this is + * useful for artistic reasons. */ struct BloomOptions { enum class BlendMode : uint8_t { @@ -150,6 +152,7 @@ public: float anamorphism = 1.0f; //!< Bloom x/y aspect-ratio (1/32 to 32) uint8_t levels = 6; //!< number of blur levels (3 to 12) BlendMode blendMode = BlendMode::ADD; //!< How the bloom effect is applied + bool threshold = true; //!< Whether to threshold the source bool enabled = false; //!< enable or disable bloom }; diff --git a/filament/src/PostProcessManager.cpp b/filament/src/PostProcessManager.cpp index 8ef3eaf3c7..02b0b3e638 100644 --- a/filament/src/PostProcessManager.cpp +++ b/filament/src/PostProcessManager.cpp @@ -978,6 +978,7 @@ FrameGraphId PostProcessManager::bloomPass(FrameGraph& fg, .filterMin = SamplerMinFilter::LINEAR /* level is always 0 */ }); mi->setParameter("level", 0.0f); + mi->setParameter("threshold", bloomOptions.threshold ? 1.0f : 0.0f); // downsample phase for (size_t i = 0; i < bloomOptions.levels; i++) { diff --git a/filament/src/materials/bloomDownsample.mat b/filament/src/materials/bloomDownsample.mat index 071e9988b6..3435dca6c3 100644 --- a/filament/src/materials/bloomDownsample.mat +++ b/filament/src/materials/bloomDownsample.mat @@ -14,6 +14,10 @@ material { { type : float, name : level + }, + { + type : float, + name : threshold } ], variables : [ @@ -31,6 +35,12 @@ vertex { } fragment { + void threshold(inout vec3 c) { + if (max3(c) < 1.0) { + c = vec3(0); + } + } + vec3 box4x4(vec3 s0, vec3 s1, vec3 s2, vec3 s3) { return (s0 + s1 + s2 + s3) * 0.25; } @@ -68,20 +78,37 @@ fragment { // five h4x4 boxes vec3 c0, c1; - if (materialParams.level > 0.5) { + + if (materialParams.level <= 0.5) { + if (materialParams.threshold > 0.0) { + // Threshold the first level blur + threshold(c); + threshold(lt); + threshold(rt); + threshold(rb); + threshold(lb); + threshold(lt2); + threshold(rt2); + threshold(rb2); + threshold(lb2); + threshold(l); + threshold(r); + threshold(r); + threshold(l); + } + // Also apply fireflies (flickering) filtering + c0 = box4x4Reinhard(lt, rt, rb, lb); + c1 = box4x4Reinhard(c, l, t, lt2); + c1 += box4x4Reinhard(c, r, t, rt2); + c1 += box4x4Reinhard(c, r, b, rb2); + c1 += box4x4Reinhard(c, l, b, lb2); + } else { // common case c0 = box4x4(lt, rt, rb, lb); c1 = box4x4(c, l, t, lt2); c1 += box4x4(c, r, t, rt2); c1 += box4x4(c, r, b, rb2); c1 += box4x4(c, l, b, lb2); - } else { - // only first level downsampling - c0 = box4x4Reinhard(lt, rt, rb, lb); - c1 = box4x4Reinhard(c, l, t, lt2); - c1 += box4x4Reinhard(c, r, t, rt2); - c1 += box4x4Reinhard(c, r, b, rb2); - c1 += box4x4Reinhard(c, l, b, lb2); } // weighted average of the five boxes