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.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