diff --git a/android/filament-android/src/main/cpp/View.cpp b/android/filament-android/src/main/cpp/View.cpp index f57807f9cb..5fc3e87844 100644 --- a/android/filament-android/src/main/cpp/View.cpp +++ b/android/filament-android/src/main/cpp/View.cpp @@ -255,7 +255,8 @@ Java_com_google_android_filament_View_nSetBlendMode(JNIEnv *, jclass , jlong nat extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_View_nSetDepthOfFieldOptions(JNIEnv *, jclass , - jlong nativeView, jfloat focusDistance, jfloat blurScale, jboolean enabled) { + jlong nativeView, jfloat focusDistance, jfloat blurScale, jfloat maxApertureDiameter, jboolean enabled) { View* view = (View*) nativeView; - view->setDepthOfFieldOptions({ .focusDistance = focusDistance, .blurScale = blurScale, .enabled = (bool)enabled }); + view->setDepthOfFieldOptions({.focusDistance = focusDistance, .blurScale = blurScale, + .maxApertureDiameter = maxApertureDiameter, .enabled = (bool)enabled}); } 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 a1aa3df253..a6304b0276 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 @@ -324,6 +324,9 @@ public class View { /** scale factor controlling the amount of blur (values other than 1.0 are not physically correct)*/ public float blurScale = 1.0f; + /** maximum aperture diameter in meters (zero to disable bokeh rotation) */ + public float maxApertureDiameter = 0.01f; + /** enable or disable Depth of field effect */ public boolean enabled = false; }; @@ -1003,7 +1006,7 @@ public class View { */ public void setDepthOfFieldOptions(@NonNull DepthOfFieldOptions options) { mDepthOfFieldOptions = options; - nSetDepthOfFieldOptions(getNativeObject(), options.focusDistance, options.blurScale, options.enabled); + nSetDepthOfFieldOptions(getNativeObject(), options.focusDistance, options.blurScale, options.maxApertureDiameter, options.enabled); } /** @@ -1060,5 +1063,5 @@ public class View { private static native void nSetBloomOptions(long nativeView, long dirtNativeObject, float dirtStrength, float strength, int resolution, float anamorphism, int levels, int blendMode, boolean threshold, boolean enabled); private static native void nSetFogOptions(long nativeView, float distance, float maximumOpacity, float height, float heightFalloff, float v, float v1, float v2, float density, float inScatteringStart, float inScatteringSize, boolean fogColorFromIbl, boolean enabled); private static native void nSetBlendMode(long nativeView, int blendMode); - private static native void nSetDepthOfFieldOptions(long nativeView, float focusDistance, float blurScale, boolean enabled); + private static native void nSetDepthOfFieldOptions(long nativeView, float focusDistance, float blurScale, float maxApertureDiameter, boolean enabled); } diff --git a/filament/include/filament/View.h b/filament/include/filament/View.h index dd9bec1b54..78274ecaee 100644 --- a/filament/include/filament/View.h +++ b/filament/include/filament/View.h @@ -171,6 +171,7 @@ public: struct DepthOfFieldOptions { float focusDistance = 10.0f; //!< focus distance in world units float blurScale = 1.0f; //!< a scale factor for the amount of blur + float maxApertureDiameter = 0.01f; //!< maximum aperture diameter in meters (zero to disable rotation) bool enabled = false; //!< enable or disable Depth of field effect }; diff --git a/filament/src/PostProcessManager.cpp b/filament/src/PostProcessManager.cpp index 1cc67e6440..4d0b99ff0b 100644 --- a/filament/src/PostProcessManager.cpp +++ b/filament/src/PostProcessManager.cpp @@ -331,11 +331,18 @@ FrameGraphId PostProcessManager::dof(FrameGraph& fg, FrameGraphId depth = fg.getBlackboard().get("structure"); assert(depth.isValid()); - const size_t sampleCount = 25; // (keep in sync with dofUtils.fs) + // rotate the bokeh based on the aperture diameter (i.e. angle of the blades) + float bokehAngle = float(F_PI) / 6.0f; + if (dofOptions.maxApertureDiameter > 0.0f) { + bokehAngle += float(F_PI_2) * saturate(cameraInfo.A / dofOptions.maxApertureDiameter); + } + + const float SAMPLE_COUNT = 11.0; // (keep in sync with dofUtils.fs) + const size_t effectiveSampleCount = 1 + (SAMPLE_COUNT - 1) * 2; const float focusDistance = std::max(cameraInfo.zn, dofOptions.focusDistance); auto const& desc = fg.getDescriptor(input); const float Kc = (cameraInfo.A * cameraInfo.f) / (focusDistance - cameraInfo.f); - const float Ks = ((float)desc.height / sampleCount) / FCamera::SENSOR_SIZE; + const float Ks = ((float)desc.height / effectiveSampleCount) / FCamera::SENSOR_SIZE; const float2 cocParams{ // we use 1/zn instead of (zf - zn) / (zf * zn), because in reality we're using // a projection with an infinite far plane @@ -392,6 +399,9 @@ FrameGraphId PostProcessManager::dof(FrameGraph& fg, }); mi->setParameter("resolution", float4{ desc.width, desc.height, 1.0f / desc.width, 1.0f / desc.height }); + mi->setParameter("blurDirections", float4{ + std::cos(0.0f + bokehAngle), std::sin(0.0f + bokehAngle), + std::cos(F_PI_4 + bokehAngle), std::sin(F_PI_4 + bokehAngle) }); mi->setParameter("cocParams", cocParams); mi->commit(driver); mi->use(driver); @@ -449,6 +459,9 @@ FrameGraphId PostProcessManager::dof(FrameGraph& fg, }); mi->setParameter("resolution", float4{ desc.width, desc.height, 1.0f / desc.width, 1.0f / desc.height }); + mi->setParameter("blurDirections", float4{ + std::cos(F_PI_2 + bokehAngle), std::sin(F_PI_2 + bokehAngle), + std::cos(3.0f * F_PI_4 + bokehAngle), std::sin(3.0f * F_PI_4 + bokehAngle) }); mi->setParameter("cocParams", cocParams); mi->commit(driver); mi->use(driver); diff --git a/filament/src/details/View.h b/filament/src/details/View.h index 4bd3abe572..1f4018b4d2 100644 --- a/filament/src/details/View.h +++ b/filament/src/details/View.h @@ -287,6 +287,7 @@ public: void setDepthOfFieldOptions(DepthOfFieldOptions options) noexcept { options.focusDistance = std::max(0.0f, options.focusDistance); options.blurScale = std::max(0.0f, options.blurScale); + options.maxApertureDiameter = std::max(0.0f, options.maxApertureDiameter); mDepthOfFieldOptions = options; } diff --git a/filament/src/materials/dof.mat b/filament/src/materials/dof.mat index 0a06f7f18b..a4b101b759 100644 --- a/filament/src/materials/dof.mat +++ b/filament/src/materials/dof.mat @@ -21,6 +21,11 @@ material { name : resolution, precision: high }, + { + type : float4, + name : blurDirections, + precision: medium + }, { type : float2, name : cocParams @@ -44,17 +49,14 @@ fragment { #include "dofUtils.fs" -const vec2 kDirVertical= unitvec(PI / 2.0 + BOKEH_ROTATION_ANGLE); -const vec2 kDirDiamond = unitvec(3.0 * PI / 4.0 + BOKEH_ROTATION_ANGLE); - void postProcess(inout PostProcessInputs postProcess) { highp vec2 uv = variable_vertex.xy; float depth = textureLod(materialParams_depth, uv, 0.0).r; float coc = getCOC(depth, materialParams.cocParams); - vec4 box = blurTexture(materialParams_buffer0, uv, kDirVertical, depth, coc); - vec4 diamond = blurTexture(materialParams_buffer1, uv, kDirDiamond, depth, coc); + vec4 box = blurTexture(materialParams_buffer0, uv, materialParams.blurDirections.xy, depth, coc); + vec4 diamond = blurTexture(materialParams_buffer1, uv, materialParams.blurDirections.zw, depth, coc); vec4 dof = min(box, diamond); postProcess.color = dof; diff --git a/filament/src/materials/dofBlur.mat b/filament/src/materials/dofBlur.mat index 0e18fa869f..30252c65ce 100644 --- a/filament/src/materials/dofBlur.mat +++ b/filament/src/materials/dofBlur.mat @@ -16,6 +16,11 @@ material { name : resolution, precision: high }, + { + type : float4, + name : blurDirections, + precision: medium + }, { type : float2, name : cocParams @@ -52,17 +57,14 @@ layout(location = 1) out vec4 fragColor1; #include "dofUtils.fs" -const vec2 kDirHorizontal = unitvec(0.0 + BOKEH_ROTATION_ANGLE); -const vec2 kDirDiagonal = unitvec(PI / 4.0 + BOKEH_ROTATION_ANGLE); - void postProcess(inout PostProcessInputs postProcess) { highp vec2 uv = variable_vertex.xy; float depth = textureLod(materialParams_depth, uv, 0.0).r; float coc = getCOC(depth, materialParams.cocParams); - vec4 horizontal = blurTexture(materialParams_color, uv, kDirHorizontal, depth, coc); - vec4 diagonal = blurTexture(materialParams_color, uv, kDirDiagonal, depth, coc); + vec4 horizontal = blurTexture(materialParams_color, uv, materialParams.blurDirections.xy, depth, coc); + vec4 diagonal = blurTexture(materialParams_color, uv, materialParams.blurDirections.zw, depth, coc); // Output to MRTs postProcess.color = horizontal; diff --git a/filament/src/materials/dofUtils.fs b/filament/src/materials/dofUtils.fs index b2816463f7..1b2394ea76 100644 --- a/filament/src/materials/dofUtils.fs +++ b/filament/src/materials/dofUtils.fs @@ -16,11 +16,6 @@ // (keep in sync with PostProcessManager.cpp:dof()) const float SAMPLE_COUNT = 11.0; -// This is here just for aesthetic reasons -const float BOKEH_ROTATION_ANGLE = PI / 6.0; - -#define unitvec(angle) vec2(cos(angle), sin(angle)) - float getCOC(float depth, vec2 cocParams) { float CoC = abs(depth * cocParams.x + cocParams.y); return saturate(CoC); @@ -37,7 +32,7 @@ void tap(inout vec4 finalColor, inout float blurAmount, float radius, coc = clamp(coc, 0.0, centerCoc * 2.0); } - float m = step(radius, coc * SAMPLE_COUNT); + float m = smoothstep(radius - 0.5, radius + 0.5, coc * SAMPLE_COUNT); finalColor += mix(finalColor * (1.0 / blurAmount), color, m); blurAmount += 1.0; }