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