From 81667f8f4597037d024b22098f35bb647a15a733 Mon Sep 17 00:00:00 2001 From: Paul Speed Date: Sat, 17 Mar 2018 02:18:31 -0400 Subject: [PATCH] Fixed the DepthOfFieldFilter to properly get the near/far distance from JME instead of having it hard-coded. Previous behavior caused focus to go all out of whack if you ever changed the near/far plane (and even the default hard-coded value was not the same as JME's default camera setup.) While I was here, I made the unfocus threshold configurable and added a debug toggle that will turn the 'unfocus' amount into grayscale color for better visualizing where unfocusing is happening. --- .../jme3/post/filters/DepthOfFieldFilter.java | 57 ++++++++++++++++++- .../Common/MatDefs/Post/DepthOfField.frag | 18 +++--- .../Common/MatDefs/Post/DepthOfField.j3md | 7 ++- 3 files changed, 73 insertions(+), 9 deletions(-) diff --git a/jme3-effects/src/main/java/com/jme3/post/filters/DepthOfFieldFilter.java b/jme3-effects/src/main/java/com/jme3/post/filters/DepthOfFieldFilter.java index dde643101..872b3566e 100644 --- a/jme3-effects/src/main/java/com/jme3/post/filters/DepthOfFieldFilter.java +++ b/jme3-effects/src/main/java/com/jme3/post/filters/DepthOfFieldFilter.java @@ -54,10 +54,13 @@ public class DepthOfFieldFilter extends Filter { private float focusDistance = 50f; private float focusRange = 10f; private float blurScale = 1f; + private float blurThreshold = 0.2f; // These values are set internally based on the // viewport size. private float xScale; private float yScale; + + private boolean debugUnfocus; /** * Creates a DepthOfField filter @@ -83,7 +86,8 @@ public class DepthOfFieldFilter extends Filter { material = new Material(assets, "Common/MatDefs/Post/DepthOfField.j3md"); material.setFloat("FocusDistance", focusDistance); material.setFloat("FocusRange", focusRange); - + material.setFloat("BlurThreshold", blurThreshold); + material.setBoolean("DebugUnfocus", debugUnfocus); xScale = 1.0f / w; yScale = 1.0f / h; @@ -161,13 +165,62 @@ public class DepthOfFieldFilter extends Filter { return blurScale; } + /** + * Sets the minimum blur factor before the convolution filter is + * calculated. The default is 0.2 which means if the "unfocus" + * amount is less than 0.2 (where 0 is no blur and 1.0 is full blurScale) + * then no blur will be applied at all. Depending on the GPU implementation, + * this may be an optimization since it uses branching to skip the expensive + * convolution filter. + * + *

In scenes where the focus distance is close (like 0) and the focus range + * is relatively large, this threshold will remove some subtlety in + * the near-camera blurring and should be set smaller than the default + * or to 0 to disable completely. Sometimes that cut-off is desired if + * mid-to-far field unfocusing is all that is desired.

+ */ + public void setBlurThreshold( float f ) { + this.blurThreshold = f; + if (material != null) { + material.setFloat("BlurThreshold", blurThreshold); + } + } + + /** + * returns the blur threshold. + * @return + */ + public float getBlurThreshold() { + return blurThreshold; + } + + /** + * Turns on/off debugging of the 'unfocus' value that is used to + * mix the convolution filter. When this is on, the 'unfocus' value + * is rendered as gray scale. This can be used to more easily visualize + * where in your view the focus is centered and how steep the gradient/cutoff + * is, etc.. + */ + public void setDebugUnfocus( boolean b ) { + this.debugUnfocus = b; + if( material != null ) { + material.setBoolean("DebugUnfocus", debugUnfocus); + } + } + + public boolean getDebugUnfocus() { + return debugUnfocus; + } + @Override public void write(JmeExporter ex) throws IOException { super.write(ex); OutputCapsule oc = ex.getCapsule(this); oc.write(blurScale, "blurScale", 1f); + oc.write(blurScale, "blurThreshold", 0.2f); oc.write(focusDistance, "focusDistance", 50f); oc.write(focusRange, "focusRange", 10f); + oc.write(debugUnfocus, "debugUnfocus", false); // strange to write this I guess } @Override @@ -175,7 +228,9 @@ public class DepthOfFieldFilter extends Filter { super.read(im); InputCapsule ic = im.getCapsule(this); blurScale = ic.readFloat("blurScale", 1f); + blurThreshold = ic.readFloat("blurThreshold", 0.2f); focusDistance = ic.readFloat("focusDistance", 50f); focusRange = ic.readFloat("focusRange", 10f); + debugUnfocus = ic.readBoolean("debugUnfocus", false); } } diff --git a/jme3-effects/src/main/resources/Common/MatDefs/Post/DepthOfField.frag b/jme3-effects/src/main/resources/Common/MatDefs/Post/DepthOfField.frag index cdc1a3526..ccf20ba59 100644 --- a/jme3-effects/src/main/resources/Common/MatDefs/Post/DepthOfField.frag +++ b/jme3-effects/src/main/resources/Common/MatDefs/Post/DepthOfField.frag @@ -10,7 +10,7 @@ uniform float m_FocusDistance; uniform float m_XScale; uniform float m_YScale; -vec2 m_NearFar = vec2( 0.1, 1000.0 ); +uniform vec2 g_FrustumNearFar; void main() { @@ -31,8 +31,8 @@ void main() { // z * (zb - a) = b // z = b / (zb - a) // - float a = m_NearFar.y / (m_NearFar.y - m_NearFar.x); - float b = m_NearFar.y * m_NearFar.x / (m_NearFar.x - m_NearFar.y); + float a = g_FrustumNearFar.y / (g_FrustumNearFar.y - g_FrustumNearFar.x); + float b = g_FrustumNearFar.y * g_FrustumNearFar.x / (g_FrustumNearFar.x - g_FrustumNearFar.y); float z = b / (zBuffer - a); // Above could be the same for any depth-based filter @@ -42,7 +42,7 @@ void main() { // at +/- m_FocusRange to either side of that. float unfocus = min( 1.0, abs( z - m_FocusDistance ) / m_FocusRange ); - if( unfocus < 0.2 ) { + if( unfocus < BLUR_THRESHOLD ) { // If we are mostly in focus then don't bother with the // convolution filter gl_FragColor = texVal; @@ -86,7 +86,11 @@ void main() { gl_FragColor = mix( texVal, sum, unfocus ); - // I used this for debugging the range - // gl_FragColor.r = unfocus; + #ifdef DEBUG_UNFOCUS + // Used for debugging the range or user settings + gl_FragColor.r = unfocus; + gl_FragColor.g = unfocus; + gl_FragColor.b = unfocus; + #endif } -} \ No newline at end of file +} diff --git a/jme3-effects/src/main/resources/Common/MatDefs/Post/DepthOfField.j3md b/jme3-effects/src/main/resources/Common/MatDefs/Post/DepthOfField.j3md index a4fe79601..908889951 100644 --- a/jme3-effects/src/main/resources/Common/MatDefs/Post/DepthOfField.j3md +++ b/jme3-effects/src/main/resources/Common/MatDefs/Post/DepthOfField.j3md @@ -9,6 +9,8 @@ MaterialDef Depth Of Field { Float FocusDistance; Float XScale; Float YScale; + Float BlurThreshold : 0.2; + Boolean DebugUnfocus : false; } Technique { @@ -16,12 +18,15 @@ MaterialDef Depth Of Field { FragmentShader GLSL150 GLSL100: Common/MatDefs/Post/DepthOfField.frag WorldParameters { + FrustumNearFar } Defines { RESOLVE_MS : NumSamples RESOLVE_DEPTH_MS : NumSamplesDepth + BLUR_THRESHOLD : BlurThreshold + DEBUG_UNFOCUS : DebugUnfocus } } -} \ No newline at end of file +}