瀏覽代碼

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.

Paul Speed 7 年之前
父節點
當前提交
81667f8f45

+ 56 - 1
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.
+     *
+     *  <p>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.</p>
+     */
+    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);
     }
 }

+ 11 - 7
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
     }
-}
+}

+ 6 - 1
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
         }
     }
 
-}
+}