aboutsummaryrefslogtreecommitdiff
path: root/engine/src/core-effects/com/jme3
diff options
context:
space:
mode:
authorScott Barta <sbarta@google.com>2012-03-01 12:35:35 -0800
committerScott Barta <sbarta@google.com>2012-03-01 12:40:08 -0800
commit59b2e6871c65f58fdad78cd7229c292f6a177578 (patch)
tree2d4e7bfc05b93f40b34675d77e403dd1c25efafd /engine/src/core-effects/com/jme3
parentf9b30489e75ac1eabc365064959804e99534f7ab (diff)
downloadjmonkeyengine-59b2e6871c65f58fdad78cd7229c292f6a177578.tar.gz
Adds the jMonkeyEngine library to the build.
Adds the jMonkeyEngine open source 3D game engine to the build. This is built as a static library and is only used by the Finsky client. Change-Id: I06a3f054df7b8a67757267d884854f70c5a16ca0
Diffstat (limited to 'engine/src/core-effects/com/jme3')
-rw-r--r--engine/src/core-effects/com/jme3/post/filters/BloomFilter.java309
-rw-r--r--engine/src/core-effects/com/jme3/post/filters/CartoonEdgeFilter.java245
-rw-r--r--engine/src/core-effects/com/jme3/post/filters/ColorOverlayFilter.java111
-rw-r--r--engine/src/core-effects/com/jme3/post/filters/CrossHatchFilter.java305
-rw-r--r--engine/src/core-effects/com/jme3/post/filters/DepthOfFieldFilter.java158
-rw-r--r--engine/src/core-effects/com/jme3/post/filters/FXAAFilter.java95
-rw-r--r--engine/src/core-effects/com/jme3/post/filters/FadeFilter.java177
-rw-r--r--engine/src/core-effects/com/jme3/post/filters/FogFilter.java172
-rw-r--r--engine/src/core-effects/com/jme3/post/filters/GammaCorrectionFilter.java78
-rw-r--r--engine/src/core-effects/com/jme3/post/filters/LightScatteringFilter.java243
-rw-r--r--engine/src/core-effects/com/jme3/post/filters/PosterizationFilter.java147
-rw-r--r--engine/src/core-effects/com/jme3/post/filters/RadialBlurFilter.java156
-rw-r--r--engine/src/core-effects/com/jme3/post/filters/TranslucentBucketFilter.java80
-rw-r--r--engine/src/core-effects/com/jme3/post/ssao/SSAOFilter.java324
-rw-r--r--engine/src/core-effects/com/jme3/water/ReflectionProcessor.java125
-rw-r--r--engine/src/core-effects/com/jme3/water/SimpleWaterProcessor.java589
-rw-r--r--engine/src/core-effects/com/jme3/water/WaterFilter.java1050
17 files changed, 4364 insertions, 0 deletions
diff --git a/engine/src/core-effects/com/jme3/post/filters/BloomFilter.java b/engine/src/core-effects/com/jme3/post/filters/BloomFilter.java
new file mode 100644
index 0000000..770e7f4
--- /dev/null
+++ b/engine/src/core-effects/com/jme3/post/filters/BloomFilter.java
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 2009-2010 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.post.filters;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.export.InputCapsule;
+import com.jme3.export.JmeExporter;
+import com.jme3.export.JmeImporter;
+import com.jme3.export.OutputCapsule;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.post.Filter;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+import com.jme3.texture.Image.Format;
+import java.io.IOException;
+import java.util.ArrayList;
+
+/**
+ * BloomFilter is used to make objects in the scene have a glow effect.<br>
+ * There are 2 mode : Scene and Objects.<br>
+ * Scene mode extracts the bright parts of the scene to make them glow<br>
+ * Object mode make objects glow according to their material's glowMap or their GlowColor<br>
+ * @see <a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:bloom_and_glow">advanced:bloom_and_glow</a> for more details
+ *
+ * @author Rémy Bouquet aka Nehon
+ */
+public class BloomFilter extends Filter {
+
+ /**
+ * GlowMode specifies if the glow will be applied to the whole scene,or to objects that have aglow color or a glow map
+ */
+ public enum GlowMode {
+
+ /**
+ * Apply bloom filter to bright areas in the scene.
+ */
+ Scene,
+ /**
+ * Apply bloom only to objects that have a glow map or a glow color.
+ */
+ Objects,
+ /**
+ * Apply bloom to both bright parts of the scene and objects with glow map.
+ */
+ SceneAndObjects;
+ }
+
+ private GlowMode glowMode = GlowMode.Scene;
+ //Bloom parameters
+ private float blurScale = 1.5f;
+ private float exposurePower = 5.0f;
+ private float exposureCutOff = 0.0f;
+ private float bloomIntensity = 2.0f;
+ private float downSamplingFactor = 1;
+ private Pass preGlowPass;
+ private Pass extractPass;
+ private Pass horizontalBlur = new Pass();
+ private Pass verticalalBlur = new Pass();
+ private Material extractMat;
+ private Material vBlurMat;
+ private Material hBlurMat;
+ private int screenWidth;
+ private int screenHeight;
+
+ /**
+ * Creates a Bloom filter
+ */
+ public BloomFilter() {
+ super("BloomFilter");
+ }
+
+ /**
+ * Creates the bloom filter with the specific glow mode
+ * @param glowMode
+ */
+ public BloomFilter(GlowMode glowMode) {
+ this();
+ this.glowMode = glowMode;
+ }
+
+ @Override
+ protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
+ screenWidth = (int) Math.max(1, (w / downSamplingFactor));
+ screenHeight = (int) Math.max(1, (h / downSamplingFactor));
+ // System.out.println(screenWidth + " " + screenHeight);
+ if (glowMode != GlowMode.Scene) {
+ preGlowPass = new Pass();
+ preGlowPass.init(renderManager.getRenderer(), screenWidth, screenHeight, Format.RGBA8, Format.Depth);
+ }
+
+ postRenderPasses = new ArrayList<Pass>();
+ //configuring extractPass
+ extractMat = new Material(manager, "Common/MatDefs/Post/BloomExtract.j3md");
+ extractPass = new Pass() {
+
+ @Override
+ public boolean requiresSceneAsTexture() {
+ return true;
+ }
+
+ @Override
+ public void beforeRender() {
+ extractMat.setFloat("ExposurePow", exposurePower);
+ extractMat.setFloat("ExposureCutoff", exposureCutOff);
+ if (glowMode != GlowMode.Scene) {
+ extractMat.setTexture("GlowMap", preGlowPass.getRenderedTexture());
+ }
+ extractMat.setBoolean("Extract", glowMode != GlowMode.Objects);
+ }
+ };
+
+ extractPass.init(renderManager.getRenderer(), screenWidth, screenHeight, Format.RGBA8, Format.Depth, 1, extractMat);
+ postRenderPasses.add(extractPass);
+
+ //configuring horizontal blur pass
+ hBlurMat = new Material(manager, "Common/MatDefs/Blur/HGaussianBlur.j3md");
+ horizontalBlur = new Pass() {
+
+ @Override
+ public void beforeRender() {
+ hBlurMat.setTexture("Texture", extractPass.getRenderedTexture());
+ hBlurMat.setFloat("Size", screenWidth);
+ hBlurMat.setFloat("Scale", blurScale);
+ }
+ };
+
+ horizontalBlur.init(renderManager.getRenderer(), screenWidth, screenHeight, Format.RGBA8, Format.Depth, 1, hBlurMat);
+ postRenderPasses.add(horizontalBlur);
+
+ //configuring vertical blur pass
+ vBlurMat = new Material(manager, "Common/MatDefs/Blur/VGaussianBlur.j3md");
+ verticalalBlur = new Pass() {
+
+ @Override
+ public void beforeRender() {
+ vBlurMat.setTexture("Texture", horizontalBlur.getRenderedTexture());
+ vBlurMat.setFloat("Size", screenHeight);
+ vBlurMat.setFloat("Scale", blurScale);
+ }
+ };
+
+ verticalalBlur.init(renderManager.getRenderer(), screenWidth, screenHeight, Format.RGBA8, Format.Depth, 1, vBlurMat);
+ postRenderPasses.add(verticalalBlur);
+
+
+ //final material
+ material = new Material(manager, "Common/MatDefs/Post/BloomFinal.j3md");
+ material.setTexture("BloomTex", verticalalBlur.getRenderedTexture());
+ }
+
+
+ @Override
+ protected Material getMaterial() {
+ material.setFloat("BloomIntensity", bloomIntensity);
+ return material;
+ }
+
+ @Override
+ protected void postQueue(RenderManager renderManager, ViewPort viewPort) {
+ if (glowMode != GlowMode.Scene) {
+ renderManager.getRenderer().setBackgroundColor(ColorRGBA.BlackNoAlpha);
+ renderManager.getRenderer().setFrameBuffer(preGlowPass.getRenderFrameBuffer());
+ renderManager.getRenderer().clearBuffers(true, true, true);
+ renderManager.setForcedTechnique("Glow");
+ renderManager.renderViewPortQueues(viewPort, false);
+ renderManager.setForcedTechnique(null);
+ renderManager.getRenderer().setFrameBuffer(viewPort.getOutputFrameBuffer());
+ }
+ }
+
+ /**
+ * returns the bloom intensity
+ * @return
+ */
+ public float getBloomIntensity() {
+ return bloomIntensity;
+ }
+
+ /**
+ * intensity of the bloom effect default is 2.0
+ * @param bloomIntensity
+ */
+ public void setBloomIntensity(float bloomIntensity) {
+ this.bloomIntensity = bloomIntensity;
+ }
+
+ /**
+ * returns the blur scale
+ * @return
+ */
+ public float getBlurScale() {
+ return blurScale;
+ }
+
+ /**
+ * sets The spread of the bloom default is 1.5f
+ * @param blurScale
+ */
+ public void setBlurScale(float blurScale) {
+ this.blurScale = blurScale;
+ }
+
+ /**
+ * returns the exposure cutoff<br>
+ * for more details see {@link setExposureCutOff(float exposureCutOff)}
+ * @return
+ */
+ public float getExposureCutOff() {
+ return exposureCutOff;
+ }
+
+ /**
+ * Define the color threshold on which the bloom will be applied (0.0 to 1.0)
+ * @param exposureCutOff
+ */
+ public void setExposureCutOff(float exposureCutOff) {
+ this.exposureCutOff = exposureCutOff;
+ }
+
+ /**
+ * returns the exposure power<br>
+ * form more details see {@link setExposurePower(float exposurePower)}
+ * @return
+ */
+ public float getExposurePower() {
+ return exposurePower;
+ }
+
+ /**
+ * defines how many time the bloom extracted color will be multiplied by itself. default id 5.0<br>
+ * a high value will reduce rough edges in the bloom and somhow the range of the bloom area *
+ * @param exposurePower
+ */
+ public void setExposurePower(float exposurePower) {
+ this.exposurePower = exposurePower;
+ }
+
+ /**
+ * returns the downSampling factor<br>
+ * form more details see {@link setDownSamplingFactor(float downSamplingFactor)}
+ * @return
+ */
+ public float getDownSamplingFactor() {
+ return downSamplingFactor;
+ }
+
+ /**
+ * Sets the downSampling factor : the size of the computed texture will be divided by this factor. default is 1 for no downsampling
+ * A 2 value is a good way of widening the blur
+ * @param downSamplingFactor
+ */
+ public void setDownSamplingFactor(float downSamplingFactor) {
+ this.downSamplingFactor = downSamplingFactor;
+ }
+
+ @Override
+ public void write(JmeExporter ex) throws IOException {
+ super.write(ex);
+ OutputCapsule oc = ex.getCapsule(this);
+ oc.write(glowMode, "glowMode", GlowMode.Scene);
+ oc.write(blurScale, "blurScale", 1.5f);
+ oc.write(exposurePower, "exposurePower", 5.0f);
+ oc.write(exposureCutOff, "exposureCutOff", 0.0f);
+ oc.write(bloomIntensity, "bloomIntensity", 2.0f);
+ oc.write(downSamplingFactor, "downSamplingFactor", 1);
+ }
+
+ @Override
+ public void read(JmeImporter im) throws IOException {
+ super.read(im);
+ InputCapsule ic = im.getCapsule(this);
+ glowMode = ic.readEnum("glowMode", GlowMode.class, GlowMode.Scene);
+ blurScale = ic.readFloat("blurScale", 1.5f);
+ exposurePower = ic.readFloat("exposurePower", 5.0f);
+ exposureCutOff = ic.readFloat("exposureCutOff", 0.0f);
+ bloomIntensity = ic.readFloat("bloomIntensity", 2.0f);
+ downSamplingFactor = ic.readFloat("downSamplingFactor", 1);
+ }
+}
diff --git a/engine/src/core-effects/com/jme3/post/filters/CartoonEdgeFilter.java b/engine/src/core-effects/com/jme3/post/filters/CartoonEdgeFilter.java
new file mode 100644
index 0000000..3e9998b
--- /dev/null
+++ b/engine/src/core-effects/com/jme3/post/filters/CartoonEdgeFilter.java
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2009-2010 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.post.filters;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.post.Filter;
+import com.jme3.post.Filter.Pass;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.Renderer;
+import com.jme3.renderer.ViewPort;
+import com.jme3.texture.Image.Format;
+
+/**
+ * Applies a cartoon-style edge detection filter to all objects in the scene.
+ *
+ * @author Kirill Vainer
+ */
+public class CartoonEdgeFilter extends Filter {
+
+ private Pass normalPass;
+ private float edgeWidth = 1.0f;
+ private float edgeIntensity = 1.0f;
+ private float normalThreshold = 0.5f;
+ private float depthThreshold = 0.1f;
+ private float normalSensitivity = 1.0f;
+ private float depthSensitivity = 10.0f;
+ private ColorRGBA edgeColor = new ColorRGBA(0, 0, 0, 1);
+
+ /**
+ * Creates a CartoonEdgeFilter
+ */
+ public CartoonEdgeFilter() {
+ super("CartoonEdgeFilter");
+ }
+
+ @Override
+ protected boolean isRequiresDepthTexture() {
+ return true;
+ }
+
+ @Override
+ protected void postQueue(RenderManager renderManager, ViewPort viewPort) {
+ Renderer r = renderManager.getRenderer();
+ r.setFrameBuffer(normalPass.getRenderFrameBuffer());
+ renderManager.getRenderer().clearBuffers(true, true, true);
+ renderManager.setForcedTechnique("PreNormalPass");
+ renderManager.renderViewPortQueues(viewPort, false);
+ renderManager.setForcedTechnique(null);
+ renderManager.getRenderer().setFrameBuffer(viewPort.getOutputFrameBuffer());
+ }
+
+ @Override
+ protected Material getMaterial() {
+ material.setTexture("NormalsTexture", normalPass.getRenderedTexture());
+ return material;
+ }
+
+ @Override
+ protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
+ normalPass = new Pass();
+ normalPass.init(renderManager.getRenderer(), w, h, Format.RGBA8, Format.Depth);
+ material = new Material(manager, "Common/MatDefs/Post/CartoonEdge.j3md");
+ material.setFloat("EdgeWidth", edgeWidth);
+ material.setFloat("EdgeIntensity", edgeIntensity);
+ material.setFloat("NormalThreshold", normalThreshold);
+ material.setFloat("DepthThreshold", depthThreshold);
+ material.setFloat("NormalSensitivity", normalSensitivity);
+ material.setFloat("DepthSensitivity", depthSensitivity);
+ material.setColor("EdgeColor", edgeColor);
+ }
+
+ /**
+ * Return the depth sensitivity<br>
+ * for more details see {@link setDepthSensitivity(float depthSensitivity)}
+ * @return
+ */
+ public float getDepthSensitivity() {
+ return depthSensitivity;
+ }
+
+ /**
+ * sets the depth sensitivity<br>
+ * defines how much depth will influence edges, default is 10
+ * @param depthSensitivity
+ */
+ public void setDepthSensitivity(float depthSensitivity) {
+ this.depthSensitivity = depthSensitivity;
+ if (material != null) {
+ material.setFloat("DepthSensitivity", depthSensitivity);
+ }
+ }
+
+ /**
+ * returns the depth threshold<br>
+ * for more details see {@link setDepthThreshold(float depthThreshold)}
+ * @return
+ */
+ public float getDepthThreshold() {
+ return depthThreshold;
+ }
+
+ /**
+ * sets the depth threshold<br>
+ * Defines at what threshold of difference of depth an edge is outlined default is 0.1f
+ * @param depthThreshold
+ */
+ public void setDepthThreshold(float depthThreshold) {
+ this.depthThreshold = depthThreshold;
+ if (material != null) {
+ material.setFloat("DepthThreshold", depthThreshold);
+ }
+ }
+
+ /**
+ * returns the edge intensity<br>
+ * for more details see {@link setEdgeIntensity(float edgeIntensity) }
+ * @return
+ */
+ public float getEdgeIntensity() {
+ return edgeIntensity;
+ }
+
+ /**
+ * sets the edge intensity<br>
+ * Defineshow visilble will be the outlined edges
+ * @param edgeIntensity
+ */
+ public void setEdgeIntensity(float edgeIntensity) {
+ this.edgeIntensity = edgeIntensity;
+ if (material != null) {
+ material.setFloat("EdgeIntensity", edgeIntensity);
+ }
+ }
+
+ /**
+ * returns the width of the edges
+ * @return
+ */
+ public float getEdgeWidth() {
+ return edgeWidth;
+ }
+
+ /**
+ * sets the witdh of the edge in pixels default is 1
+ * @param edgeWidth
+ */
+ public void setEdgeWidth(float edgeWidth) {
+ this.edgeWidth = edgeWidth;
+ if (material != null) {
+ material.setFloat("EdgeWidth", edgeWidth);
+ }
+
+ }
+
+ /**
+ * returns the normals sensitivity<br>
+ * form more details see {@link setNormalSensitivity(float normalSensitivity)}
+ * @return
+ */
+ public float getNormalSensitivity() {
+ return normalSensitivity;
+ }
+
+ /**
+ * sets the normals sensitivity default is 1
+ * @param normalSensitivity
+ */
+ public void setNormalSensitivity(float normalSensitivity) {
+ this.normalSensitivity = normalSensitivity;
+ if (material != null) {
+ material.setFloat("NormalSensitivity", normalSensitivity);
+ }
+ }
+
+ /**
+ * returns the normal threshold<br>
+ * for more details see {@link setNormalThreshold(float normalThreshold)}
+ *
+ * @return
+ */
+ public float getNormalThreshold() {
+ return normalThreshold;
+ }
+
+ /**
+ * sets the normal threshold default is 0.5
+ * @param normalThreshold
+ */
+ public void setNormalThreshold(float normalThreshold) {
+ this.normalThreshold = normalThreshold;
+ if (material != null) {
+ material.setFloat("NormalThreshold", normalThreshold);
+ }
+ }
+
+ /**
+ * returns the edge color
+ * @return
+ */
+ public ColorRGBA getEdgeColor() {
+ return edgeColor;
+ }
+
+ /**
+ * Sets the edge color, default is black
+ * @param edgeColor
+ */
+ public void setEdgeColor(ColorRGBA edgeColor) {
+ this.edgeColor = edgeColor;
+ if (material != null) {
+ material.setColor("EdgeColor", edgeColor);
+ }
+ }
+}
diff --git a/engine/src/core-effects/com/jme3/post/filters/ColorOverlayFilter.java b/engine/src/core-effects/com/jme3/post/filters/ColorOverlayFilter.java
new file mode 100644
index 0000000..a7f30f8
--- /dev/null
+++ b/engine/src/core-effects/com/jme3/post/filters/ColorOverlayFilter.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2009-2010 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.post.filters;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.export.InputCapsule;
+import com.jme3.export.JmeExporter;
+import com.jme3.export.JmeImporter;
+import com.jme3.export.OutputCapsule;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.post.Filter;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+import java.io.IOException;
+
+/**
+ * This filter simply multiply the whole scene by a color
+ * @author Rémy Bouquet aka Nehon
+ */
+public class ColorOverlayFilter extends Filter {
+
+ private ColorRGBA color = ColorRGBA.White;
+
+ /**
+ * creates a colorOverlayFilter with a white coor (transparent)
+ */
+ public ColorOverlayFilter() {
+ super("Color Overlay");
+ }
+
+ /**
+ * creates a colorOverlayFilter with the given color
+ * @param color
+ */
+ public ColorOverlayFilter(ColorRGBA color) {
+ this();
+ this.color = color;
+ }
+
+ @Override
+ protected Material getMaterial() {
+
+ material.setColor("Color", color);
+ return material;
+ }
+
+ /**
+ * returns the color
+ * @return color
+ */
+ public ColorRGBA getColor() {
+ return color;
+ }
+
+ /**
+ * sets the color
+ * @param color
+ */
+ public void setColor(ColorRGBA color) {
+ this.color = color;
+ }
+
+ @Override
+ protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
+ material = new Material(manager, "Common/MatDefs/Post/Overlay.j3md");
+ }
+
+ @Override
+ public void write(JmeExporter ex) throws IOException {
+ super.write(ex);
+ OutputCapsule oc = ex.getCapsule(this);
+ oc.write(color, "color", ColorRGBA.White);
+ }
+
+ @Override
+ public void read(JmeImporter im) throws IOException {
+ super.read(im);
+ InputCapsule ic = im.getCapsule(this);
+ color = (ColorRGBA) ic.readSavable("color", ColorRGBA.White);
+ }
+}
diff --git a/engine/src/core-effects/com/jme3/post/filters/CrossHatchFilter.java b/engine/src/core-effects/com/jme3/post/filters/CrossHatchFilter.java
new file mode 100644
index 0000000..699a252
--- /dev/null
+++ b/engine/src/core-effects/com/jme3/post/filters/CrossHatchFilter.java
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.post.filters;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.post.Filter;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+
+/**
+ * A Post Processing filter that makes the screen look like it was drawn as
+ * diagonal lines with a pen.
+ * Try combining this with a cartoon edge filter to obtain manga style visuals.
+ *
+ * Based on an article from Geeks3D:
+ * <a href="http://www.geeks3d.com/20110219/shader-library-crosshatching-glsl-filter/" rel="nofollow">http://www.geeks3d.com/20110219/shader-library-crosshatching-glsl-filter/</a>
+ *
+ * @author Roy Straver a.k.a. Baal Garnaal
+ */
+public class CrossHatchFilter extends Filter {
+
+ private ColorRGBA lineColor = ColorRGBA.Black.clone();
+ private ColorRGBA paperColor = ColorRGBA.White.clone();
+ private float colorInfluenceLine = 0.8f;
+ private float colorInfluencePaper = 0.1f;
+ private float fillValue = 0.9f;
+ private float luminance1 = 0.9f;
+ private float luminance2 = 0.7f;
+ private float luminance3 = 0.5f;
+ private float luminance4 = 0.3f;
+ private float luminance5 = 0.0f;
+ private float lineThickness = 1.0f;
+ private float lineDistance = 4.0f;
+
+ /**
+ * Creates a crossHatch filter
+ */
+ public CrossHatchFilter() {
+ super("CrossHatchFilter");
+ }
+
+ /**
+ * Creates a crossHatch filter
+ * @param lineColor the colors of the lines
+ * @param paperColor the paper color
+ */
+ public CrossHatchFilter(ColorRGBA lineColor, ColorRGBA paperColor) {
+ this();
+ this.lineColor = lineColor;
+ this.paperColor = paperColor;
+ }
+
+ @Override
+ protected boolean isRequiresDepthTexture() {
+ return false;
+ }
+
+ @Override
+ protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
+ material = new Material(manager, "Common/MatDefs/Post/CrossHatch.j3md");
+ material.setColor("LineColor", lineColor);
+ material.setColor("PaperColor", paperColor);
+
+ material.setFloat("ColorInfluenceLine", colorInfluenceLine);
+ material.setFloat("ColorInfluencePaper", colorInfluencePaper);
+
+ material.setFloat("FillValue", fillValue);
+
+ material.setFloat("Luminance1", luminance1);
+ material.setFloat("Luminance2", luminance2);
+ material.setFloat("Luminance3", luminance3);
+ material.setFloat("Luminance4", luminance4);
+ material.setFloat("Luminance5", luminance5);
+
+ material.setFloat("LineThickness", lineThickness);
+ material.setFloat("LineDistance", lineDistance);
+ }
+
+ @Override
+ protected Material getMaterial() {
+ return material;
+ }
+
+ /**
+ * Sets color used to draw lines
+ * @param lineColor
+ */
+ public void setLineColor(ColorRGBA lineColor) {
+ this.lineColor = lineColor;
+ if (material != null) {
+ material.setColor("LineColor", lineColor);
+ }
+ }
+
+ /**
+ * Sets color used as background
+ * @param paperColor
+ */
+ public void setPaperColor(ColorRGBA paperColor) {
+ this.paperColor = paperColor;
+ if (material != null) {
+ material.setColor("PaperColor", paperColor);
+ }
+ }
+
+ /**
+ * Sets color influence of original image on lines drawn
+ * @param colorInfluenceLine
+ */
+ public void setColorInfluenceLine(float colorInfluenceLine) {
+ this.colorInfluenceLine = colorInfluenceLine;
+ if (material != null) {
+ material.setFloat("ColorInfluenceLine", colorInfluenceLine);
+ }
+ }
+
+ /**
+ * Sets color influence of original image on non-line areas
+ * @param colorInfluencePaper
+ */
+ public void setColorInfluencePaper(float colorInfluencePaper) {
+ this.colorInfluencePaper = colorInfluencePaper;
+ if (material != null) {
+ material.setFloat("ColorInfluencePaper", colorInfluencePaper);
+ }
+ }
+
+ /**
+ * Sets line/paper color ratio for areas with values < luminance5,
+ * really dark areas get no lines but a filled blob instead
+ * @param fillValue
+ */
+ public void setFillValue(float fillValue) {
+ this.fillValue = fillValue;
+ if (material != null) {
+ material.setFloat("FillValue", fillValue);
+ }
+ }
+
+ /**
+ *
+ * Sets minimum luminance levels for lines drawn
+ * @param luminance1 Top-left to down right 1
+ * @param luminance2 Top-right to bottom left 1
+ * @param luminance3 Top-left to down right 2
+ * @param luminance4 Top-right to bottom left 2
+ * @param luminance5 Blobs
+ */
+ public void setLuminanceLevels(float luminance1, float luminance2, float luminance3, float luminance4, float luminance5) {
+ this.luminance1 = luminance1;
+ this.luminance2 = luminance2;
+ this.luminance3 = luminance3;
+ this.luminance4 = luminance4;
+ this.luminance5 = luminance5;
+
+ if (material != null) {
+ material.setFloat("Luminance1", luminance1);
+ material.setFloat("Luminance2", luminance2);
+ material.setFloat("Luminance3", luminance3);
+ material.setFloat("Luminance4", luminance4);
+ material.setFloat("Luminance5", luminance5);
+ }
+ }
+
+ /**
+ * Sets the thickness of lines drawn
+ * @param lineThickness
+ */
+ public void setLineThickness(float lineThickness) {
+ this.lineThickness = lineThickness;
+ if (material != null) {
+ material.setFloat("LineThickness", lineThickness);
+ }
+ }
+
+ /**
+ * Sets minimum distance between lines drawn
+ * Primary lines are drawn at 2*lineDistance
+ * Secondary lines are drawn at lineDistance
+ * @param lineDistance
+ */
+ public void setLineDistance(float lineDistance) {
+ this.lineDistance = lineDistance;
+ if (material != null) {
+ material.setFloat("LineDistance", lineDistance);
+ }
+ }
+
+ /**
+ * Returns line color
+ * @return
+ */
+ public ColorRGBA getLineColor() {
+ return lineColor;
+ }
+
+ /**
+ * Returns paper background color
+ * @return
+ */
+ public ColorRGBA getPaperColor() {
+ return paperColor;
+ }
+
+ /**
+ * Returns current influence of image colors on lines
+ */
+ public float getColorInfluenceLine() {
+ return colorInfluenceLine;
+ }
+
+ /**
+ * Returns current influence of image colors on paper background
+ */
+ public float getColorInfluencePaper() {
+ return colorInfluencePaper;
+ }
+
+ /**
+ * Returns line/paper color ratio for blobs
+ */
+ public float getFillValue() {
+ return fillValue;
+ }
+
+ /**
+ * Returns the thickness of the lines drawn
+ */
+ public float getLineThickness() {
+ return lineThickness;
+ }
+
+ /**
+ * Returns minimum distance between lines
+ */
+ public float getLineDistance() {
+ return lineDistance;
+ }
+
+ /**
+ * Returns treshold for lines 1
+ */
+ public float getLuminance1() {
+ return luminance1;
+ }
+
+ /**
+ * Returns treshold for lines 2
+ */
+ public float getLuminance2() {
+ return luminance2;
+ }
+
+ /**
+ * Returns treshold for lines 3
+ */
+ public float getLuminance3() {
+ return luminance3;
+ }
+
+ /**
+ * Returns treshold for lines 4
+ */
+ public float getLuminance4() {
+ return luminance4;
+ }
+
+ /**
+ * Returns treshold for blobs
+ */
+ public float getLuminance5() {
+ return luminance5;
+ }
+} \ No newline at end of file
diff --git a/engine/src/core-effects/com/jme3/post/filters/DepthOfFieldFilter.java b/engine/src/core-effects/com/jme3/post/filters/DepthOfFieldFilter.java
new file mode 100644
index 0000000..55591c9
--- /dev/null
+++ b/engine/src/core-effects/com/jme3/post/filters/DepthOfFieldFilter.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2009-2010 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.post.filters;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.material.Material;
+import com.jme3.post.Filter;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+
+/**
+ * A post-processing filter that performs a depth range
+ * blur using a scaled convolution filter.
+ *
+ * @version $Revision: 779 $
+ * @author Paul Speed
+ */
+public class DepthOfFieldFilter extends Filter {
+
+ private float focusDistance = 50f;
+ private float focusRange = 10f;
+ private float blurScale = 1f;
+ // These values are set internally based on the
+ // viewport size.
+ private float xScale;
+ private float yScale;
+
+ /**
+ * Creates a DepthOfField filter
+ */
+ public DepthOfFieldFilter() {
+ super("Depth Of Field");
+ }
+
+ @Override
+ protected boolean isRequiresDepthTexture() {
+ return true;
+ }
+
+ @Override
+ protected Material getMaterial() {
+
+ return material;
+ }
+
+ @Override
+ protected void initFilter(AssetManager assets, RenderManager renderManager,
+ ViewPort vp, int w, int h) {
+ material = new Material(assets, "Common/MatDefs/Post/DepthOfField.j3md");
+ material.setFloat("FocusDistance", focusDistance);
+ material.setFloat("FocusRange", focusRange);
+
+
+ xScale = 1.0f / w;
+ yScale = 1.0f / h;
+
+ material.setFloat("XScale", blurScale * xScale);
+ material.setFloat("YScale", blurScale * yScale);
+ }
+
+ /**
+ * Sets the distance at which objects are purely in focus.
+ */
+ public void setFocusDistance(float f) {
+
+ this.focusDistance = f;
+ if (material != null) {
+ material.setFloat("FocusDistance", focusDistance);
+ }
+
+ }
+
+ /**
+ * returns the focus distance
+ * @return
+ */
+ public float getFocusDistance() {
+ return focusDistance;
+ }
+
+ /**
+ * Sets the range to either side of focusDistance where the
+ * objects go gradually out of focus. Less than focusDistance - focusRange
+ * and greater than focusDistance + focusRange, objects are maximally "blurred".
+ */
+ public void setFocusRange(float f) {
+ this.focusRange = f;
+ if (material != null) {
+ material.setFloat("FocusRange", focusRange);
+ }
+
+ }
+
+ /**
+ * returns the focus range
+ * @return
+ */
+ public float getFocusRange() {
+ return focusRange;
+ }
+
+ /**
+ * Sets the blur amount by scaling the convolution filter up or
+ * down. A value of 1 (the default) performs a sparse 5x5 evenly
+ * distribubted convolution at pixel level accuracy. Higher values skip
+ * more pixels, and so on until you are no longer blurring the image
+ * but simply hashing it.
+ *
+ * The sparse convolution is as follows:
+ *%MINIFYHTMLc3d0cd9fab65de6875a381fd3f83e1b338%*
+ * Where 'x' is the texel being modified. Setting blur scale higher
+ * than 1 spaces the samples out.
+ */
+ public void setBlurScale(float f) {
+ this.blurScale = f;
+ if (material != null) {
+ material.setFloat("XScale", blurScale * xScale);
+ material.setFloat("YScale", blurScale * yScale);
+ }
+ }
+
+ /**
+ * returns the blur scale
+ * @return
+ */
+ public float getBlurScale() {
+ return blurScale;
+ }
+}
diff --git a/engine/src/core-effects/com/jme3/post/filters/FXAAFilter.java b/engine/src/core-effects/com/jme3/post/filters/FXAAFilter.java
new file mode 100644
index 0000000..8ba3c16
--- /dev/null
+++ b/engine/src/core-effects/com/jme3/post/filters/FXAAFilter.java
@@ -0,0 +1,95 @@
+package com.jme3.post.filters;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.material.Material;
+import com.jme3.post.Filter;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+
+/**
+ * <a href="http://www.geeks3d.com/20110405/fxaa-fast-approximate-anti-aliasing-demo-glsl-opengl-test-radeon-geforce/3/" rel="nofollow">http://www.geeks3d.com/20110405/fxaa-fast-approximate-anti-aliasing-demo-glsl-<span class="domtooltips" title="OpenGL (Open Graphics Library) is a standard specification defining a cross-language, cross-platform API for writing applications that produce 2D and 3D computer graphics." id="domtooltipsspan11">opengl</span>-test-radeon-geforce/3/</a>
+ * <a href="http://developer.download.nvidia.com/assets/gamedev/files/sdk/11/FXAA_WhitePaper.pdf" rel="nofollow">http://developer.download.nvidia.com/assets/gamedev/files/sdk/11/FXAA_WhitePaper.pdf</a>
+ *
+ * @author Phate666 (adapted to jme3)
+ *
+ */
+public class FXAAFilter extends Filter {
+
+ private float subPixelShift = 1.0f / 4.0f;
+ private float vxOffset = 0.0f;
+ private float spanMax = 8.0f;
+ private float reduceMul = 1.0f / 8.0f;
+
+ public FXAAFilter() {
+ super("FXAAFilter");
+ }
+
+ @Override
+ protected void initFilter(AssetManager manager,
+ RenderManager renderManager, ViewPort vp, int w, int h) {
+ material = new Material(manager, "Common/MatDefs/Post/FXAA.j3md");
+ material.setFloat("SubPixelShift", subPixelShift);
+ material.setFloat("VxOffset", vxOffset);
+ material.setFloat("SpanMax", spanMax);
+ material.setFloat("ReduceMul", reduceMul);
+ }
+
+ @Override
+ protected Material getMaterial() {
+ return material;
+ }
+
+ public void setSpanMax(float spanMax) {
+ this.spanMax = spanMax;
+ if (material != null) {
+ material.setFloat("SpanMax", this.spanMax);
+ }
+ }
+
+ /**
+ * set to 0.0f for higher quality
+ *
+ * @param subPixelShift
+ */
+ public void setSubPixelShift(float subPixelShift) {
+ this.subPixelShift = subPixelShift;
+ if (material != null) {
+ material.setFloat("SubPixelShif", this.subPixelShift);
+ }
+ }
+
+ /**
+ * set to 0.0f for higher quality
+ *
+ * @param reduceMul
+ */
+ public void setReduceMul(float reduceMul) {
+ this.reduceMul = reduceMul;
+ if (material != null) {
+ material.setFloat("ReduceMul", this.reduceMul);
+ }
+ }
+
+ public void setVxOffset(float vxOffset) {
+ this.vxOffset = vxOffset;
+ if (material != null) {
+ material.setFloat("VxOffset", this.vxOffset);
+ }
+ }
+
+ public float getReduceMul() {
+ return reduceMul;
+ }
+
+ public float getSpanMax() {
+ return spanMax;
+ }
+
+ public float getSubPixelShift() {
+ return subPixelShift;
+ }
+
+ public float getVxOffset() {
+ return vxOffset;
+ }
+} \ No newline at end of file
diff --git a/engine/src/core-effects/com/jme3/post/filters/FadeFilter.java b/engine/src/core-effects/com/jme3/post/filters/FadeFilter.java
new file mode 100644
index 0000000..1fb2340
--- /dev/null
+++ b/engine/src/core-effects/com/jme3/post/filters/FadeFilter.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2009-2010 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.post.filters;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.export.InputCapsule;
+import com.jme3.export.JmeExporter;
+import com.jme3.export.JmeImporter;
+import com.jme3.export.OutputCapsule;
+import com.jme3.material.Material;
+import com.jme3.post.Filter;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+import java.io.IOException;
+
+/**
+ *
+ * Fade Filter allows you to make an animated fade effect on a scene.
+ * @author Rémy Bouquet aka Nehon
+ * implemented from boxjar implementation
+ * @see <a href="http://jmonkeyengine.org/groups/graphics/forum/topic/newbie-question-general-fade-inout-effect/#post-105559">http://jmonkeyengine.org/groups/graphics/forum/topic/newbie-question-general-fade-inout-effect/#post-105559</a>
+ */
+public class FadeFilter extends Filter {
+
+ private float value = 1;
+ private boolean playing = false;
+ private float direction = 1;
+ private float duration = 1;
+
+ /**
+ * Creates a FadeFilter
+ */
+ public FadeFilter() {
+ super("Fade In/Out");
+ }
+
+ /**
+ * Creates a FadeFilter with the given duration
+ * @param duration
+ */
+ public FadeFilter(float duration) {
+ this();
+ this.duration = duration;
+ }
+
+ @Override
+ protected Material getMaterial() {
+ material.setFloat("Value", value);
+ return material;
+ }
+
+ @Override
+ protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
+ material = new Material(manager, "Common/MatDefs/Post/Fade.j3md");
+ }
+
+ @Override
+ protected void preFrame(float tpf) {
+ if (playing) {
+ value += tpf * direction / duration;
+
+ if (direction > 0 && value > 1) {
+ value = 1;
+ playing = false;
+ setEnabled(false);
+ }
+ if (direction < 0 && value < 0) {
+ value = 0;
+ playing = false;
+ setEnabled(false);
+ }
+ }
+ }
+
+ /**
+ * returns the duration of the effect
+ * @return
+ */
+ public float getDuration() {
+ return duration;
+ }
+
+ /**
+ * Sets the duration of the filter default is 1 second
+ * @param duration
+ */
+ public void setDuration(float duration) {
+ this.duration = duration;
+ }
+
+ /**
+ * fades the scene in (black to scene)
+ */
+ public void fadeIn() {
+ setEnabled(true);
+ direction = 1;
+ playing = true;
+ }
+
+ /**
+ * fades the scene out (scene to black)
+ */
+ public void fadeOut() {
+ setEnabled(true);
+ direction = -1;
+ playing = true;
+
+ }
+
+ public void pause() {
+ playing = false;
+ }
+
+ @Override
+ public void write(JmeExporter ex) throws IOException {
+ super.write(ex);
+ OutputCapsule oc = ex.getCapsule(this);
+ oc.write(duration, "duration", 1);
+ }
+
+ @Override
+ public void read(JmeImporter im) throws IOException {
+ super.read(im);
+ InputCapsule ic = im.getCapsule(this);
+ duration = ic.readFloat("duration", 1);
+ }
+
+ /**
+ * return the current value of the fading
+ * can be used to chack if fade is complete (eg value=1)
+ * @return
+ */
+ public float getValue() {
+ return value;
+ }
+
+ /**
+ * sets the fade value
+ * can be used to force complete black or compete scene
+ * @param value
+ */
+ public void setValue(float value) {
+ this.value = value;
+ if (material != null) {
+ material.setFloat("Value", value);
+ }
+ }
+}
diff --git a/engine/src/core-effects/com/jme3/post/filters/FogFilter.java b/engine/src/core-effects/com/jme3/post/filters/FogFilter.java
new file mode 100644
index 0000000..c1df3b7
--- /dev/null
+++ b/engine/src/core-effects/com/jme3/post/filters/FogFilter.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.post.filters;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.export.InputCapsule;
+import com.jme3.export.JmeExporter;
+import com.jme3.export.JmeImporter;
+import com.jme3.export.OutputCapsule;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.post.Filter;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+import java.io.IOException;
+
+/**
+ * A filter to render a fog effect
+ * @author Rémy Bouquet aka Nehon
+ */
+public class FogFilter extends Filter {
+
+ private ColorRGBA fogColor = ColorRGBA.White.clone();
+ private float fogDensity = 0.7f;
+ private float fogDistance = 1000;
+
+ /**
+ * Creates a FogFilter
+ */
+ public FogFilter() {
+ super("FogFilter");
+ }
+
+ /**
+ * Create a fog filter
+ * @param fogColor the color of the fog (default is white)
+ * @param fogDensity the density of the fog (default is 0.7)
+ * @param fogDistance the distance of the fog (default is 1000)
+ */
+ public FogFilter(ColorRGBA fogColor, float fogDensity, float fogDistance) {
+ this();
+ this.fogColor = fogColor;
+ this.fogDensity = fogDensity;
+ this.fogDistance = fogDistance;
+ }
+
+ @Override
+ protected boolean isRequiresDepthTexture() {
+ return true;
+ }
+
+ @Override
+ protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
+ material = new Material(manager, "Common/MatDefs/Post/Fog.j3md");
+ material.setColor("FogColor", fogColor);
+ material.setFloat("FogDensity", fogDensity);
+ material.setFloat("FogDistance", fogDistance);
+ }
+
+ @Override
+ protected Material getMaterial() {
+
+ return material;
+ }
+
+
+ /**
+ * returns the fog color
+ * @return
+ */
+ public ColorRGBA getFogColor() {
+ return fogColor;
+ }
+
+ /**
+ * Sets the color of the fog
+ * @param fogColor
+ */
+ public void setFogColor(ColorRGBA fogColor) {
+ if (material != null) {
+ material.setColor("FogColor", fogColor);
+ }
+ this.fogColor = fogColor;
+ }
+
+ /**
+ * returns the fog density
+ * @return
+ */
+ public float getFogDensity() {
+ return fogDensity;
+ }
+
+ /**
+ * Sets the density of the fog, a high value gives a thick fog
+ * @param fogDensity
+ */
+ public void setFogDensity(float fogDensity) {
+ if (material != null) {
+ material.setFloat("FogDensity", fogDensity);
+ }
+ this.fogDensity = fogDensity;
+ }
+
+ /**
+ * returns the fog distance
+ * @return
+ */
+ public float getFogDistance() {
+ return fogDistance;
+ }
+
+ /**
+ * the distance of the fog. the higer the value the distant the fog looks
+ * @param fogDistance
+ */
+ public void setFogDistance(float fogDistance) {
+ if (material != null) {
+ material.setFloat("FogDistance", fogDistance);
+ }
+ this.fogDistance = fogDistance;
+ }
+
+ @Override
+ public void write(JmeExporter ex) throws IOException {
+ super.write(ex);
+ OutputCapsule oc = ex.getCapsule(this);
+ oc.write(fogColor, "fogColor", ColorRGBA.White.clone());
+ oc.write(fogDensity, "fogDensity", 0.7f);
+ oc.write(fogDistance, "fogDistance", 1000);
+ }
+
+ @Override
+ public void read(JmeImporter im) throws IOException {
+ super.read(im);
+ InputCapsule ic = im.getCapsule(this);
+ fogColor = (ColorRGBA) ic.readSavable("fogColor", ColorRGBA.White.clone());
+ fogDensity = ic.readFloat("fogDensity", 0.7f);
+ fogDistance = ic.readFloat("fogDistance", 1000);
+ }
+
+
+}
diff --git a/engine/src/core-effects/com/jme3/post/filters/GammaCorrectionFilter.java b/engine/src/core-effects/com/jme3/post/filters/GammaCorrectionFilter.java
new file mode 100644
index 0000000..9e283ca
--- /dev/null
+++ b/engine/src/core-effects/com/jme3/post/filters/GammaCorrectionFilter.java
@@ -0,0 +1,78 @@
+package com.jme3.post.filters;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.material.Material;
+import com.jme3.post.Filter;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+
+/**
+ *
+ * @author Phate666
+ * @version 1.0 initial version
+ * @version 1.1 added luma
+ */
+public class GammaCorrectionFilter extends Filter
+{
+ private float gamma = 2.0f;
+ private boolean computeLuma = false;
+
+ public GammaCorrectionFilter()
+ {
+ super("GammaCorrectionFilter");
+ }
+
+ public GammaCorrectionFilter(float gamma)
+ {
+ this();
+ this.setGamma(gamma);
+ }
+
+ @Override
+ protected Material getMaterial()
+ {
+ return material;
+ }
+
+ @Override
+ protected void initFilter(AssetManager manager,
+ RenderManager renderManager, ViewPort vp, int w, int h)
+ {
+ material = new Material(manager,
+ "Common/MatDefs/Post/GammaCorrection.j3md");
+ material.setFloat("gamma", gamma);
+ material.setBoolean("computeLuma", computeLuma);
+ }
+
+ public float getGamma()
+ {
+ return gamma;
+ }
+
+ /**
+ * set to 0.0 to disable gamma correction
+ * @param gamma
+ */
+ public void setGamma(float gamma)
+ {
+ if (material != null)
+ {
+ material.setFloat("gamma", gamma);
+ }
+ this.gamma = gamma;
+ }
+
+ public boolean isComputeLuma()
+ {
+ return computeLuma;
+ }
+
+ public void setComputeLuma(boolean computeLuma)
+ {
+ if (material != null)
+ {
+ material.setBoolean("computeLuma", computeLuma);
+ }
+ this.computeLuma = computeLuma;
+ }
+}
diff --git a/engine/src/core-effects/com/jme3/post/filters/LightScatteringFilter.java b/engine/src/core-effects/com/jme3/post/filters/LightScatteringFilter.java
new file mode 100644
index 0000000..953f10a
--- /dev/null
+++ b/engine/src/core-effects/com/jme3/post/filters/LightScatteringFilter.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2009-2010 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.post.filters;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.export.InputCapsule;
+import com.jme3.export.JmeExporter;
+import com.jme3.export.JmeImporter;
+import com.jme3.export.OutputCapsule;
+import com.jme3.material.Material;
+import com.jme3.math.Vector3f;
+import com.jme3.post.Filter;
+import com.jme3.renderer.Camera;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+import java.io.IOException;
+
+/**
+ * LightScattering filters creates rays comming from a light sources
+ * This is often reffered as god rays.
+ *
+ * @author Rémy Bouquet aka Nehon
+ */
+public class LightScatteringFilter extends Filter {
+
+ private Vector3f lightPosition;
+ private Vector3f screenLightPos = new Vector3f();
+ private int nbSamples = 50;
+ private float blurStart = 0.02f;
+ private float blurWidth = 0.9f;
+ private float lightDensity = 1.4f;
+ private boolean adaptative = true;
+ Vector3f viewLightPos = new Vector3f();
+ private boolean display = true;
+ private float innerLightDensity;
+
+ /**
+ * creates a lightScaterring filter
+ */
+ public LightScatteringFilter() {
+ super("Light Scattering");
+ }
+
+ /**
+ * Creates a lightScatteringFilter
+ * @param lightPosition
+ */
+ public LightScatteringFilter(Vector3f lightPosition) {
+ this();
+ this.lightPosition = lightPosition;
+ }
+
+ @Override
+ protected boolean isRequiresDepthTexture() {
+ return true;
+ }
+
+ @Override
+ protected Material getMaterial() {
+ material.setVector3("LightPosition", screenLightPos);
+ material.setInt("NbSamples", nbSamples);
+ material.setFloat("BlurStart", blurStart);
+ material.setFloat("BlurWidth", blurWidth);
+ material.setFloat("LightDensity", innerLightDensity);
+ material.setBoolean("Display", display);
+ return material;
+ }
+
+ @Override
+ protected void postQueue(RenderManager renderManager, ViewPort viewPort) {
+ getClipCoordinates(lightPosition, screenLightPos, viewPort.getCamera());
+ // screenLightPos.x = screenLightPos.x / viewPort.getCamera().getWidth();
+ // screenLightPos.y = screenLightPos.y / viewPort.getCamera().getHeight();
+
+ viewPort.getCamera().getViewMatrix().mult(lightPosition, viewLightPos);
+ //System.err.println("viewLightPos "+viewLightPos);
+ display = screenLightPos.x < 1.6f && screenLightPos.x > -0.6f && screenLightPos.y < 1.6f && screenLightPos.y > -0.6f && viewLightPos.z < 0;
+//System.err.println("camdir "+viewPort.getCamera().getDirection());
+//System.err.println("lightPos "+lightPosition);
+//System.err.println("screenLightPos "+screenLightPos);
+ if (adaptative) {
+ innerLightDensity = Math.max(lightDensity - Math.max(screenLightPos.x, screenLightPos.y), 0.0f);
+ } else {
+ innerLightDensity = lightDensity;
+ }
+ }
+
+ private Vector3f getClipCoordinates(Vector3f worldPosition, Vector3f store, Camera cam) {
+
+ float w = cam.getViewProjectionMatrix().multProj(worldPosition, store);
+ store.divideLocal(w);
+
+ store.x = ((store.x + 1f) * (cam.getViewPortRight() - cam.getViewPortLeft()) / 2f + cam.getViewPortLeft());
+ store.y = ((store.y + 1f) * (cam.getViewPortTop() - cam.getViewPortBottom()) / 2f + cam.getViewPortBottom());
+ store.z = (store.z + 1f) / 2f;
+
+ return store;
+ }
+
+ @Override
+ protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
+ material = new Material(manager, "Common/MatDefs/Post/LightScattering.j3md");
+ }
+
+ /**
+ * returns the blur start of the scattering
+ * see {@link setBlurStart(float blurStart)}
+ * @return
+ */
+ public float getBlurStart() {
+ return blurStart;
+ }
+
+ /**
+ * sets the blur start<br>
+ * at which distance from the light source the effect starts default is 0.02
+ * @param blurStart
+ */
+ public void setBlurStart(float blurStart) {
+ this.blurStart = blurStart;
+ }
+
+ /**
+ * returns the blur width<br>
+ * see {@link setBlurWidth(float blurWidth)}
+ * @return
+ */
+ public float getBlurWidth() {
+ return blurWidth;
+ }
+
+ /**
+ * sets the blur width default is 0.9
+ * @param blurWidth
+ */
+ public void setBlurWidth(float blurWidth) {
+ this.blurWidth = blurWidth;
+ }
+
+ /**
+ * retiurns the light density<br>
+ * see {@link setLightDensity(float lightDensity)}
+ *
+ * @return
+ */
+ public float getLightDensity() {
+ return lightDensity;
+ }
+
+ /**
+ * sets how much the effect is visible over the rendered scene default is 1.4
+ * @param lightDensity
+ */
+ public void setLightDensity(float lightDensity) {
+ this.lightDensity = lightDensity;
+ }
+
+ /**
+ * returns the light position
+ * @return
+ */
+ public Vector3f getLightPosition() {
+ return lightPosition;
+ }
+
+ /**
+ * sets the light position
+ * @param lightPosition
+ */
+ public void setLightPosition(Vector3f lightPosition) {
+ this.lightPosition = lightPosition;
+ }
+
+ /**
+ * returns the nmber of samples for the radial blur
+ * @return
+ */
+ public int getNbSamples() {
+ return nbSamples;
+ }
+
+ /**
+ * sets the number of samples for the radial blur default is 50
+ * the higher the value the higher the quality, but the slower the performances.
+ * @param nbSamples
+ */
+ public void setNbSamples(int nbSamples) {
+ this.nbSamples = nbSamples;
+ }
+
+ @Override
+ public void write(JmeExporter ex) throws IOException {
+ super.write(ex);
+ OutputCapsule oc = ex.getCapsule(this);
+ oc.write(lightPosition, "lightPosition", Vector3f.ZERO);
+ oc.write(nbSamples, "nbSamples", 50);
+ oc.write(blurStart, "blurStart", 0.02f);
+ oc.write(blurWidth, "blurWidth", 0.9f);
+ oc.write(lightDensity, "lightDensity", 1.4f);
+ oc.write(adaptative, "adaptative", true);
+ }
+
+ @Override
+ public void read(JmeImporter im) throws IOException {
+ super.read(im);
+ InputCapsule ic = im.getCapsule(this);
+ lightPosition = (Vector3f) ic.readSavable("lightPosition", Vector3f.ZERO);
+ nbSamples = ic.readInt("nbSamples", 50);
+ blurStart = ic.readFloat("blurStart", 0.02f);
+ blurWidth = ic.readFloat("blurWidth", 0.9f);
+ lightDensity = ic.readFloat("lightDensity", 1.4f);
+ adaptative = ic.readBoolean("adaptative", true);
+ }
+}
diff --git a/engine/src/core-effects/com/jme3/post/filters/PosterizationFilter.java b/engine/src/core-effects/com/jme3/post/filters/PosterizationFilter.java
new file mode 100644
index 0000000..c980eda
--- /dev/null
+++ b/engine/src/core-effects/com/jme3/post/filters/PosterizationFilter.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2009-2010 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.post.filters;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.material.Material;
+import com.jme3.post.Filter;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+
+/**
+ * A Post Processing filter to change colors appear with sharp edges as if the
+ * available amount of colors available was not enough to draw the true image.
+ * Possibly useful in cartoon styled games. Use the strength variable to lessen
+ * influence of this filter on the total result. Values from 0.2 to 0.7 appear
+ * to give nice results.
+ *
+ * Based on an article from Geeks3D:
+ * <a href="http://www.geeks3d.com/20091027/shader-library-posterization-post-processing-effect-glsl/" rel="nofollow">http://www.geeks3d.com/20091027/shader-library-posterization-post-processing-effect-glsl/</a>
+ *
+ * @author: Roy Straver a.k.a. Baal Garnaal
+ */
+public class PosterizationFilter extends Filter {
+
+ private int numColors = 8;
+ private float gamma = 0.6f;
+ private float strength = 1.0f;
+
+ /**
+ * Creates a posterization Filter
+ */
+ public PosterizationFilter() {
+ super("PosterizationFilter");
+ }
+
+ /**
+ * Creates a posterization Filter with the given number of colors
+ * @param numColors
+ */
+ public PosterizationFilter(int numColors) {
+ this();
+ this.numColors = numColors;
+ }
+
+ /**
+ * Creates a posterization Filter with the given number of colors and gamma
+ * @param numColors
+ * @param gamma
+ */
+ public PosterizationFilter(int numColors, float gamma) {
+ this(numColors);
+ this.gamma = gamma;
+ }
+
+ @Override
+ protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
+ material = new Material(manager, "Common/MatDefs/Post/Posterization.j3md");
+ material.setInt("NumColors", numColors);
+ material.setFloat("Gamma", gamma);
+ material.setFloat("Strength", strength);
+ }
+
+ @Override
+ protected Material getMaterial() {
+ return material;
+ }
+
+ /**
+ * Sets number of color levels used to draw the screen
+ */
+ public void setNumColors(int numColors) {
+ this.numColors = numColors;
+ if (material != null) {
+ material.setInt("NumColors", numColors);
+ }
+ }
+
+ /**
+ * Sets gamma level used to enhange visual quality
+ */
+ public void setGamma(float gamma) {
+ this.gamma = gamma;
+ if (material != null) {
+ material.setFloat("Gamma", gamma);
+ }
+ }
+
+ /**
+ * Sets urrent strength value, i.e. influence on final image
+ */
+ public void setStrength(float strength) {
+ this.strength = strength;
+ if (material != null) {
+ material.setFloat("Strength", strength);
+ }
+ }
+
+ /**
+ * Returns number of color levels used
+ */
+ public int getNumColors() {
+ return numColors;
+ }
+
+ /**
+ * Returns current gamma value
+ */
+ public float getGamma() {
+ return gamma;
+ }
+
+ /**
+ * Returns current strength value, i.e. influence on final image
+ */
+ public float getStrength() {
+ return strength;
+ }
+} \ No newline at end of file
diff --git a/engine/src/core-effects/com/jme3/post/filters/RadialBlurFilter.java b/engine/src/core-effects/com/jme3/post/filters/RadialBlurFilter.java
new file mode 100644
index 0000000..0bcae5f
--- /dev/null
+++ b/engine/src/core-effects/com/jme3/post/filters/RadialBlurFilter.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.post.filters;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.export.InputCapsule;
+import com.jme3.export.JmeExporter;
+import com.jme3.export.JmeImporter;
+import com.jme3.export.OutputCapsule;
+import com.jme3.material.Material;
+import com.jme3.post.Filter;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+import com.jme3.shader.VarType;
+import java.io.IOException;
+
+/**
+ * Radially blurs the scene from the center of it
+ * @author Rémy Bouquet aka Nehon
+ */
+public class RadialBlurFilter extends Filter {
+
+ private float sampleDist = 1.0f;
+ private float sampleStrength = 2.2f;
+ private float[] samples = {-0.08f, -0.05f, -0.03f, -0.02f, -0.01f, 0.01f, 0.02f, 0.03f, 0.05f, 0.08f};
+
+ /**
+ * Creates a RadialBlurFilter
+ */
+ public RadialBlurFilter() {
+ super("Radial blur");
+ }
+
+ /**
+ * Creates a RadialBlurFilter
+ * @param sampleDist the distance between samples
+ * @param sampleStrength the strenght of each sample
+ */
+ public RadialBlurFilter(float sampleDist, float sampleStrength) {
+ this();
+ this.sampleDist = sampleDist;
+ this.sampleStrength = sampleStrength;
+ }
+
+ @Override
+ protected Material getMaterial() {
+
+ material.setFloat("SampleDist", sampleDist);
+ material.setFloat("SampleStrength", sampleStrength);
+ material.setParam("Samples", VarType.FloatArray, samples);
+
+ return material;
+ }
+
+ /**
+ * return the sample distance
+ * @return
+ */
+ public float getSampleDistance() {
+ return sampleDist;
+ }
+
+ /**
+ * sets the samples distances default is 1
+ * @param sampleDist
+ */
+ public void setSampleDistance(float sampleDist) {
+ this.sampleDist = sampleDist;
+ }
+
+ /**
+ *
+ * @return
+ * @deprecated use {@link #getSampleDistance()}
+ */
+ @Deprecated
+ public float getSampleDist() {
+ return sampleDist;
+ }
+
+ /**
+ *
+ * @param sampleDist
+ * @deprecated use {@link #setSampleDistance(float sampleDist)}
+ */
+ @Deprecated
+ public void setSampleDist(float sampleDist) {
+ this.sampleDist = sampleDist;
+ }
+
+ /**
+ * Returns the sample Strength
+ * @return
+ */
+ public float getSampleStrength() {
+ return sampleStrength;
+ }
+
+ /**
+ * sets the sample streanght default is 2.2
+ * @param sampleStrength
+ */
+ public void setSampleStrength(float sampleStrength) {
+ this.sampleStrength = sampleStrength;
+ }
+
+ @Override
+ protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
+ material = new Material(manager, "Common/MatDefs/Blur/RadialBlur.j3md");
+ }
+
+ @Override
+ public void write(JmeExporter ex) throws IOException {
+ super.write(ex);
+ OutputCapsule oc = ex.getCapsule(this);
+ oc.write(sampleDist, "sampleDist", 1.0f);
+ oc.write(sampleStrength, "sampleStrength", 2.2f);
+ }
+
+ @Override
+ public void read(JmeImporter im) throws IOException {
+ super.read(im);
+ InputCapsule ic = im.getCapsule(this);
+ sampleDist = ic.readFloat("sampleDist", 1.0f);
+ sampleStrength = ic.readFloat("sampleStrength", 2.2f);
+ }
+}
diff --git a/engine/src/core-effects/com/jme3/post/filters/TranslucentBucketFilter.java b/engine/src/core-effects/com/jme3/post/filters/TranslucentBucketFilter.java
new file mode 100644
index 0000000..47be413
--- /dev/null
+++ b/engine/src/core-effects/com/jme3/post/filters/TranslucentBucketFilter.java
@@ -0,0 +1,80 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.post.filters;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.post.Filter;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.Renderer;
+import com.jme3.renderer.ViewPort;
+import com.jme3.renderer.queue.RenderQueue;
+import com.jme3.texture.FrameBuffer;
+import com.jme3.texture.Texture2D;
+
+/**
+ * A filter to handle translucent objects when rendering a scene with filters that uses depth like WaterFilter and SSAOFilter
+ * just create a TranslucentBucketFilter and add it to the Filter list of a FilterPostPorcessor
+ * @author Nehon
+ */
+public final class TranslucentBucketFilter extends Filter {
+
+ private RenderManager renderManager;
+
+ @Override
+ protected void initFilter(AssetManager manager, RenderManager rm, ViewPort vp, int w, int h) {
+ this.renderManager = rm;
+ material = new Material(manager, "Common/MatDefs/Post/Overlay.j3md");
+ material.setColor("Color", ColorRGBA.White);
+ Texture2D tex = processor.getFilterTexture();
+ material.setTexture("Texture", tex);
+ if (tex.getImage().getMultiSamples() > 1) {
+ material.setInt("NumSamples", tex.getImage().getMultiSamples());
+ } else {
+ material.clearParam("NumSamples");
+ }
+ renderManager.setHandleTranslucentBucket(false);
+ }
+
+ /**
+ * Override this method and return false if your Filter does not need the scene texture
+ * @return
+ */
+ @Override
+ protected boolean isRequiresSceneTexture() {
+ return false;
+ }
+
+ @Override
+ protected void postFrame(RenderManager renderManager, ViewPort viewPort, FrameBuffer prevFilterBuffer, FrameBuffer sceneBuffer) {
+ renderManager.setCamera(viewPort.getCamera(), false);
+ if (prevFilterBuffer != sceneBuffer) {
+ renderManager.getRenderer().copyFrameBuffer(prevFilterBuffer, sceneBuffer, false);
+ }
+ renderManager.getRenderer().setFrameBuffer(sceneBuffer);
+ viewPort.getQueue().renderQueue(RenderQueue.Bucket.Translucent, renderManager, viewPort.getCamera());
+ }
+
+ @Override
+ protected void cleanUpFilter(Renderer r) {
+ if (renderManager != null) {
+ renderManager.setHandleTranslucentBucket(true);
+ }
+ }
+
+ @Override
+ protected Material getMaterial() {
+ return material;
+ }
+
+ @Override
+ public void setEnabled(boolean enabled) {
+ super.setEnabled(enabled);
+ if (renderManager != null) {
+ renderManager.setHandleTranslucentBucket(!enabled);
+ }
+ }
+}
diff --git a/engine/src/core-effects/com/jme3/post/ssao/SSAOFilter.java b/engine/src/core-effects/com/jme3/post/ssao/SSAOFilter.java
new file mode 100644
index 0000000..cb0c037
--- /dev/null
+++ b/engine/src/core-effects/com/jme3/post/ssao/SSAOFilter.java
@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.post.ssao;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.export.InputCapsule;
+import com.jme3.export.JmeExporter;
+import com.jme3.export.JmeImporter;
+import com.jme3.export.OutputCapsule;
+import com.jme3.material.Material;
+import com.jme3.math.Vector2f;
+import com.jme3.math.Vector3f;
+import com.jme3.post.Filter;
+import com.jme3.post.Filter.Pass;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.Renderer;
+import com.jme3.renderer.ViewPort;
+import com.jme3.shader.VarType;
+import com.jme3.texture.Image.Format;
+import com.jme3.texture.Texture;
+import java.io.IOException;
+import java.util.ArrayList;
+
+/**
+ * SSAO stands for screen space ambient occlusion
+ * It's a technique that fake ambient lighting by computing shadows that near by objects would casts on each others
+ * under the effect of an ambient light
+ * more info on this in this blog post <a href="http://jmonkeyengine.org/2010/08/16/screen-space-ambient-occlusion-for-jmonkeyengine-3-0/">http://jmonkeyengine.org/2010/08/16/screen-space-ambient-occlusion-for-jmonkeyengine-3-0/</a>
+ *
+ * @author Rémy Bouquet aka Nehon
+ */
+public class SSAOFilter extends Filter {
+
+ private Pass normalPass;
+ private Vector3f frustumCorner;
+ private Vector2f frustumNearFar;
+ private Vector2f[] samples = {new Vector2f(1.0f, 0.0f), new Vector2f(-1.0f, 0.0f), new Vector2f(0.0f, 1.0f), new Vector2f(0.0f, -1.0f)};
+ private float sampleRadius = 5.1f;
+ private float intensity = 1.5f;
+ private float scale = 0.2f;
+ private float bias = 0.1f;
+ private boolean useOnlyAo = false;
+ private boolean useAo = true;
+ private Material ssaoMat;
+ private Pass ssaoPass;
+// private Material downSampleMat;
+// private Pass downSamplePass;
+ private float downSampleFactor = 1f;
+
+ /**
+ * Create a Screen Space Ambient Occlusion Filter
+ */
+ public SSAOFilter() {
+ super("SSAOFilter");
+ }
+
+ /**
+ * Create a Screen Space Ambient Occlusion Filter
+ * @param sampleRadius The radius of the area where random samples will be picked. default 5.1f
+ * @param intensity intensity of the resulting AO. default 1.2f
+ * @param scale distance between occluders and occludee. default 0.2f
+ * @param bias the width of the occlusion cone considered by the occludee. default 0.1f
+ */
+ public SSAOFilter(float sampleRadius, float intensity, float scale, float bias) {
+ this();
+ this.sampleRadius = sampleRadius;
+ this.intensity = intensity;
+ this.scale = scale;
+ this.bias = bias;
+ }
+
+ @Override
+ protected boolean isRequiresDepthTexture() {
+ return true;
+ }
+
+ @Override
+ protected void postQueue(RenderManager renderManager, ViewPort viewPort) {
+ Renderer r = renderManager.getRenderer();
+ r.setFrameBuffer(normalPass.getRenderFrameBuffer());
+ renderManager.getRenderer().clearBuffers(true, true, true);
+ renderManager.setForcedTechnique("PreNormalPass");
+ renderManager.renderViewPortQueues(viewPort, false);
+ renderManager.setForcedTechnique(null);
+ renderManager.getRenderer().setFrameBuffer(viewPort.getOutputFrameBuffer());
+ }
+
+ @Override
+ protected Material getMaterial() {
+ return material;
+ }
+
+ @Override
+ protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
+ int screenWidth = w;
+ int screenHeight = h;
+ postRenderPasses = new ArrayList<Pass>();
+
+ normalPass = new Pass();
+ normalPass.init(renderManager.getRenderer(), (int) (screenWidth / downSampleFactor), (int) (screenHeight / downSampleFactor), Format.RGBA8, Format.Depth);
+
+
+ frustumNearFar = new Vector2f();
+
+ float farY = (vp.getCamera().getFrustumTop() / vp.getCamera().getFrustumNear()) * vp.getCamera().getFrustumFar();
+ float farX = farY * ((float) screenWidth / (float) screenHeight);
+ frustumCorner = new Vector3f(farX, farY, vp.getCamera().getFrustumFar());
+ frustumNearFar.x = vp.getCamera().getFrustumNear();
+ frustumNearFar.y = vp.getCamera().getFrustumFar();
+
+
+
+
+
+ //ssao Pass
+ ssaoMat = new Material(manager, "Common/MatDefs/SSAO/ssao.j3md");
+ ssaoMat.setTexture("Normals", normalPass.getRenderedTexture());
+ Texture random = manager.loadTexture("Common/MatDefs/SSAO/Textures/random.png");
+ random.setWrap(Texture.WrapMode.Repeat);
+ ssaoMat.setTexture("RandomMap", random);
+
+ ssaoPass = new Pass() {
+
+ @Override
+ public boolean requiresDepthAsTexture() {
+ return true;
+ }
+ };
+
+ ssaoPass.init(renderManager.getRenderer(), (int) (screenWidth / downSampleFactor), (int) (screenHeight / downSampleFactor), Format.RGBA8, Format.Depth, 1, ssaoMat);
+ ssaoPass.getRenderedTexture().setMinFilter(Texture.MinFilter.Trilinear);
+ ssaoPass.getRenderedTexture().setMagFilter(Texture.MagFilter.Bilinear);
+ postRenderPasses.add(ssaoPass);
+ material = new Material(manager, "Common/MatDefs/SSAO/ssaoBlur.j3md");
+ material.setTexture("SSAOMap", ssaoPass.getRenderedTexture());
+
+ ssaoMat.setVector3("FrustumCorner", frustumCorner);
+ ssaoMat.setFloat("SampleRadius", sampleRadius);
+ ssaoMat.setFloat("Intensity", intensity);
+ ssaoMat.setFloat("Scale", scale);
+ ssaoMat.setFloat("Bias", bias);
+ material.setBoolean("UseAo", useAo);
+ material.setBoolean("UseOnlyAo", useOnlyAo);
+ ssaoMat.setVector2("FrustumNearFar", frustumNearFar);
+ material.setVector2("FrustumNearFar", frustumNearFar);
+ ssaoMat.setParam("Samples", VarType.Vector2Array, samples);
+
+ float xScale = 1.0f / w;
+ float yScale = 1.0f / h;
+
+ float blurScale = 2f;
+ material.setFloat("XScale", blurScale * xScale);
+ material.setFloat("YScale", blurScale * yScale);
+
+ }
+
+ /**
+ * Return the bias<br>
+ * see {@link #setBias(float bias)}
+ * @return
+ */
+ public float getBias() {
+ return bias;
+ }
+
+ /**
+ * Sets the the width of the occlusion cone considered by the occludee default is 0.1f
+ * @param bias
+ */
+ public void setBias(float bias) {
+ this.bias = bias;
+ if (ssaoMat != null) {
+ ssaoMat.setFloat("Bias", bias);
+ }
+ }
+
+ /**
+ * returns the ambient occlusion intensity
+ * @return
+ */
+ public float getIntensity() {
+ return intensity;
+ }
+
+ /**
+ * Sets the Ambient occlusion intensity default is 1.2f
+ * @param intensity
+ */
+ public void setIntensity(float intensity) {
+ this.intensity = intensity;
+ if (ssaoMat != null) {
+ ssaoMat.setFloat("Intensity", intensity);
+ }
+
+ }
+
+ /**
+ * returns the sample radius<br>
+ * see {link setSampleRadius(float sampleRadius)}
+ * @return
+ */
+ public float getSampleRadius() {
+ return sampleRadius;
+ }
+
+ /**
+ * Sets the radius of the area where random samples will be picked dafault 5.1f
+ * @param sampleRadius
+ */
+ public void setSampleRadius(float sampleRadius) {
+ this.sampleRadius = sampleRadius;
+ if (ssaoMat != null) {
+ ssaoMat.setFloat("SampleRadius", sampleRadius);
+ }
+
+ }
+
+ /**
+ * returns the scale<br>
+ * see {@link #setScale(float scale)}
+ * @return
+ */
+ public float getScale() {
+ return scale;
+ }
+
+ /**
+ *
+ * Returns the distance between occluders and occludee. default 0.2f
+ * @param scale
+ */
+ public void setScale(float scale) {
+ this.scale = scale;
+ if (ssaoMat != null) {
+ ssaoMat.setFloat("Scale", scale);
+ }
+ }
+
+ /**
+ * debugging only , will be removed
+ * @return
+ */
+ public boolean isUseAo() {
+ return useAo;
+ }
+
+ /**
+ * debugging only , will be removed
+ */
+ public void setUseAo(boolean useAo) {
+ this.useAo = useAo;
+ if (material != null) {
+ material.setBoolean("UseAo", useAo);
+ }
+
+ }
+
+ /**
+ * debugging only , will be removed
+ * @return
+ */
+ public boolean isUseOnlyAo() {
+ return useOnlyAo;
+ }
+
+ /**
+ * debugging only , will be removed
+ */
+ public void setUseOnlyAo(boolean useOnlyAo) {
+ this.useOnlyAo = useOnlyAo;
+ if (material != null) {
+ material.setBoolean("UseOnlyAo", useOnlyAo);
+ }
+ }
+
+ @Override
+ public void write(JmeExporter ex) throws IOException {
+ super.write(ex);
+ OutputCapsule oc = ex.getCapsule(this);
+ oc.write(sampleRadius, "sampleRadius", 5.1f);
+ oc.write(intensity, "intensity", 1.5f);
+ oc.write(scale, "scale", 0.2f);
+ oc.write(bias, "bias", 0.1f);
+ }
+
+ @Override
+ public void read(JmeImporter im) throws IOException {
+ super.read(im);
+ InputCapsule ic = im.getCapsule(this);
+ sampleRadius = ic.readFloat("sampleRadius", 5.1f);
+ intensity = ic.readFloat("intensity", 1.5f);
+ scale = ic.readFloat("scale", 0.2f);
+ bias = ic.readFloat("bias", 0.1f);
+ }
+}
diff --git a/engine/src/core-effects/com/jme3/water/ReflectionProcessor.java b/engine/src/core-effects/com/jme3/water/ReflectionProcessor.java
new file mode 100644
index 0000000..9a14df8
--- /dev/null
+++ b/engine/src/core-effects/com/jme3/water/ReflectionProcessor.java
@@ -0,0 +1,125 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.water;
+
+import com.jme3.math.Plane;
+import com.jme3.post.SceneProcessor;
+import com.jme3.renderer.Camera;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+import com.jme3.renderer.queue.RenderQueue;
+import com.jme3.texture.FrameBuffer;
+
+/**
+ * Reflection Processor
+ * Used to render the reflected scene in an off view port
+ */
+public class ReflectionProcessor implements SceneProcessor {
+
+ private RenderManager rm;
+ private ViewPort vp;
+ private Camera reflectionCam;
+ private FrameBuffer reflectionBuffer;
+ private Plane reflectionClipPlane;
+
+ /**
+ * Creates a ReflectionProcessor
+ * @param reflectionCam the cam to use for reflection
+ * @param reflectionBuffer the FrameBuffer to render to
+ * @param reflectionClipPlane the clipping plane
+ */
+ public ReflectionProcessor(Camera reflectionCam, FrameBuffer reflectionBuffer, Plane reflectionClipPlane) {
+ this.reflectionCam = reflectionCam;
+ this.reflectionBuffer = reflectionBuffer;
+ this.reflectionClipPlane = reflectionClipPlane;
+ }
+
+ public void initialize(RenderManager rm, ViewPort vp) {
+ this.rm = rm;
+ this.vp = vp;
+ }
+
+ public void reshape(ViewPort vp, int w, int h) {
+ }
+
+ public boolean isInitialized() {
+ return rm != null;
+ }
+
+ public void preFrame(float tpf) {
+ }
+
+ public void postQueue(RenderQueue rq) {
+ //we need special treatement for the sky because it must not be clipped
+ rm.getRenderer().setFrameBuffer(reflectionBuffer);
+ reflectionCam.setProjectionMatrix(null);
+ rm.setCamera(reflectionCam, false);
+ rm.getRenderer().clearBuffers(true, true, true);
+ //Rendering the sky whithout clipping
+ rm.getRenderer().setDepthRange(1, 1);
+ vp.getQueue().renderQueue(RenderQueue.Bucket.Sky, rm, reflectionCam, true);
+ rm.getRenderer().setDepthRange(0, 1);
+ //setting the clip plane to the cam
+ reflectionCam.setClipPlane(reflectionClipPlane, Plane.Side.Positive);//,1
+ rm.setCamera(reflectionCam, false);
+
+ }
+
+ public void postFrame(FrameBuffer out) {
+ }
+
+ public void cleanup() {
+ }
+
+ /**
+ * Internal use only<br>
+ * returns the frame buffer
+ * @return
+ */
+ public FrameBuffer getReflectionBuffer() {
+ return reflectionBuffer;
+ }
+
+ /**
+ * Internal use only<br>
+ * sets the frame buffer
+ * @param reflectionBuffer
+ */
+ public void setReflectionBuffer(FrameBuffer reflectionBuffer) {
+ this.reflectionBuffer = reflectionBuffer;
+ }
+
+ /**
+ * returns the reflection cam
+ * @return
+ */
+ public Camera getReflectionCam() {
+ return reflectionCam;
+ }
+
+ /**
+ * sets the reflection cam
+ * @param reflectionCam
+ */
+ public void setReflectionCam(Camera reflectionCam) {
+ this.reflectionCam = reflectionCam;
+ }
+
+ /**
+ * returns the reflection clip plane
+ * @return
+ */
+ public Plane getReflectionClipPlane() {
+ return reflectionClipPlane;
+ }
+
+ /**
+ * Sets the reflection clip plane
+ * @param reflectionClipPlane
+ */
+ public void setReflectionClipPlane(Plane reflectionClipPlane) {
+ this.reflectionClipPlane = reflectionClipPlane;
+ }
+}
diff --git a/engine/src/core-effects/com/jme3/water/SimpleWaterProcessor.java b/engine/src/core-effects/com/jme3/water/SimpleWaterProcessor.java
new file mode 100644
index 0000000..70ccd11
--- /dev/null
+++ b/engine/src/core-effects/com/jme3/water/SimpleWaterProcessor.java
@@ -0,0 +1,589 @@
+/*
+ * Copyright (c) 2009-2010 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.water;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.material.Material;
+import com.jme3.math.*;
+import com.jme3.post.SceneProcessor;
+import com.jme3.renderer.Camera;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.Renderer;
+import com.jme3.renderer.ViewPort;
+import com.jme3.renderer.queue.RenderQueue;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.shape.Quad;
+import com.jme3.texture.FrameBuffer;
+import com.jme3.texture.Image.Format;
+import com.jme3.texture.Texture.WrapMode;
+import com.jme3.texture.Texture2D;
+import com.jme3.ui.Picture;
+
+/**
+ *
+ * Simple Water renders a simple plane that use reflection and refraction to look like water.
+ * It's pretty basic, but much faster than the WaterFilter
+ * It's useful if you aim low specs hardware and still want a good looking water.
+ * Usage is :
+ * <code>
+ * SimpleWaterProcessor waterProcessor = new SimpleWaterProcessor(assetManager);
+ * //setting the scene to use for reflection
+ * waterProcessor.setReflectionScene(mainScene);
+ * //setting the light position
+ * waterProcessor.setLightPosition(lightPos);
+ *
+ * //setting the water plane
+ * Vector3f waterLocation=new Vector3f(0,-20,0);
+ * waterProcessor.setPlane(new Plane(Vector3f.UNIT_Y, waterLocation.dot(Vector3f.UNIT_Y)));
+ * //setting the water color
+ * waterProcessor.setWaterColor(ColorRGBA.Brown);
+ *
+ * //creating a quad to render water to
+ * Quad quad = new Quad(400,400);
+ *
+ * //the texture coordinates define the general size of the waves
+ * quad.scaleTextureCoordinates(new Vector2f(6f,6f));
+ *
+ * //creating a geom to attach the water material
+ * Geometry water=new Geometry("water", quad);
+ * water.setLocalTranslation(-200, -20, 250);
+ * water.setLocalRotation(new Quaternion().fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X));
+ * //finally setting the material
+ * water.setMaterial(waterProcessor.getMaterial());
+ *
+ * //attaching the water to the root node
+ * rootNode.attachChild(water);
+ * </code>
+ * @author Normen Hansen & Rémy Bouquet
+ */
+public class SimpleWaterProcessor implements SceneProcessor {
+
+ protected RenderManager rm;
+ protected ViewPort vp;
+ protected Spatial reflectionScene;
+ protected ViewPort reflectionView;
+ protected ViewPort refractionView;
+ protected FrameBuffer reflectionBuffer;
+ protected FrameBuffer refractionBuffer;
+ protected Camera reflectionCam;
+ protected Camera refractionCam;
+ protected Texture2D reflectionTexture;
+ protected Texture2D refractionTexture;
+ protected Texture2D depthTexture;
+ protected Texture2D normalTexture;
+ protected Texture2D dudvTexture;
+ protected int renderWidth = 512;
+ protected int renderHeight = 512;
+ protected Plane plane = new Plane(Vector3f.UNIT_Y, Vector3f.ZERO.dot(Vector3f.UNIT_Y));
+ protected float speed = 0.05f;
+ protected Ray ray = new Ray();
+ protected Vector3f targetLocation = new Vector3f();
+ protected AssetManager manager;
+ protected Material material;
+ protected float waterDepth = 1;
+ protected float waterTransparency = 0.4f;
+ protected boolean debug = false;
+ private Picture dispRefraction;
+ private Picture dispReflection;
+ private Picture dispDepth;
+ private Plane reflectionClipPlane;
+ private Plane refractionClipPlane;
+ private float refractionClippingOffset = 0.3f;
+ private float reflectionClippingOffset = -5f;
+ private Vector3f vect1 = new Vector3f();
+ private Vector3f vect2 = new Vector3f();
+ private Vector3f vect3 = new Vector3f();
+
+ /**
+ * Creates a SimpleWaterProcessor
+ * @param manager the asset manager
+ */
+ public SimpleWaterProcessor(AssetManager manager) {
+ this.manager = manager;
+ material = new Material(manager, "Common/MatDefs/Water/SimpleWater.j3md");
+ material.setFloat("waterDepth", waterDepth);
+ material.setFloat("waterTransparency", waterTransparency / 10);
+ material.setColor("waterColor", ColorRGBA.White);
+ material.setVector3("lightPos", new Vector3f(1, -1, 1));
+
+ material.setColor("distortionScale", new ColorRGBA(0.2f, 0.2f, 0.2f, 0.2f));
+ material.setColor("distortionMix", new ColorRGBA(0.5f, 0.5f, 0.5f, 0.5f));
+ material.setColor("texScale", new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
+ updateClipPlanes();
+
+ }
+
+ public void initialize(RenderManager rm, ViewPort vp) {
+ this.rm = rm;
+ this.vp = vp;
+
+ loadTextures(manager);
+ createTextures();
+ applyTextures(material);
+
+ createPreViews();
+
+ material.setVector2("FrustumNearFar", new Vector2f(vp.getCamera().getFrustumNear(), vp.getCamera().getFrustumFar()));
+
+ if (debug) {
+ dispRefraction = new Picture("dispRefraction");
+ dispRefraction.setTexture(manager, refractionTexture, false);
+ dispReflection = new Picture("dispRefraction");
+ dispReflection.setTexture(manager, reflectionTexture, false);
+ dispDepth = new Picture("depthTexture");
+ dispDepth.setTexture(manager, depthTexture, false);
+ }
+ }
+
+ public void reshape(ViewPort vp, int w, int h) {
+ }
+
+ public boolean isInitialized() {
+ return rm != null;
+ }
+ float time = 0;
+ float savedTpf = 0;
+
+ public void preFrame(float tpf) {
+ time = time + (tpf * speed);
+ if (time > 1f) {
+ time = 0;
+ }
+ material.setFloat("time", time);
+ savedTpf = tpf;
+ }
+
+ public void postQueue(RenderQueue rq) {
+ Camera sceneCam = rm.getCurrentCamera();
+
+ //update ray
+ ray.setOrigin(sceneCam.getLocation());
+ ray.setDirection(sceneCam.getDirection());
+
+ //update refraction cam
+ refractionCam.setLocation(sceneCam.getLocation());
+ refractionCam.setRotation(sceneCam.getRotation());
+ refractionCam.setFrustum(sceneCam.getFrustumNear(),
+ sceneCam.getFrustumFar(),
+ sceneCam.getFrustumLeft(),
+ sceneCam.getFrustumRight(),
+ sceneCam.getFrustumTop(),
+ sceneCam.getFrustumBottom());
+
+ //update reflection cam
+ boolean inv = false;
+ if (!ray.intersectsWherePlane(plane, targetLocation)) {
+ ray.setDirection(ray.getDirection().negateLocal());
+ ray.intersectsWherePlane(plane, targetLocation);
+ inv = true;
+ }
+ Vector3f loc = plane.reflect(sceneCam.getLocation(), new Vector3f());
+ reflectionCam.setLocation(loc);
+ reflectionCam.setFrustum(sceneCam.getFrustumNear(),
+ sceneCam.getFrustumFar(),
+ sceneCam.getFrustumLeft(),
+ sceneCam.getFrustumRight(),
+ sceneCam.getFrustumTop(),
+ sceneCam.getFrustumBottom());
+ // tempVec and calcVect are just temporary vector3f objects
+ vect1.set(sceneCam.getLocation()).addLocal(sceneCam.getUp());
+ float planeDistance = plane.pseudoDistance(vect1);
+ vect2.set(plane.getNormal()).multLocal(planeDistance * 2.0f);
+ vect3.set(vect1.subtractLocal(vect2)).subtractLocal(loc).normalizeLocal().negateLocal();
+ // now set the up vector
+ reflectionCam.lookAt(targetLocation, vect3);
+ if (inv) {
+ reflectionCam.setAxes(reflectionCam.getLeft().negateLocal(), reflectionCam.getUp(), reflectionCam.getDirection().negateLocal());
+ }
+
+ //Rendering reflection and refraction
+ rm.renderViewPort(reflectionView, savedTpf);
+ rm.renderViewPort(refractionView, savedTpf);
+ rm.getRenderer().setFrameBuffer(vp.getOutputFrameBuffer());
+ rm.setCamera(sceneCam, false);
+
+ }
+
+ public void postFrame(FrameBuffer out) {
+ if (debug) {
+ displayMap(rm.getRenderer(), dispRefraction, 64);
+ displayMap(rm.getRenderer(), dispReflection, 256);
+ displayMap(rm.getRenderer(), dispDepth, 448);
+ }
+ }
+
+ public void cleanup() {
+ }
+
+ //debug only : displays maps
+ protected void displayMap(Renderer r, Picture pic, int left) {
+ Camera cam = vp.getCamera();
+ rm.setCamera(cam, true);
+ int h = cam.getHeight();
+
+ pic.setPosition(left, h / 20f);
+
+ pic.setWidth(128);
+ pic.setHeight(128);
+ pic.updateGeometricState();
+ rm.renderGeometry(pic);
+ rm.setCamera(cam, false);
+ }
+
+ protected void loadTextures(AssetManager manager) {
+ normalTexture = (Texture2D) manager.loadTexture("Common/MatDefs/Water/Textures/water_normalmap.dds");
+ dudvTexture = (Texture2D) manager.loadTexture("Common/MatDefs/Water/Textures/dudv_map.jpg");
+ normalTexture.setWrap(WrapMode.Repeat);
+ dudvTexture.setWrap(WrapMode.Repeat);
+ }
+
+ protected void createTextures() {
+ reflectionTexture = new Texture2D(renderWidth, renderHeight, Format.RGBA8);
+ refractionTexture = new Texture2D(renderWidth, renderHeight, Format.RGBA8);
+ depthTexture = new Texture2D(renderWidth, renderHeight, Format.Depth);
+ }
+
+ protected void applyTextures(Material mat) {
+ mat.setTexture("water_reflection", reflectionTexture);
+ mat.setTexture("water_refraction", refractionTexture);
+ mat.setTexture("water_depthmap", depthTexture);
+ mat.setTexture("water_normalmap", normalTexture);
+ mat.setTexture("water_dudvmap", dudvTexture);
+ }
+
+ protected void createPreViews() {
+ reflectionCam = new Camera(renderWidth, renderHeight);
+ refractionCam = new Camera(renderWidth, renderHeight);
+
+ // create a pre-view. a view that is rendered before the main view
+ reflectionView = new ViewPort("Reflection View", reflectionCam);
+ reflectionView.setClearFlags(true, true, true);
+ reflectionView.setBackgroundColor(ColorRGBA.Black);
+ // create offscreen framebuffer
+ reflectionBuffer = new FrameBuffer(renderWidth, renderHeight, 1);
+ //setup framebuffer to use texture
+ reflectionBuffer.setDepthBuffer(Format.Depth);
+ reflectionBuffer.setColorTexture(reflectionTexture);
+
+ //set viewport to render to offscreen framebuffer
+ reflectionView.setOutputFrameBuffer(reflectionBuffer);
+ reflectionView.addProcessor(new ReflectionProcessor(reflectionCam, reflectionBuffer, reflectionClipPlane));
+ // attach the scene to the viewport to be rendered
+ reflectionView.attachScene(reflectionScene);
+
+ // create a pre-view. a view that is rendered before the main view
+ refractionView = new ViewPort("Refraction View", refractionCam);
+ refractionView.setClearFlags(true, true, true);
+ refractionView.setBackgroundColor(ColorRGBA.Black);
+ // create offscreen framebuffer
+ refractionBuffer = new FrameBuffer(renderWidth, renderHeight, 1);
+ //setup framebuffer to use texture
+ refractionBuffer.setDepthBuffer(Format.Depth);
+ refractionBuffer.setColorTexture(refractionTexture);
+ refractionBuffer.setDepthTexture(depthTexture);
+ //set viewport to render to offscreen framebuffer
+ refractionView.setOutputFrameBuffer(refractionBuffer);
+ refractionView.addProcessor(new RefractionProcessor());
+ // attach the scene to the viewport to be rendered
+ refractionView.attachScene(reflectionScene);
+ }
+
+ protected void destroyViews() {
+ // rm.removePreView(reflectionView);
+ rm.removePreView(refractionView);
+ }
+
+ /**
+ * Get the water material from this processor, apply this to your water quad.
+ * @return
+ */
+ public Material getMaterial() {
+ return material;
+ }
+
+ /**
+ * Sets the reflected scene, should not include the water quad!
+ * Set before adding processor.
+ * @param spat
+ */
+ public void setReflectionScene(Spatial spat) {
+ reflectionScene = spat;
+ }
+
+ /**
+ * returns the width of the reflection and refraction textures
+ * @return
+ */
+ public int getRenderWidth() {
+ return renderWidth;
+ }
+
+ /**
+ * returns the height of the reflection and refraction textures
+ * @return
+ */
+ public int getRenderHeight() {
+ return renderHeight;
+ }
+
+ /**
+ * Set the reflection Texture render size,
+ * set before adding the processor!
+ * @param with
+ * @param height
+ */
+ public void setRenderSize(int width, int height) {
+ renderWidth = width;
+ renderHeight = height;
+ }
+
+ /**
+ * returns the water plane
+ * @return
+ */
+ public Plane getPlane() {
+ return plane;
+ }
+
+ /**
+ * Set the water plane for this processor.
+ * @param plane
+ */
+ public void setPlane(Plane plane) {
+ this.plane.setConstant(plane.getConstant());
+ this.plane.setNormal(plane.getNormal());
+ updateClipPlanes();
+ }
+
+ /**
+ * Set the water plane using an origin (location) and a normal (reflection direction).
+ * @param origin Set to 0,-6,0 if your water quad is at that location for correct reflection
+ * @param normal Set to 0,1,0 (Vector3f.UNIT_Y) for normal planar water
+ */
+ public void setPlane(Vector3f origin, Vector3f normal) {
+ this.plane.setOriginNormal(origin, normal);
+ updateClipPlanes();
+ }
+
+ private void updateClipPlanes() {
+ reflectionClipPlane = plane.clone();
+ reflectionClipPlane.setConstant(reflectionClipPlane.getConstant() + reflectionClippingOffset);
+ refractionClipPlane = plane.clone();
+ refractionClipPlane.setConstant(refractionClipPlane.getConstant() + refractionClippingOffset);
+
+ }
+
+ /**
+ * Set the light Position for the processor
+ * @param position
+ */
+ //TODO maybe we should provide a convenient method to compute position from direction
+ public void setLightPosition(Vector3f position) {
+ material.setVector3("lightPos", position);
+ }
+
+ /**
+ * Set the color that will be added to the refraction texture.
+ * @param color
+ */
+ public void setWaterColor(ColorRGBA color) {
+ material.setColor("waterColor", color);
+ }
+
+ /**
+ * Higher values make the refraction texture shine through earlier.
+ * Default is 4
+ * @param depth
+ */
+ public void setWaterDepth(float depth) {
+ waterDepth = depth;
+ material.setFloat("waterDepth", depth);
+ }
+
+ /**
+ * return the water depth
+ * @return
+ */
+ public float getWaterDepth() {
+ return waterDepth;
+ }
+
+ /**
+ * returns water transparency
+ * @return
+ */
+ public float getWaterTransparency() {
+ return waterTransparency;
+ }
+
+ /**
+ * sets the water transparency default os 0.1f
+ * @param waterTransparency
+ */
+ public void setWaterTransparency(float waterTransparency) {
+ this.waterTransparency = Math.max(0, waterTransparency);
+ material.setFloat("waterTransparency", waterTransparency / 10);
+ }
+
+ /**
+ * Sets the speed of the wave animation, default = 0.05f.
+ * @param speed
+ */
+ public void setWaveSpeed(float speed) {
+ this.speed = speed;
+ }
+
+ /**
+ * Sets the scale of distortion by the normal map, default = 0.2
+ */
+ public void setDistortionScale(float value) {
+ material.setColor("distortionScale", new ColorRGBA(value, value, value, value));
+ }
+
+ /**
+ * Sets how the normal and dudv map are mixed to create the wave effect, default = 0.5
+ */
+ public void setDistortionMix(float value) {
+ material.setColor("distortionMix", new ColorRGBA(value, value, value, value));
+ }
+
+ /**
+ * Sets the scale of the normal/dudv texture, default = 1.
+ * Note that the waves should be scaled by the texture coordinates of the quad to avoid animation artifacts,
+ * use mesh.scaleTextureCoordinates(Vector2f) for that.
+ */
+ public void setTexScale(float value) {
+ material.setColor("texScale", new ColorRGBA(value, value, value, value));
+ }
+
+ /**
+ * retruns true if the waterprocessor is in debug mode
+ * @return
+ */
+ public boolean isDebug() {
+ return debug;
+ }
+
+ /**
+ * set to true to display reflection and refraction textures in the GUI for debug purpose
+ * @param debug
+ */
+ public void setDebug(boolean debug) {
+ this.debug = debug;
+ }
+
+ /**
+ * Creates a quad with the water material applied to it.
+ * @param width
+ * @param height
+ * @return
+ */
+ public Geometry createWaterGeometry(float width, float height) {
+ Quad quad = new Quad(width, height);
+ Geometry geom = new Geometry("WaterGeometry", quad);
+ geom.setLocalRotation(new Quaternion().fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X));
+ geom.setMaterial(material);
+ return geom;
+ }
+
+ /**
+ * returns the reflection clipping plane offset
+ * @return
+ */
+ public float getReflectionClippingOffset() {
+ return reflectionClippingOffset;
+ }
+
+ /**
+ * sets the reflection clipping plane offset
+ * set a nagetive value to lower the clipping plane for relection texture rendering.
+ * @param reflectionClippingOffset
+ */
+ public void setReflectionClippingOffset(float reflectionClippingOffset) {
+ this.reflectionClippingOffset = reflectionClippingOffset;
+ updateClipPlanes();
+ }
+
+ /**
+ * returns the refraction clipping plane offset
+ * @return
+ */
+ public float getRefractionClippingOffset() {
+ return refractionClippingOffset;
+ }
+
+ /**
+ * Sets the refraction clipping plane offset
+ * set a positive value to raise the clipping plane for refraction texture rendering
+ * @param refractionClippingOffset
+ */
+ public void setRefractionClippingOffset(float refractionClippingOffset) {
+ this.refractionClippingOffset = refractionClippingOffset;
+ updateClipPlanes();
+ }
+
+ /**
+ * Refraction Processor
+ */
+ public class RefractionProcessor implements SceneProcessor {
+
+ RenderManager rm;
+ ViewPort vp;
+
+ public void initialize(RenderManager rm, ViewPort vp) {
+ this.rm = rm;
+ this.vp = vp;
+ }
+
+ public void reshape(ViewPort vp, int w, int h) {
+ }
+
+ public boolean isInitialized() {
+ return rm != null;
+ }
+
+ public void preFrame(float tpf) {
+ refractionCam.setClipPlane(refractionClipPlane, Plane.Side.Negative);//,-1
+
+ }
+
+ public void postQueue(RenderQueue rq) {
+ }
+
+ public void postFrame(FrameBuffer out) {
+ }
+
+ public void cleanup() {
+ }
+ }
+}
diff --git a/engine/src/core-effects/com/jme3/water/WaterFilter.java b/engine/src/core-effects/com/jme3/water/WaterFilter.java
new file mode 100644
index 0000000..2943dce
--- /dev/null
+++ b/engine/src/core-effects/com/jme3/water/WaterFilter.java
@@ -0,0 +1,1050 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.water;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.export.InputCapsule;
+import com.jme3.export.JmeExporter;
+import com.jme3.export.JmeImporter;
+import com.jme3.export.OutputCapsule;
+import com.jme3.light.DirectionalLight;
+import com.jme3.light.Light;
+import com.jme3.material.Material;
+import com.jme3.math.*;
+import com.jme3.post.Filter;
+import com.jme3.post.Filter.Pass;
+import com.jme3.renderer.Camera;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+import com.jme3.texture.Image.Format;
+import com.jme3.texture.Texture.WrapMode;
+import com.jme3.texture.Texture2D;
+import com.jme3.util.TempVars;
+import java.io.IOException;
+
+/**
+ * The WaterFilter is a 2D post process that simulate water.
+ * It renders water above and under water.
+ * See this blog post for more info <a href="http://jmonkeyengine.org/2011/01/15/new-advanced-water-effect-for-jmonkeyengine-3/">http://jmonkeyengine.org/2011/01/15/new-advanced-water-effect-for-jmonkeyengine-3/</a>
+ *
+ *
+ * @author Rémy Bouquet aka Nehon
+ */
+public class WaterFilter extends Filter {
+
+ private Pass reflectionPass;
+ protected Spatial reflectionScene;
+ protected ViewPort reflectionView;
+ private Texture2D normalTexture;
+ private Texture2D foamTexture;
+ private Texture2D causticsTexture;
+ private Texture2D heightTexture;
+ private Plane plane;
+ private Camera reflectionCam;
+ protected Ray ray = new Ray();
+ private Vector3f targetLocation = new Vector3f();
+ private ReflectionProcessor reflectionProcessor;
+ private Matrix4f biasMatrix = new Matrix4f(0.5f, 0.0f, 0.0f, 0.5f,
+ 0.0f, 0.5f, 0.0f, 0.5f,
+ 0.0f, 0.0f, 0.0f, 0.5f,
+ 0.0f, 0.0f, 0.0f, 1.0f);
+ private Matrix4f textureProjMatrix = new Matrix4f();
+ private boolean underWater;
+ private RenderManager renderManager;
+ private ViewPort viewPort;
+ private float time = 0;
+ //properties
+ private float speed = 1;
+ private Vector3f lightDirection = new Vector3f(0, -1, 0);
+ private ColorRGBA lightColor = ColorRGBA.White;
+ private float waterHeight = 0.0f;
+ private ColorRGBA waterColor = new ColorRGBA(0.0078f, 0.3176f, 0.5f, 1.0f);
+ private ColorRGBA deepWaterColor = new ColorRGBA(0.0039f, 0.00196f, 0.145f, 1.0f);
+ private Vector3f colorExtinction = new Vector3f(5.0f, 20.0f, 30.0f);
+ private float waterTransparency = 0.1f;
+ private float maxAmplitude = 1.5f;
+ private float shoreHardness = 0.1f;
+ private boolean useFoam = true;
+ private float foamIntensity = 0.5f;
+ private float foamHardness = 1.0f;
+ private Vector3f foamExistence = new Vector3f(0.45f, 4.35f, 1.5f);
+ private float waveScale = 0.005f;
+ private float sunScale = 3.0f;
+ private float shininess = 0.7f;
+ private Vector2f windDirection = new Vector2f(0.0f, -1.0f);
+ private int reflectionMapSize = 512;
+ private boolean useRipples = true;
+ private float normalScale = 3.0f;
+ private boolean useHQShoreline = true;
+ private boolean useSpecular = true;
+ private boolean useRefraction = true;
+ private float refractionStrength = 0.0f;
+ private float refractionConstant = 0.5f;
+ private float reflectionDisplace = 30;
+ private float underWaterFogDistance = 120;
+ private boolean useCaustics = true;
+ private float causticsIntensity = 0.5f;
+
+ /**
+ * Create a Water Filter
+ */
+ public WaterFilter() {
+ super("WaterFilter");
+ }
+
+ public WaterFilter(Node reflectionScene, Vector3f lightDirection) {
+ super("WaterFilter");
+ this.reflectionScene = reflectionScene;
+ this.lightDirection = lightDirection;
+ }
+
+ @Override
+ protected boolean isRequiresDepthTexture() {
+ return true;
+ }
+
+ @Override
+ protected void preFrame(float tpf) {
+ time = time + (tpf * speed);
+ material.setFloat("Time", time);
+ Camera sceneCam = viewPort.getCamera();
+ biasMatrix.mult(sceneCam.getViewProjectionMatrix(), textureProjMatrix);
+ material.setMatrix4("TextureProjMatrix", textureProjMatrix);
+ material.setVector3("CameraPosition", sceneCam.getLocation());
+ material.setMatrix4("ViewProjectionMatrixInverse", sceneCam.getViewProjectionMatrix().invert());
+
+ material.setFloat("WaterHeight", waterHeight);
+
+ //update reflection cam
+ ray.setOrigin(sceneCam.getLocation());
+ ray.setDirection(sceneCam.getDirection());
+ plane = new Plane(Vector3f.UNIT_Y, new Vector3f(0, waterHeight, 0).dot(Vector3f.UNIT_Y));
+ reflectionProcessor.setReflectionClipPlane(plane);
+ boolean inv = false;
+ if (!ray.intersectsWherePlane(plane, targetLocation)) {
+ ray.setDirection(ray.getDirection().negateLocal());
+ ray.intersectsWherePlane(plane, targetLocation);
+ inv = true;
+ }
+ Vector3f loc = plane.reflect(sceneCam.getLocation(), new Vector3f());
+ reflectionCam.setLocation(loc);
+ reflectionCam.setFrustum(sceneCam.getFrustumNear(),
+ sceneCam.getFrustumFar(),
+ sceneCam.getFrustumLeft(),
+ sceneCam.getFrustumRight(),
+ sceneCam.getFrustumTop(),
+ sceneCam.getFrustumBottom());
+ TempVars vars = TempVars.get();
+
+
+ vars.vect1.set(sceneCam.getLocation()).addLocal(sceneCam.getUp());
+ float planeDistance = plane.pseudoDistance(vars.vect1);
+ vars.vect2.set(plane.getNormal()).multLocal(planeDistance * 2.0f);
+ vars.vect3.set(vars.vect1.subtractLocal(vars.vect2)).subtractLocal(loc).normalizeLocal().negateLocal();
+
+ reflectionCam.lookAt(targetLocation, vars.vect3);
+ vars.release();
+
+ if (inv) {
+ reflectionCam.setAxes(reflectionCam.getLeft().negateLocal(), reflectionCam.getUp(), reflectionCam.getDirection().negateLocal());
+ }
+
+ //if we're under water no need to compute reflection
+ if (sceneCam.getLocation().y >= waterHeight) {
+ boolean rtb = true;
+ if (!renderManager.isHandleTranslucentBucket()) {
+ renderManager.setHandleTranslucentBucket(true);
+ rtb = false;
+ }
+ renderManager.renderViewPort(reflectionView, tpf);
+ if (!rtb) {
+ renderManager.setHandleTranslucentBucket(false);
+ }
+ renderManager.setCamera(sceneCam, false);
+ renderManager.getRenderer().setFrameBuffer(viewPort.getOutputFrameBuffer());
+
+
+ underWater = false;
+ } else {
+ underWater = true;
+ }
+ }
+
+ @Override
+ protected Material getMaterial() {
+ return material;
+ }
+
+ private DirectionalLight findLight(Node node) {
+ for (Light light : node.getWorldLightList()) {
+ if (light instanceof DirectionalLight) {
+ return (DirectionalLight) light;
+ }
+ }
+ for (Spatial child : node.getChildren()) {
+ if (child instanceof Node) {
+ return findLight((Node) child);
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
+
+ if (reflectionScene == null) {
+ reflectionScene = vp.getScenes().get(0);
+ DirectionalLight l = findLight((Node) reflectionScene);
+ if (l != null) {
+ lightDirection = l.getDirection();
+ }
+
+ }
+
+ this.renderManager = renderManager;
+ this.viewPort = vp;
+ reflectionPass = new Pass();
+ reflectionPass.init(renderManager.getRenderer(), reflectionMapSize, reflectionMapSize, Format.RGBA8, Format.Depth);
+ reflectionCam = new Camera(reflectionMapSize, reflectionMapSize);
+ reflectionView = new ViewPort("reflectionView", reflectionCam);
+ reflectionView.setClearFlags(true, true, true);
+ reflectionView.attachScene(reflectionScene);
+ reflectionView.setOutputFrameBuffer(reflectionPass.getRenderFrameBuffer());
+ plane = new Plane(Vector3f.UNIT_Y, new Vector3f(0, waterHeight, 0).dot(Vector3f.UNIT_Y));
+ reflectionProcessor = new ReflectionProcessor(reflectionCam, reflectionPass.getRenderFrameBuffer(), plane);
+ reflectionView.addProcessor(reflectionProcessor);
+
+ normalTexture = (Texture2D) manager.loadTexture("Common/MatDefs/Water/Textures/water_normalmap.dds");
+ if (foamTexture == null) {
+ foamTexture = (Texture2D) manager.loadTexture("Common/MatDefs/Water/Textures/foam.jpg");
+ }
+ if (causticsTexture == null) {
+ causticsTexture = (Texture2D) manager.loadTexture("Common/MatDefs/Water/Textures/caustics.jpg");
+ }
+ heightTexture = (Texture2D) manager.loadTexture("Common/MatDefs/Water/Textures/heightmap.jpg");
+
+ normalTexture.setWrap(WrapMode.Repeat);
+ foamTexture.setWrap(WrapMode.Repeat);
+ causticsTexture.setWrap(WrapMode.Repeat);
+ heightTexture.setWrap(WrapMode.Repeat);
+
+ material = new Material(manager, "Common/MatDefs/Water/Water.j3md");
+ material.setTexture("HeightMap", heightTexture);
+ material.setTexture("CausticsMap", causticsTexture);
+ material.setTexture("FoamMap", foamTexture);
+ material.setTexture("NormalMap", normalTexture);
+ material.setTexture("ReflectionMap", reflectionPass.getRenderedTexture());
+
+ material.setFloat("WaterTransparency", waterTransparency);
+ material.setFloat("NormalScale", normalScale);
+ material.setFloat("R0", refractionConstant);
+ material.setFloat("MaxAmplitude", maxAmplitude);
+ material.setVector3("LightDir", lightDirection);
+ material.setColor("LightColor", lightColor);
+ material.setFloat("ShoreHardness", shoreHardness);
+ material.setFloat("RefractionStrength", refractionStrength);
+ material.setFloat("WaveScale", waveScale);
+ material.setVector3("FoamExistence", foamExistence);
+ material.setFloat("SunScale", sunScale);
+ material.setVector3("ColorExtinction", colorExtinction);
+ material.setFloat("Shininess", shininess);
+ material.setColor("WaterColor", waterColor);
+ material.setColor("DeepWaterColor", deepWaterColor);
+ material.setVector2("WindDirection", windDirection);
+ material.setFloat("FoamHardness", foamHardness);
+ material.setBoolean("UseRipples", useRipples);
+ material.setBoolean("UseHQShoreline", useHQShoreline);
+ material.setBoolean("UseSpecular", useSpecular);
+ material.setBoolean("UseFoam", useFoam);
+ material.setBoolean("UseCaustics", useCaustics);
+ material.setBoolean("UseRefraction", useRefraction);
+ material.setFloat("ReflectionDisplace", reflectionDisplace);
+ material.setFloat("FoamIntensity", foamIntensity);
+ material.setFloat("UnderWaterFogDistance", underWaterFogDistance);
+ material.setFloat("CausticsIntensity", causticsIntensity);
+
+
+ }
+
+ @Override
+ public void write(JmeExporter ex) throws IOException {
+ super.write(ex);
+ OutputCapsule oc = ex.getCapsule(this);
+
+ oc.write(speed, "speed", 1f);
+ oc.write(lightDirection, "lightDirection", new Vector3f(0, -1, 0));
+ oc.write(lightColor, "lightColor", ColorRGBA.White);
+ oc.write(waterHeight, "waterHeight", 0.0f);
+ oc.write(waterColor, "waterColor", new ColorRGBA(0.0078f, 0.3176f, 0.5f, 1.0f));
+ oc.write(deepWaterColor, "deepWaterColor", new ColorRGBA(0.0039f, 0.00196f, 0.145f, 1.0f));
+
+ oc.write(colorExtinction, "colorExtinction", new Vector3f(5.0f, 20.0f, 30.0f));
+ oc.write(waterTransparency, "waterTransparency", 0.1f);
+ oc.write(maxAmplitude, "maxAmplitude", 1.5f);
+ oc.write(shoreHardness, "shoreHardness", 0.1f);
+ oc.write(useFoam, "useFoam", true);
+
+ oc.write(foamIntensity, "foamIntensity", 0.5f);
+ oc.write(foamHardness, "foamHardness", 1.0f);
+
+ oc.write(foamExistence, "foamExistence", new Vector3f(0.45f, 4.35f, 1.5f));
+ oc.write(waveScale, "waveScale", 0.005f);
+
+ oc.write(sunScale, "sunScale", 3.0f);
+ oc.write(shininess, "shininess", 0.7f);
+ oc.write(windDirection, "windDirection", new Vector2f(0.0f, -1.0f));
+ oc.write(reflectionMapSize, "reflectionMapSize", 512);
+ oc.write(useRipples, "useRipples", true);
+
+ oc.write(normalScale, "normalScale", 3.0f);
+ oc.write(useHQShoreline, "useHQShoreline", true);
+
+ oc.write(useSpecular, "useSpecular", true);
+
+ oc.write(useRefraction, "useRefraction", true);
+ oc.write(refractionStrength, "refractionStrength", 0.0f);
+ oc.write(refractionConstant, "refractionConstant", 0.5f);
+ oc.write(reflectionDisplace, "reflectionDisplace", 30f);
+ oc.write(underWaterFogDistance, "underWaterFogDistance", 120f);
+ oc.write(causticsIntensity, "causticsIntensity", 0.5f);
+
+ oc.write(useCaustics, "useCaustics", true);
+ }
+
+ @Override
+ public void read(JmeImporter im) throws IOException {
+ super.read(im);
+ InputCapsule ic = im.getCapsule(this);
+ speed = ic.readFloat("speed", 1f);
+ lightDirection = (Vector3f) ic.readSavable("lightDirection", new Vector3f(0, -1, 0));
+ lightColor = (ColorRGBA) ic.readSavable("lightColor", ColorRGBA.White);
+ waterHeight = ic.readFloat("waterHeight", 0.0f);
+ waterColor = (ColorRGBA) ic.readSavable("waterColor", new ColorRGBA(0.0078f, 0.3176f, 0.5f, 1.0f));
+ deepWaterColor = (ColorRGBA) ic.readSavable("deepWaterColor", new ColorRGBA(0.0039f, 0.00196f, 0.145f, 1.0f));
+
+ colorExtinction = (Vector3f) ic.readSavable("colorExtinction", new Vector3f(5.0f, 20.0f, 30.0f));
+ waterTransparency = ic.readFloat("waterTransparency", 0.1f);
+ maxAmplitude = ic.readFloat("maxAmplitude", 1.5f);
+ shoreHardness = ic.readFloat("shoreHardness", 0.1f);
+ useFoam = ic.readBoolean("useFoam", true);
+
+ foamIntensity = ic.readFloat("foamIntensity", 0.5f);
+ foamHardness = ic.readFloat("foamHardness", 1.0f);
+
+ foamExistence = (Vector3f) ic.readSavable("foamExistence", new Vector3f(0.45f, 4.35f, 1.5f));
+ waveScale = ic.readFloat("waveScale", 0.005f);
+
+ sunScale = ic.readFloat("sunScale", 3.0f);
+ shininess = ic.readFloat("shininess", 0.7f);
+ windDirection = (Vector2f) ic.readSavable("windDirection", new Vector2f(0.0f, -1.0f));
+ reflectionMapSize = ic.readInt("reflectionMapSize", 512);
+ useRipples = ic.readBoolean("useRipples", true);
+
+ normalScale = ic.readFloat("normalScale", 3.0f);
+ useHQShoreline = ic.readBoolean("useHQShoreline", true);
+
+ useSpecular = ic.readBoolean("useSpecular", true);
+
+ useRefraction = ic.readBoolean("useRefraction", true);
+ refractionStrength = ic.readFloat("refractionStrength", 0.0f);
+ refractionConstant = ic.readFloat("refractionConstant", 0.5f);
+ reflectionDisplace = ic.readFloat("reflectionDisplace", 30f);
+ underWaterFogDistance = ic.readFloat("underWaterFogDistance", 120f);
+ causticsIntensity = ic.readFloat("causticsIntensity", 0.5f);
+
+ useCaustics = ic.readBoolean("useCaustics", true);
+
+ }
+
+ /**
+ * gets the height of the water plane
+ * @return
+ */
+ public float getWaterHeight() {
+ return waterHeight;
+ }
+
+ /**
+ * Sets the height of the water plane
+ * default is 0.0
+ * @param waterHeight
+ */
+ public void setWaterHeight(float waterHeight) {
+ this.waterHeight = waterHeight;
+ }
+
+ /**
+ * sets the scene to render in the reflection map
+ * @param reflectionScene
+ */
+ public void setReflectionScene(Spatial reflectionScene) {
+ this.reflectionScene = reflectionScene;
+ }
+
+ /**
+ * returns the waterTransparency value
+ * @return
+ */
+ public float getWaterTransparency() {
+ return waterTransparency;
+ }
+
+ /**
+ * Sets how fast will colours fade out. You can also think about this
+ * values as how clear water is. Therefore use smaller values (eg. 0.05)
+ * to have crystal clear water and bigger to achieve "muddy" water.
+ * default is 0.1f
+ * @param waterTransparency
+ */
+ public void setWaterTransparency(float waterTransparency) {
+ this.waterTransparency = waterTransparency;
+ if (material != null) {
+ material.setFloat("WaterTransparency", waterTransparency);
+ }
+ }
+
+ /**
+ * Returns the normal scales applied to the normal map
+ * @return
+ */
+ public float getNormalScale() {
+ return normalScale;
+ }
+
+ /**
+ * Sets the normal scaling factors to apply to the normal map.
+ * the higher the value the more small ripples will be visible on the waves.
+ * default is 1.0
+ * @param normalScale
+ */
+ public void setNormalScale(float normalScale) {
+ this.normalScale = normalScale;
+ if (material != null) {
+ material.setFloat("NormalScale", normalScale);
+ }
+ }
+
+ /**
+ * returns the refractoin constant
+ * @return
+ */
+ public float getRefractionConstant() {
+ return refractionConstant;
+ }
+
+ /**
+ * This is a constant related to the index of refraction (IOR) used to compute the fresnel term.
+ * F = R0 + (1-R0)( 1 - N.V)^5
+ * where F is the fresnel term, R0 the constant, N the normal vector and V tne view vector.
+ * It usually depend on the material you are lookinh through (here water).
+ * Default value is 0.3f
+ * In practice, the lowest the value and the less the reflection can be seen on water
+ * @param refractionConstant
+ */
+ public void setRefractionConstant(float refractionConstant) {
+ this.refractionConstant = refractionConstant;
+ if (material != null) {
+ material.setFloat("R0", refractionConstant);
+ }
+ }
+
+ /**
+ * return the maximum wave amplitude
+ * @return
+ */
+ public float getMaxAmplitude() {
+ return maxAmplitude;
+ }
+
+ /**
+ * Sets the maximum waves amplitude
+ * default is 1.0
+ * @param maxAmplitude
+ */
+ public void setMaxAmplitude(float maxAmplitude) {
+ this.maxAmplitude = maxAmplitude;
+ if (material != null) {
+ material.setFloat("MaxAmplitude", maxAmplitude);
+ }
+ }
+
+ /**
+ * gets the light direction
+ * @return
+ */
+ public Vector3f getLightDirection() {
+ return lightDirection;
+ }
+
+ /**
+ * Sets the light direction
+ * @param lightDirection
+ */
+ public void setLightDirection(Vector3f lightDirection) {
+ this.lightDirection = lightDirection;
+ if (material != null) {
+ material.setVector3("LightDir", lightDirection);
+ }
+ }
+
+ /**
+ * returns the light color
+ * @return
+ */
+ public ColorRGBA getLightColor() {
+ return lightColor;
+ }
+
+ /**
+ * Sets the light color to use
+ * default is white
+ * @param lightColor
+ */
+ public void setLightColor(ColorRGBA lightColor) {
+ this.lightColor = lightColor;
+ if (material != null) {
+ material.setColor("LightColor", lightColor);
+ }
+ }
+
+ /**
+ * Return the shoreHardeness
+ * @return
+ */
+ public float getShoreHardness() {
+ return shoreHardness;
+ }
+
+ /**
+ * The smaller this value is, the softer the transition between
+ * shore and water. If you want hard edges use very big value.
+ * Default is 0.1f.
+ * @param shoreHardness
+ */
+ public void setShoreHardness(float shoreHardness) {
+ this.shoreHardness = shoreHardness;
+ if (material != null) {
+ material.setFloat("ShoreHardness", shoreHardness);
+ }
+ }
+
+ /**
+ * returns the foam hardness
+ * @return
+ */
+ public float getFoamHardness() {
+ return foamHardness;
+ }
+
+ /**
+ * Sets the foam hardness : How much the foam will blend with the shore to avoid hard edged water plane.
+ * Default is 1.0
+ * @param foamHardness
+ */
+ public void setFoamHardness(float foamHardness) {
+ this.foamHardness = foamHardness;
+ if (material != null) {
+ material.setFloat("FoamHardness", foamHardness);
+ }
+ }
+
+ /**
+ * returns the refractionStrenght
+ * @return
+ */
+ public float getRefractionStrength() {
+ return refractionStrength;
+ }
+
+ /**
+ * This value modifies current fresnel term. If you want to weaken
+ * reflections use bigger value. If you want to empasize them use
+ * value smaller then 0. Default is 0.0f.
+ * @param refractionStrength
+ */
+ public void setRefractionStrength(float refractionStrength) {
+ this.refractionStrength = refractionStrength;
+ if (material != null) {
+ material.setFloat("RefractionStrength", refractionStrength);
+ }
+ }
+
+ /**
+ * returns the scale factor of the waves height map
+ * @return
+ */
+ public float getWaveScale() {
+ return waveScale;
+ }
+
+ /**
+ * Sets the scale factor of the waves height map
+ * the smaller the value the bigger the waves
+ * default is 0.005f
+ * @param waveScale
+ */
+ public void setWaveScale(float waveScale) {
+ this.waveScale = waveScale;
+ if (material != null) {
+ material.setFloat("WaveScale", waveScale);
+ }
+ }
+
+ /**
+ * returns the foam existance vector
+ * @return
+ */
+ public Vector3f getFoamExistence() {
+ return foamExistence;
+ }
+
+ /**
+ * Describes at what depth foam starts to fade out and
+ * at what it is completely invisible. The third value is at
+ * what height foam for waves appear (+ waterHeight).
+ * default is (0.45, 4.35, 1.0);
+ * @param foamExistence
+ */
+ public void setFoamExistence(Vector3f foamExistence) {
+ this.foamExistence = foamExistence;
+ if (material != null) {
+ material.setVector3("FoamExistence", foamExistence);
+ }
+ }
+
+ /**
+ * gets the scale of the sun
+ * @return
+ */
+ public float getSunScale() {
+ return sunScale;
+ }
+
+ /**
+ * Sets the scale of the sun for specular effect
+ * @param sunScale
+ */
+ public void setSunScale(float sunScale) {
+ this.sunScale = sunScale;
+ if (material != null) {
+ material.setFloat("SunScale", sunScale);
+ }
+ }
+
+ /**
+ * Returns the color exctinction vector of the water
+ * @return
+ */
+ public Vector3f getColorExtinction() {
+ return colorExtinction;
+ }
+
+ /**
+ * Return at what depth the refraction color extinct
+ * the first value is for red
+ * the second is for green
+ * the third is for blue
+ * Play with thos parameters to "trouble" the water
+ * default is (5.0, 20.0, 30.0f);
+ * @param colorExtinction
+ */
+ public void setColorExtinction(Vector3f colorExtinction) {
+ this.colorExtinction = colorExtinction;
+ if (material != null) {
+ material.setVector3("ColorExtinction", colorExtinction);
+ }
+ }
+
+ /**
+ * Sets the foam texture
+ * @param foamTexture
+ */
+ public void setFoamTexture(Texture2D foamTexture) {
+ this.foamTexture = foamTexture;
+ foamTexture.setWrap(WrapMode.Repeat);
+ if (material != null) {
+ material.setTexture("FoamMap", foamTexture);
+ }
+ }
+
+ /**
+ * Sets the height texture
+ * @param heightTexture
+ */
+ public void setHeightTexture(Texture2D heightTexture) {
+ this.heightTexture = heightTexture;
+ heightTexture.setWrap(WrapMode.Repeat);
+ }
+
+ /**
+ * Sets the normal Texture
+ * @param normalTexture
+ */
+ public void setNormalTexture(Texture2D normalTexture) {
+ this.normalTexture = normalTexture;
+ normalTexture.setWrap(WrapMode.Repeat);
+ }
+
+ /**
+ * return the shininess factor of the water
+ * @return
+ */
+ public float getShininess() {
+ return shininess;
+ }
+
+ /**
+ * Sets the shinines factor of the water
+ * default is 0.7f
+ * @param shininess
+ */
+ public void setShininess(float shininess) {
+ this.shininess = shininess;
+ if (material != null) {
+ material.setFloat("Shininess", shininess);
+ }
+ }
+
+ /**
+ * retruns the speed of the waves
+ * @return
+ */
+ public float getSpeed() {
+ return speed;
+ }
+
+ /**
+ * Set the speed of the waves (0.0 is still) default is 1.0
+ * @param speed
+ */
+ public void setSpeed(float speed) {
+ this.speed = speed;
+ }
+
+ /**
+ * returns the color of the water
+ *
+ * @return
+ */
+ public ColorRGBA getWaterColor() {
+ return waterColor;
+ }
+
+ /**
+ * Sets the color of the water
+ * see setDeepWaterColor for deep water color
+ * default is (0.0078f, 0.5176f, 0.5f,1.0f) (greenish blue)
+ * @param waterColor
+ */
+ public void setWaterColor(ColorRGBA waterColor) {
+ this.waterColor = waterColor;
+ if (material != null) {
+ material.setColor("WaterColor", waterColor);
+ }
+ }
+
+ /**
+ * returns the deep water color
+ * @return
+ */
+ public ColorRGBA getDeepWaterColor() {
+ return deepWaterColor;
+ }
+
+ /**
+ * sets the deep water color
+ * see setWaterColor for general color
+ * default is (0.0039f, 0.00196f, 0.145f,1.0f) (very dark blue)
+ * @param deepWaterColor
+ */
+ public void setDeepWaterColor(ColorRGBA deepWaterColor) {
+ this.deepWaterColor = deepWaterColor;
+ if (material != null) {
+ material.setColor("DeepWaterColor", deepWaterColor);
+ }
+ }
+
+ /**
+ * returns the wind direction
+ * @return
+ */
+ public Vector2f getWindDirection() {
+ return windDirection;
+ }
+
+ /**
+ * sets the wind direction
+ * the direction where the waves move
+ * default is (0.0f, -1.0f)
+ * @param windDirection
+ */
+ public void setWindDirection(Vector2f windDirection) {
+ this.windDirection = windDirection;
+ if (material != null) {
+ material.setVector2("WindDirection", windDirection);
+ }
+ }
+
+ /**
+ * returns the size of the reflection map
+ * @return
+ */
+ public int getReflectionMapSize() {
+ return reflectionMapSize;
+ }
+
+ /**
+ * Sets the size of the reflection map
+ * default is 512, the higher, the better quality, but the slower the effect.
+ * @param reflectionMapSize
+ */
+ public void setReflectionMapSize(int reflectionMapSize) {
+ this.reflectionMapSize = reflectionMapSize;
+ }
+
+ /**
+ * returns true if the water uses foam
+ * @return
+ */
+ public boolean isUseFoam() {
+ return useFoam;
+ }
+
+ /**
+ * set to true to use foam with water
+ * default true
+ * @param useFoam
+ */
+ public void setUseFoam(boolean useFoam) {
+ this.useFoam = useFoam;
+ if (material != null) {
+ material.setBoolean("UseFoam", useFoam);
+ }
+
+ }
+
+ /**
+ * sets the texture to use to render caustics on the ground underwater
+ * @param causticsTexture
+ */
+ public void setCausticsTexture(Texture2D causticsTexture) {
+ this.causticsTexture = causticsTexture;
+ if (material != null) {
+ material.setTexture("causticsMap", causticsTexture);
+ }
+ }
+
+ /**
+ * returns true if caustics are rendered
+ * @return
+ */
+ public boolean isUseCaustics() {
+ return useCaustics;
+ }
+
+ /**
+ * set to true if you want caustics to be rendered on the ground underwater, false otherwise
+ * @param useCaustics
+ */
+ public void setUseCaustics(boolean useCaustics) {
+ this.useCaustics = useCaustics;
+ if (material != null) {
+ material.setBoolean("UseCaustics", useCaustics);
+ }
+ }
+
+ /**
+ * return true
+ * @return
+ */
+ public boolean isUseHQShoreline() {
+ return useHQShoreline;
+ }
+
+ public void setUseHQShoreline(boolean useHQShoreline) {
+ this.useHQShoreline = useHQShoreline;
+ if (material != null) {
+ material.setBoolean("UseHQShoreline", useHQShoreline);
+ }
+
+ }
+
+ /**
+ * returns true if the water use the refraction
+ * @return
+ */
+ public boolean isUseRefraction() {
+ return useRefraction;
+ }
+
+ /**
+ * set to true to use refraction (default is true)
+ * @param useRefraction
+ */
+ public void setUseRefraction(boolean useRefraction) {
+ this.useRefraction = useRefraction;
+ if (material != null) {
+ material.setBoolean("UseRefraction", useRefraction);
+ }
+
+ }
+
+ /**
+ * returns true if the ater use ripples
+ * @return
+ */
+ public boolean isUseRipples() {
+ return useRipples;
+ }
+
+ /**
+ *
+ * Set to true tu use ripples
+ * @param useRipples
+ */
+ public void setUseRipples(boolean useRipples) {
+ this.useRipples = useRipples;
+ if (material != null) {
+ material.setBoolean("UseRipples", useRipples);
+ }
+
+ }
+
+ /**
+ * returns true if the water use specular
+ * @return
+ */
+ public boolean isUseSpecular() {
+ return useSpecular;
+ }
+
+ /**
+ * Set to true to use specular lightings on the water
+ * @param useSpecular
+ */
+ public void setUseSpecular(boolean useSpecular) {
+ this.useSpecular = useSpecular;
+ if (material != null) {
+ material.setBoolean("UseSpecular", useSpecular);
+ }
+ }
+
+ /**
+ * returns the foam intensity
+ * @return
+ */
+ public float getFoamIntensity() {
+ return foamIntensity;
+ }
+
+ /**
+ * sets the foam intensity default is 0.5f
+ * @param foamIntensity
+ */
+ public void setFoamIntensity(float foamIntensity) {
+ this.foamIntensity = foamIntensity;
+ if (material != null) {
+ material.setFloat("FoamIntensity", foamIntensity);
+
+ }
+ }
+
+ /**
+ * returns the reflection displace
+ * see {@link setReflectionDisplace(float reflectionDisplace)}
+ * @return
+ */
+ public float getReflectionDisplace() {
+ return reflectionDisplace;
+ }
+
+ /**
+ * Sets the reflection displace. define how troubled will look the reflection in the water. default is 30
+ * @param reflectionDisplace
+ */
+ public void setReflectionDisplace(float reflectionDisplace) {
+ this.reflectionDisplace = reflectionDisplace;
+ if (material != null) {
+ material.setFloat("m_ReflectionDisplace", reflectionDisplace);
+ }
+ }
+
+ /**
+ * returns true if the camera is under the water level
+ * @return
+ */
+ public boolean isUnderWater() {
+ return underWater;
+ }
+
+ /**
+ * returns the distance of the fog when under water
+ * @return
+ */
+ public float getUnderWaterFogDistance() {
+ return underWaterFogDistance;
+ }
+
+ /**
+ * sets the distance of the fog when under water.
+ * default is 120 (120 world units) use a high value to raise the view range under water
+ * @param underWaterFogDistance
+ */
+ public void setUnderWaterFogDistance(float underWaterFogDistance) {
+ this.underWaterFogDistance = underWaterFogDistance;
+ if (material != null) {
+ material.setFloat("UnderWaterFogDistance", underWaterFogDistance);
+ }
+ }
+
+ /**
+ * get the intensity of caustics under water
+ * @return
+ */
+ public float getCausticsIntensity() {
+ return causticsIntensity;
+ }
+
+ /**
+ * sets the intensity of caustics under water. goes from 0 to 1, default is 0.5f
+ * @param causticsIntensity
+ */
+ public void setCausticsIntensity(float causticsIntensity) {
+ this.causticsIntensity = causticsIntensity;
+ if (material != null) {
+ material.setFloat("CausticsIntensity", causticsIntensity);
+ }
+ }
+}