Home | History | Annotate | Download | only in filters
      1 /*
      2  * Copyright (c) 2009-2010 jMonkeyEngine
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are
      7  * met:
      8  *
      9  * * Redistributions of source code must retain the above copyright
     10  *   notice, this list of conditions and the following disclaimer.
     11  *
     12  * * Redistributions in binary form must reproduce the above copyright
     13  *   notice, this list of conditions and the following disclaimer in the
     14  *   documentation and/or other materials provided with the distribution.
     15  *
     16  * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
     17  *   may be used to endorse or promote products derived from this software
     18  *   without specific prior written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 package com.jme3.post.filters;
     33 
     34 import com.jme3.asset.AssetManager;
     35 import com.jme3.export.InputCapsule;
     36 import com.jme3.export.JmeExporter;
     37 import com.jme3.export.JmeImporter;
     38 import com.jme3.export.OutputCapsule;
     39 import com.jme3.material.Material;
     40 import com.jme3.math.ColorRGBA;
     41 import com.jme3.post.Filter;
     42 import com.jme3.renderer.RenderManager;
     43 import com.jme3.renderer.ViewPort;
     44 import com.jme3.texture.Image.Format;
     45 import java.io.IOException;
     46 import java.util.ArrayList;
     47 
     48 /**
     49  * BloomFilter is used to make objects in the scene have a glow effect.<br>
     50  * There are 2 mode : Scene and Objects.<br>
     51  * Scene mode extracts the bright parts of the scene to make them glow<br>
     52  * Object mode make objects glow according to their material's glowMap or their GlowColor<br>
     53  * @see <a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:bloom_and_glow">advanced:bloom_and_glow</a> for more details
     54  *
     55  * @author Rmy Bouquet aka Nehon
     56  */
     57 public class BloomFilter extends Filter {
     58 
     59     /**
     60      * GlowMode specifies if the glow will be applied to the whole scene,or to objects that have aglow color or a glow map
     61      */
     62     public enum GlowMode {
     63 
     64         /**
     65          * Apply bloom filter to bright areas in the scene.
     66          */
     67         Scene,
     68         /**
     69          * Apply bloom only to objects that have a glow map or a glow color.
     70          */
     71         Objects,
     72         /**
     73          * Apply bloom to both bright parts of the scene and objects with glow map.
     74          */
     75         SceneAndObjects;
     76     }
     77 
     78     private GlowMode glowMode = GlowMode.Scene;
     79     //Bloom parameters
     80     private float blurScale = 1.5f;
     81     private float exposurePower = 5.0f;
     82     private float exposureCutOff = 0.0f;
     83     private float bloomIntensity = 2.0f;
     84     private float downSamplingFactor = 1;
     85     private Pass preGlowPass;
     86     private Pass extractPass;
     87     private Pass horizontalBlur = new Pass();
     88     private Pass verticalalBlur = new Pass();
     89     private Material extractMat;
     90     private Material vBlurMat;
     91     private Material hBlurMat;
     92     private int screenWidth;
     93     private int screenHeight;
     94 
     95     /**
     96      * Creates a Bloom filter
     97      */
     98     public BloomFilter() {
     99         super("BloomFilter");
    100     }
    101 
    102     /**
    103      * Creates the bloom filter with the specific glow mode
    104      * @param glowMode
    105      */
    106     public BloomFilter(GlowMode glowMode) {
    107         this();
    108         this.glowMode = glowMode;
    109     }
    110 
    111     @Override
    112     protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
    113         screenWidth = (int) Math.max(1, (w / downSamplingFactor));
    114         screenHeight = (int) Math.max(1, (h / downSamplingFactor));
    115         //    System.out.println(screenWidth + " " + screenHeight);
    116         if (glowMode != GlowMode.Scene) {
    117             preGlowPass = new Pass();
    118             preGlowPass.init(renderManager.getRenderer(), screenWidth, screenHeight, Format.RGBA8, Format.Depth);
    119         }
    120 
    121         postRenderPasses = new ArrayList<Pass>();
    122         //configuring extractPass
    123         extractMat = new Material(manager, "Common/MatDefs/Post/BloomExtract.j3md");
    124         extractPass = new Pass() {
    125 
    126             @Override
    127             public boolean requiresSceneAsTexture() {
    128                 return true;
    129             }
    130 
    131             @Override
    132             public void beforeRender() {
    133                 extractMat.setFloat("ExposurePow", exposurePower);
    134                 extractMat.setFloat("ExposureCutoff", exposureCutOff);
    135                 if (glowMode != GlowMode.Scene) {
    136                     extractMat.setTexture("GlowMap", preGlowPass.getRenderedTexture());
    137                 }
    138                 extractMat.setBoolean("Extract", glowMode != GlowMode.Objects);
    139             }
    140         };
    141 
    142         extractPass.init(renderManager.getRenderer(), screenWidth, screenHeight, Format.RGBA8, Format.Depth, 1, extractMat);
    143         postRenderPasses.add(extractPass);
    144 
    145         //configuring horizontal blur pass
    146         hBlurMat = new Material(manager, "Common/MatDefs/Blur/HGaussianBlur.j3md");
    147         horizontalBlur = new Pass() {
    148 
    149             @Override
    150             public void beforeRender() {
    151                 hBlurMat.setTexture("Texture", extractPass.getRenderedTexture());
    152                 hBlurMat.setFloat("Size", screenWidth);
    153                 hBlurMat.setFloat("Scale", blurScale);
    154             }
    155         };
    156 
    157         horizontalBlur.init(renderManager.getRenderer(), screenWidth, screenHeight, Format.RGBA8, Format.Depth, 1, hBlurMat);
    158         postRenderPasses.add(horizontalBlur);
    159 
    160         //configuring vertical blur pass
    161         vBlurMat = new Material(manager, "Common/MatDefs/Blur/VGaussianBlur.j3md");
    162         verticalalBlur = new Pass() {
    163 
    164             @Override
    165             public void beforeRender() {
    166                 vBlurMat.setTexture("Texture", horizontalBlur.getRenderedTexture());
    167                 vBlurMat.setFloat("Size", screenHeight);
    168                 vBlurMat.setFloat("Scale", blurScale);
    169             }
    170         };
    171 
    172         verticalalBlur.init(renderManager.getRenderer(), screenWidth, screenHeight, Format.RGBA8, Format.Depth, 1, vBlurMat);
    173         postRenderPasses.add(verticalalBlur);
    174 
    175 
    176         //final material
    177         material = new Material(manager, "Common/MatDefs/Post/BloomFinal.j3md");
    178         material.setTexture("BloomTex", verticalalBlur.getRenderedTexture());
    179     }
    180 
    181 
    182     @Override
    183     protected Material getMaterial() {
    184         material.setFloat("BloomIntensity", bloomIntensity);
    185         return material;
    186     }
    187 
    188     @Override
    189     protected void postQueue(RenderManager renderManager, ViewPort viewPort) {
    190         if (glowMode != GlowMode.Scene) {
    191             renderManager.getRenderer().setBackgroundColor(ColorRGBA.BlackNoAlpha);
    192             renderManager.getRenderer().setFrameBuffer(preGlowPass.getRenderFrameBuffer());
    193             renderManager.getRenderer().clearBuffers(true, true, true);
    194             renderManager.setForcedTechnique("Glow");
    195             renderManager.renderViewPortQueues(viewPort, false);
    196             renderManager.setForcedTechnique(null);
    197             renderManager.getRenderer().setFrameBuffer(viewPort.getOutputFrameBuffer());
    198         }
    199     }
    200 
    201     /**
    202      * returns the bloom intensity
    203      * @return
    204      */
    205     public float getBloomIntensity() {
    206         return bloomIntensity;
    207     }
    208 
    209     /**
    210      * intensity of the bloom effect default is 2.0
    211      * @param bloomIntensity
    212      */
    213     public void setBloomIntensity(float bloomIntensity) {
    214         this.bloomIntensity = bloomIntensity;
    215     }
    216 
    217     /**
    218      * returns the blur scale
    219      * @return
    220      */
    221     public float getBlurScale() {
    222         return blurScale;
    223     }
    224 
    225     /**
    226      * sets The spread of the bloom default is 1.5f
    227      * @param blurScale
    228      */
    229     public void setBlurScale(float blurScale) {
    230         this.blurScale = blurScale;
    231     }
    232 
    233     /**
    234      * returns the exposure cutoff<br>
    235      * for more details see {@link setExposureCutOff(float exposureCutOff)}
    236      * @return
    237      */
    238     public float getExposureCutOff() {
    239         return exposureCutOff;
    240     }
    241 
    242     /**
    243      * Define the color threshold on which the bloom will be applied (0.0 to 1.0)
    244      * @param exposureCutOff
    245      */
    246     public void setExposureCutOff(float exposureCutOff) {
    247         this.exposureCutOff = exposureCutOff;
    248     }
    249 
    250     /**
    251      * returns the exposure power<br>
    252      * form more details see {@link setExposurePower(float exposurePower)}
    253      * @return
    254      */
    255     public float getExposurePower() {
    256         return exposurePower;
    257     }
    258 
    259     /**
    260      * defines how many time the bloom extracted color will be multiplied by itself. default id 5.0<br>
    261      * a high value will reduce rough edges in the bloom and somhow the range of the bloom area     *
    262      * @param exposurePower
    263      */
    264     public void setExposurePower(float exposurePower) {
    265         this.exposurePower = exposurePower;
    266     }
    267 
    268     /**
    269      * returns the downSampling factor<br>
    270      * form more details see {@link setDownSamplingFactor(float downSamplingFactor)}
    271      * @return
    272      */
    273     public float getDownSamplingFactor() {
    274         return downSamplingFactor;
    275     }
    276 
    277     /**
    278      * Sets the downSampling factor : the size of the computed texture will be divided by this factor. default is 1 for no downsampling
    279      * A 2 value is a good way of widening the blur
    280      * @param downSamplingFactor
    281      */
    282     public void setDownSamplingFactor(float downSamplingFactor) {
    283         this.downSamplingFactor = downSamplingFactor;
    284     }
    285 
    286     @Override
    287     public void write(JmeExporter ex) throws IOException {
    288         super.write(ex);
    289         OutputCapsule oc = ex.getCapsule(this);
    290         oc.write(glowMode, "glowMode", GlowMode.Scene);
    291         oc.write(blurScale, "blurScale", 1.5f);
    292         oc.write(exposurePower, "exposurePower", 5.0f);
    293         oc.write(exposureCutOff, "exposureCutOff", 0.0f);
    294         oc.write(bloomIntensity, "bloomIntensity", 2.0f);
    295         oc.write(downSamplingFactor, "downSamplingFactor", 1);
    296     }
    297 
    298     @Override
    299     public void read(JmeImporter im) throws IOException {
    300         super.read(im);
    301         InputCapsule ic = im.getCapsule(this);
    302         glowMode = ic.readEnum("glowMode", GlowMode.class, GlowMode.Scene);
    303         blurScale = ic.readFloat("blurScale", 1.5f);
    304         exposurePower = ic.readFloat("exposurePower", 5.0f);
    305         exposureCutOff = ic.readFloat("exposureCutOff", 0.0f);
    306         bloomIntensity = ic.readFloat("bloomIntensity", 2.0f);
    307         downSamplingFactor = ic.readFloat("downSamplingFactor", 1);
    308     }
    309 }
    310