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.Vector3f; 41 import com.jme3.post.Filter; 42 import com.jme3.renderer.Camera; 43 import com.jme3.renderer.RenderManager; 44 import com.jme3.renderer.ViewPort; 45 import java.io.IOException; 46 47 /** 48 * LightScattering filters creates rays comming from a light sources 49 * This is often reffered as god rays. 50 * 51 * @author Rmy Bouquet aka Nehon 52 */ 53 public class LightScatteringFilter extends Filter { 54 55 private Vector3f lightPosition; 56 private Vector3f screenLightPos = new Vector3f(); 57 private int nbSamples = 50; 58 private float blurStart = 0.02f; 59 private float blurWidth = 0.9f; 60 private float lightDensity = 1.4f; 61 private boolean adaptative = true; 62 Vector3f viewLightPos = new Vector3f(); 63 private boolean display = true; 64 private float innerLightDensity; 65 66 /** 67 * creates a lightScaterring filter 68 */ 69 public LightScatteringFilter() { 70 super("Light Scattering"); 71 } 72 73 /** 74 * Creates a lightScatteringFilter 75 * @param lightPosition 76 */ 77 public LightScatteringFilter(Vector3f lightPosition) { 78 this(); 79 this.lightPosition = lightPosition; 80 } 81 82 @Override 83 protected boolean isRequiresDepthTexture() { 84 return true; 85 } 86 87 @Override 88 protected Material getMaterial() { 89 material.setVector3("LightPosition", screenLightPos); 90 material.setInt("NbSamples", nbSamples); 91 material.setFloat("BlurStart", blurStart); 92 material.setFloat("BlurWidth", blurWidth); 93 material.setFloat("LightDensity", innerLightDensity); 94 material.setBoolean("Display", display); 95 return material; 96 } 97 98 @Override 99 protected void postQueue(RenderManager renderManager, ViewPort viewPort) { 100 getClipCoordinates(lightPosition, screenLightPos, viewPort.getCamera()); 101 // screenLightPos.x = screenLightPos.x / viewPort.getCamera().getWidth(); 102 // screenLightPos.y = screenLightPos.y / viewPort.getCamera().getHeight(); 103 104 viewPort.getCamera().getViewMatrix().mult(lightPosition, viewLightPos); 105 //System.err.println("viewLightPos "+viewLightPos); 106 display = screenLightPos.x < 1.6f && screenLightPos.x > -0.6f && screenLightPos.y < 1.6f && screenLightPos.y > -0.6f && viewLightPos.z < 0; 107 //System.err.println("camdir "+viewPort.getCamera().getDirection()); 108 //System.err.println("lightPos "+lightPosition); 109 //System.err.println("screenLightPos "+screenLightPos); 110 if (adaptative) { 111 innerLightDensity = Math.max(lightDensity - Math.max(screenLightPos.x, screenLightPos.y), 0.0f); 112 } else { 113 innerLightDensity = lightDensity; 114 } 115 } 116 117 private Vector3f getClipCoordinates(Vector3f worldPosition, Vector3f store, Camera cam) { 118 119 float w = cam.getViewProjectionMatrix().multProj(worldPosition, store); 120 store.divideLocal(w); 121 122 store.x = ((store.x + 1f) * (cam.getViewPortRight() - cam.getViewPortLeft()) / 2f + cam.getViewPortLeft()); 123 store.y = ((store.y + 1f) * (cam.getViewPortTop() - cam.getViewPortBottom()) / 2f + cam.getViewPortBottom()); 124 store.z = (store.z + 1f) / 2f; 125 126 return store; 127 } 128 129 @Override 130 protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) { 131 material = new Material(manager, "Common/MatDefs/Post/LightScattering.j3md"); 132 } 133 134 /** 135 * returns the blur start of the scattering 136 * see {@link setBlurStart(float blurStart)} 137 * @return 138 */ 139 public float getBlurStart() { 140 return blurStart; 141 } 142 143 /** 144 * sets the blur start<br> 145 * at which distance from the light source the effect starts default is 0.02 146 * @param blurStart 147 */ 148 public void setBlurStart(float blurStart) { 149 this.blurStart = blurStart; 150 } 151 152 /** 153 * returns the blur width<br> 154 * see {@link setBlurWidth(float blurWidth)} 155 * @return 156 */ 157 public float getBlurWidth() { 158 return blurWidth; 159 } 160 161 /** 162 * sets the blur width default is 0.9 163 * @param blurWidth 164 */ 165 public void setBlurWidth(float blurWidth) { 166 this.blurWidth = blurWidth; 167 } 168 169 /** 170 * retiurns the light density<br> 171 * see {@link setLightDensity(float lightDensity)} 172 * 173 * @return 174 */ 175 public float getLightDensity() { 176 return lightDensity; 177 } 178 179 /** 180 * sets how much the effect is visible over the rendered scene default is 1.4 181 * @param lightDensity 182 */ 183 public void setLightDensity(float lightDensity) { 184 this.lightDensity = lightDensity; 185 } 186 187 /** 188 * returns the light position 189 * @return 190 */ 191 public Vector3f getLightPosition() { 192 return lightPosition; 193 } 194 195 /** 196 * sets the light position 197 * @param lightPosition 198 */ 199 public void setLightPosition(Vector3f lightPosition) { 200 this.lightPosition = lightPosition; 201 } 202 203 /** 204 * returns the nmber of samples for the radial blur 205 * @return 206 */ 207 public int getNbSamples() { 208 return nbSamples; 209 } 210 211 /** 212 * sets the number of samples for the radial blur default is 50 213 * the higher the value the higher the quality, but the slower the performances. 214 * @param nbSamples 215 */ 216 public void setNbSamples(int nbSamples) { 217 this.nbSamples = nbSamples; 218 } 219 220 @Override 221 public void write(JmeExporter ex) throws IOException { 222 super.write(ex); 223 OutputCapsule oc = ex.getCapsule(this); 224 oc.write(lightPosition, "lightPosition", Vector3f.ZERO); 225 oc.write(nbSamples, "nbSamples", 50); 226 oc.write(blurStart, "blurStart", 0.02f); 227 oc.write(blurWidth, "blurWidth", 0.9f); 228 oc.write(lightDensity, "lightDensity", 1.4f); 229 oc.write(adaptative, "adaptative", true); 230 } 231 232 @Override 233 public void read(JmeImporter im) throws IOException { 234 super.read(im); 235 InputCapsule ic = im.getCapsule(this); 236 lightPosition = (Vector3f) ic.readSavable("lightPosition", Vector3f.ZERO); 237 nbSamples = ic.readInt("nbSamples", 50); 238 blurStart = ic.readFloat("blurStart", 0.02f); 239 blurWidth = ic.readFloat("blurWidth", 0.9f); 240 lightDensity = ic.readFloat("lightDensity", 1.4f); 241 adaptative = ic.readBoolean("adaptative", true); 242 } 243 } 244