1 /*
2  * Copyright (c) 2009-2012 jMonkeyEngine
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
12  * * Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  *
16  * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17  *   may be used to endorse or promote products derived from this software
18  *   without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 package com.jme3.water;
33 
34 import com.jme3.asset.AssetManager;
35 import com.jme3.export.InputCapsule;
36 import com.jme3.export.JmeExporter;
37 import com.jme3.export.JmeImporter;
38 import com.jme3.export.OutputCapsule;
39 import com.jme3.light.DirectionalLight;
40 import com.jme3.light.Light;
41 import com.jme3.material.Material;
42 import com.jme3.math.*;
43 import com.jme3.post.Filter;
44 import com.jme3.post.Filter.Pass;
45 import com.jme3.renderer.Camera;
46 import com.jme3.renderer.RenderManager;
47 import com.jme3.renderer.ViewPort;
48 import com.jme3.scene.Node;
49 import com.jme3.scene.Spatial;
50 import com.jme3.texture.Image.Format;
51 import com.jme3.texture.Texture.WrapMode;
52 import com.jme3.texture.Texture2D;
53 import com.jme3.util.TempVars;
54 import java.io.IOException;
55 
56 /**
57  * The WaterFilter is a 2D post process that simulate water.
58  * It renders water above and under water.
59  * 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>
60  *
61  *
62  * @author Rémy Bouquet aka Nehon
63  */
64 public class WaterFilter extends Filter {
65 
66     private Pass reflectionPass;
67     protected Spatial reflectionScene;
68     protected ViewPort reflectionView;
69     private Texture2D normalTexture;
70     private Texture2D foamTexture;
71     private Texture2D causticsTexture;
72     private Texture2D heightTexture;
73     private Plane plane;
74     private Camera reflectionCam;
75     protected Ray ray = new Ray();
76     private Vector3f targetLocation = new Vector3f();
77     private ReflectionProcessor reflectionProcessor;
78     private Matrix4f biasMatrix = new Matrix4f(0.5f, 0.0f, 0.0f, 0.5f,
79             0.0f, 0.5f, 0.0f, 0.5f,
80             0.0f, 0.0f, 0.0f, 0.5f,
81             0.0f, 0.0f, 0.0f, 1.0f);
82     private Matrix4f textureProjMatrix = new Matrix4f();
83     private boolean underWater;
84     private RenderManager renderManager;
85     private ViewPort viewPort;
86     private float time = 0;
87     //properties
88     private float speed = 1;
89     private Vector3f lightDirection = new Vector3f(0, -1, 0);
90     private ColorRGBA lightColor = ColorRGBA.White;
91     private float waterHeight = 0.0f;
92     private ColorRGBA waterColor = new ColorRGBA(0.0078f, 0.3176f, 0.5f, 1.0f);
93     private ColorRGBA deepWaterColor = new ColorRGBA(0.0039f, 0.00196f, 0.145f, 1.0f);
94     private Vector3f colorExtinction = new Vector3f(5.0f, 20.0f, 30.0f);
95     private float waterTransparency = 0.1f;
96     private float maxAmplitude = 1.5f;
97     private float shoreHardness = 0.1f;
98     private boolean useFoam = true;
99     private float foamIntensity = 0.5f;
100     private float foamHardness = 1.0f;
101     private Vector3f foamExistence = new Vector3f(0.45f, 4.35f, 1.5f);
102     private float waveScale = 0.005f;
103     private float sunScale = 3.0f;
104     private float shininess = 0.7f;
105     private Vector2f windDirection = new Vector2f(0.0f, -1.0f);
106     private int reflectionMapSize = 512;
107     private boolean useRipples = true;
108     private float normalScale = 3.0f;
109     private boolean useHQShoreline = true;
110     private boolean useSpecular = true;
111     private boolean useRefraction = true;
112     private float refractionStrength = 0.0f;
113     private float refractionConstant = 0.5f;
114     private float reflectionDisplace = 30;
115     private float underWaterFogDistance = 120;
116     private boolean useCaustics = true;
117     private float causticsIntensity = 0.5f;
118 
119     /**
120      * Create a Water Filter
121      */
WaterFilter()122     public WaterFilter() {
123         super("WaterFilter");
124     }
125 
WaterFilter(Node reflectionScene, Vector3f lightDirection)126     public WaterFilter(Node reflectionScene, Vector3f lightDirection) {
127         super("WaterFilter");
128         this.reflectionScene = reflectionScene;
129         this.lightDirection = lightDirection;
130     }
131 
132     @Override
isRequiresDepthTexture()133     protected boolean isRequiresDepthTexture() {
134         return true;
135     }
136 
137     @Override
preFrame(float tpf)138     protected void preFrame(float tpf) {
139         time = time + (tpf * speed);
140         material.setFloat("Time", time);
141         Camera sceneCam = viewPort.getCamera();
142         biasMatrix.mult(sceneCam.getViewProjectionMatrix(), textureProjMatrix);
143         material.setMatrix4("TextureProjMatrix", textureProjMatrix);
144         material.setVector3("CameraPosition", sceneCam.getLocation());
145         material.setMatrix4("ViewProjectionMatrixInverse", sceneCam.getViewProjectionMatrix().invert());
146 
147         material.setFloat("WaterHeight", waterHeight);
148 
149         //update reflection cam
150         ray.setOrigin(sceneCam.getLocation());
151         ray.setDirection(sceneCam.getDirection());
152         plane = new Plane(Vector3f.UNIT_Y, new Vector3f(0, waterHeight, 0).dot(Vector3f.UNIT_Y));
153         reflectionProcessor.setReflectionClipPlane(plane);
154         boolean inv = false;
155         if (!ray.intersectsWherePlane(plane, targetLocation)) {
156             ray.setDirection(ray.getDirection().negateLocal());
157             ray.intersectsWherePlane(plane, targetLocation);
158             inv = true;
159         }
160         Vector3f loc = plane.reflect(sceneCam.getLocation(), new Vector3f());
161         reflectionCam.setLocation(loc);
162         reflectionCam.setFrustum(sceneCam.getFrustumNear(),
163                 sceneCam.getFrustumFar(),
164                 sceneCam.getFrustumLeft(),
165                 sceneCam.getFrustumRight(),
166                 sceneCam.getFrustumTop(),
167                 sceneCam.getFrustumBottom());
168         TempVars vars = TempVars.get();
169 
170 
171         vars.vect1.set(sceneCam.getLocation()).addLocal(sceneCam.getUp());
172         float planeDistance = plane.pseudoDistance(vars.vect1);
173         vars.vect2.set(plane.getNormal()).multLocal(planeDistance * 2.0f);
174         vars.vect3.set(vars.vect1.subtractLocal(vars.vect2)).subtractLocal(loc).normalizeLocal().negateLocal();
175 
176         reflectionCam.lookAt(targetLocation, vars.vect3);
177         vars.release();
178 
179         if (inv) {
180             reflectionCam.setAxes(reflectionCam.getLeft().negateLocal(), reflectionCam.getUp(), reflectionCam.getDirection().negateLocal());
181         }
182 
183         //if we're under water no need to compute reflection
184         if (sceneCam.getLocation().y >= waterHeight) {
185             boolean rtb = true;
186             if (!renderManager.isHandleTranslucentBucket()) {
187                 renderManager.setHandleTranslucentBucket(true);
188                 rtb = false;
189             }
190             renderManager.renderViewPort(reflectionView, tpf);
191             if (!rtb) {
192                 renderManager.setHandleTranslucentBucket(false);
193             }
194             renderManager.setCamera(sceneCam, false);
195             renderManager.getRenderer().setFrameBuffer(viewPort.getOutputFrameBuffer());
196 
197 
198             underWater = false;
199         } else {
200             underWater = true;
201         }
202     }
203 
204     @Override
getMaterial()205     protected Material getMaterial() {
206         return material;
207     }
208 
findLight(Node node)209     private DirectionalLight findLight(Node node) {
210         for (Light light : node.getWorldLightList()) {
211             if (light instanceof DirectionalLight) {
212                 return (DirectionalLight) light;
213             }
214         }
215         for (Spatial child : node.getChildren()) {
216             if (child instanceof Node) {
217                 return findLight((Node) child);
218             }
219         }
220 
221         return null;
222     }
223 
224     @Override
initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h)225     protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
226 
227         if (reflectionScene == null) {
228             reflectionScene = vp.getScenes().get(0);
229             DirectionalLight l = findLight((Node) reflectionScene);
230             if (l != null) {
231                 lightDirection = l.getDirection();
232             }
233 
234         }
235 
236         this.renderManager = renderManager;
237         this.viewPort = vp;
238         reflectionPass = new Pass();
239         reflectionPass.init(renderManager.getRenderer(), reflectionMapSize, reflectionMapSize, Format.RGBA8, Format.Depth);
240         reflectionCam = new Camera(reflectionMapSize, reflectionMapSize);
241         reflectionView = new ViewPort("reflectionView", reflectionCam);
242         reflectionView.setClearFlags(true, true, true);
243         reflectionView.attachScene(reflectionScene);
244         reflectionView.setOutputFrameBuffer(reflectionPass.getRenderFrameBuffer());
245         plane = new Plane(Vector3f.UNIT_Y, new Vector3f(0, waterHeight, 0).dot(Vector3f.UNIT_Y));
246         reflectionProcessor = new ReflectionProcessor(reflectionCam, reflectionPass.getRenderFrameBuffer(), plane);
247         reflectionView.addProcessor(reflectionProcessor);
248 
249         normalTexture = (Texture2D) manager.loadTexture("Common/MatDefs/Water/Textures/water_normalmap.dds");
250         if (foamTexture == null) {
251             foamTexture = (Texture2D) manager.loadTexture("Common/MatDefs/Water/Textures/foam.jpg");
252         }
253         if (causticsTexture == null) {
254             causticsTexture = (Texture2D) manager.loadTexture("Common/MatDefs/Water/Textures/caustics.jpg");
255         }
256         heightTexture = (Texture2D) manager.loadTexture("Common/MatDefs/Water/Textures/heightmap.jpg");
257 
258         normalTexture.setWrap(WrapMode.Repeat);
259         foamTexture.setWrap(WrapMode.Repeat);
260         causticsTexture.setWrap(WrapMode.Repeat);
261         heightTexture.setWrap(WrapMode.Repeat);
262 
263         material = new Material(manager, "Common/MatDefs/Water/Water.j3md");
264         material.setTexture("HeightMap", heightTexture);
265         material.setTexture("CausticsMap", causticsTexture);
266         material.setTexture("FoamMap", foamTexture);
267         material.setTexture("NormalMap", normalTexture);
268         material.setTexture("ReflectionMap", reflectionPass.getRenderedTexture());
269 
270         material.setFloat("WaterTransparency", waterTransparency);
271         material.setFloat("NormalScale", normalScale);
272         material.setFloat("R0", refractionConstant);
273         material.setFloat("MaxAmplitude", maxAmplitude);
274         material.setVector3("LightDir", lightDirection);
275         material.setColor("LightColor", lightColor);
276         material.setFloat("ShoreHardness", shoreHardness);
277         material.setFloat("RefractionStrength", refractionStrength);
278         material.setFloat("WaveScale", waveScale);
279         material.setVector3("FoamExistence", foamExistence);
280         material.setFloat("SunScale", sunScale);
281         material.setVector3("ColorExtinction", colorExtinction);
282         material.setFloat("Shininess", shininess);
283         material.setColor("WaterColor", waterColor);
284         material.setColor("DeepWaterColor", deepWaterColor);
285         material.setVector2("WindDirection", windDirection);
286         material.setFloat("FoamHardness", foamHardness);
287         material.setBoolean("UseRipples", useRipples);
288         material.setBoolean("UseHQShoreline", useHQShoreline);
289         material.setBoolean("UseSpecular", useSpecular);
290         material.setBoolean("UseFoam", useFoam);
291         material.setBoolean("UseCaustics", useCaustics);
292         material.setBoolean("UseRefraction", useRefraction);
293         material.setFloat("ReflectionDisplace", reflectionDisplace);
294         material.setFloat("FoamIntensity", foamIntensity);
295         material.setFloat("UnderWaterFogDistance", underWaterFogDistance);
296         material.setFloat("CausticsIntensity", causticsIntensity);
297 
298 
299     }
300 
301     @Override
write(JmeExporter ex)302     public void write(JmeExporter ex) throws IOException {
303         super.write(ex);
304         OutputCapsule oc = ex.getCapsule(this);
305 
306         oc.write(speed, "speed", 1f);
307         oc.write(lightDirection, "lightDirection", new Vector3f(0, -1, 0));
308         oc.write(lightColor, "lightColor", ColorRGBA.White);
309         oc.write(waterHeight, "waterHeight", 0.0f);
310         oc.write(waterColor, "waterColor", new ColorRGBA(0.0078f, 0.3176f, 0.5f, 1.0f));
311         oc.write(deepWaterColor, "deepWaterColor", new ColorRGBA(0.0039f, 0.00196f, 0.145f, 1.0f));
312 
313         oc.write(colorExtinction, "colorExtinction", new Vector3f(5.0f, 20.0f, 30.0f));
314         oc.write(waterTransparency, "waterTransparency", 0.1f);
315         oc.write(maxAmplitude, "maxAmplitude", 1.5f);
316         oc.write(shoreHardness, "shoreHardness", 0.1f);
317         oc.write(useFoam, "useFoam", true);
318 
319         oc.write(foamIntensity, "foamIntensity", 0.5f);
320         oc.write(foamHardness, "foamHardness", 1.0f);
321 
322         oc.write(foamExistence, "foamExistence", new Vector3f(0.45f, 4.35f, 1.5f));
323         oc.write(waveScale, "waveScale", 0.005f);
324 
325         oc.write(sunScale, "sunScale", 3.0f);
326         oc.write(shininess, "shininess", 0.7f);
327         oc.write(windDirection, "windDirection", new Vector2f(0.0f, -1.0f));
328         oc.write(reflectionMapSize, "reflectionMapSize", 512);
329         oc.write(useRipples, "useRipples", true);
330 
331         oc.write(normalScale, "normalScale", 3.0f);
332         oc.write(useHQShoreline, "useHQShoreline", true);
333 
334         oc.write(useSpecular, "useSpecular", true);
335 
336         oc.write(useRefraction, "useRefraction", true);
337         oc.write(refractionStrength, "refractionStrength", 0.0f);
338         oc.write(refractionConstant, "refractionConstant", 0.5f);
339         oc.write(reflectionDisplace, "reflectionDisplace", 30f);
340         oc.write(underWaterFogDistance, "underWaterFogDistance", 120f);
341         oc.write(causticsIntensity, "causticsIntensity", 0.5f);
342 
343         oc.write(useCaustics, "useCaustics", true);
344     }
345 
346     @Override
read(JmeImporter im)347     public void read(JmeImporter im) throws IOException {
348         super.read(im);
349         InputCapsule ic = im.getCapsule(this);
350         speed = ic.readFloat("speed", 1f);
351         lightDirection = (Vector3f) ic.readSavable("lightDirection", new Vector3f(0, -1, 0));
352         lightColor = (ColorRGBA) ic.readSavable("lightColor", ColorRGBA.White);
353         waterHeight = ic.readFloat("waterHeight", 0.0f);
354         waterColor = (ColorRGBA) ic.readSavable("waterColor", new ColorRGBA(0.0078f, 0.3176f, 0.5f, 1.0f));
355         deepWaterColor = (ColorRGBA) ic.readSavable("deepWaterColor", new ColorRGBA(0.0039f, 0.00196f, 0.145f, 1.0f));
356 
357         colorExtinction = (Vector3f) ic.readSavable("colorExtinction", new Vector3f(5.0f, 20.0f, 30.0f));
358         waterTransparency = ic.readFloat("waterTransparency", 0.1f);
359         maxAmplitude = ic.readFloat("maxAmplitude", 1.5f);
360         shoreHardness = ic.readFloat("shoreHardness", 0.1f);
361         useFoam = ic.readBoolean("useFoam", true);
362 
363         foamIntensity = ic.readFloat("foamIntensity", 0.5f);
364         foamHardness = ic.readFloat("foamHardness", 1.0f);
365 
366         foamExistence = (Vector3f) ic.readSavable("foamExistence", new Vector3f(0.45f, 4.35f, 1.5f));
367         waveScale = ic.readFloat("waveScale", 0.005f);
368 
369         sunScale = ic.readFloat("sunScale", 3.0f);
370         shininess = ic.readFloat("shininess", 0.7f);
371         windDirection = (Vector2f) ic.readSavable("windDirection", new Vector2f(0.0f, -1.0f));
372         reflectionMapSize = ic.readInt("reflectionMapSize", 512);
373         useRipples = ic.readBoolean("useRipples", true);
374 
375         normalScale = ic.readFloat("normalScale", 3.0f);
376         useHQShoreline = ic.readBoolean("useHQShoreline", true);
377 
378         useSpecular = ic.readBoolean("useSpecular", true);
379 
380         useRefraction = ic.readBoolean("useRefraction", true);
381         refractionStrength = ic.readFloat("refractionStrength", 0.0f);
382         refractionConstant = ic.readFloat("refractionConstant", 0.5f);
383         reflectionDisplace = ic.readFloat("reflectionDisplace", 30f);
384         underWaterFogDistance = ic.readFloat("underWaterFogDistance", 120f);
385         causticsIntensity = ic.readFloat("causticsIntensity", 0.5f);
386 
387         useCaustics = ic.readBoolean("useCaustics", true);
388 
389     }
390 
391     /**
392      * gets the height of the water plane
393      * @return
394      */
getWaterHeight()395     public float getWaterHeight() {
396         return waterHeight;
397     }
398 
399     /**
400      * Sets the height of the water plane
401      * default is 0.0
402      * @param waterHeight
403      */
setWaterHeight(float waterHeight)404     public void setWaterHeight(float waterHeight) {
405         this.waterHeight = waterHeight;
406     }
407 
408     /**
409      * sets the scene to render in the reflection map
410      * @param reflectionScene
411      */
setReflectionScene(Spatial reflectionScene)412     public void setReflectionScene(Spatial reflectionScene) {
413         this.reflectionScene = reflectionScene;
414     }
415 
416     /**
417      * returns the waterTransparency value
418      * @return
419      */
getWaterTransparency()420     public float getWaterTransparency() {
421         return waterTransparency;
422     }
423 
424     /**
425      * Sets how fast will colours fade out. You can also think about this
426      * values as how clear water is. Therefore use smaller values (eg. 0.05)
427      * to have crystal clear water and bigger to achieve "muddy" water.
428      * default is 0.1f
429      * @param waterTransparency
430      */
setWaterTransparency(float waterTransparency)431     public void setWaterTransparency(float waterTransparency) {
432         this.waterTransparency = waterTransparency;
433         if (material != null) {
434             material.setFloat("WaterTransparency", waterTransparency);
435         }
436     }
437 
438     /**
439      * Returns the normal scales applied to the normal map
440      * @return
441      */
getNormalScale()442     public float getNormalScale() {
443         return normalScale;
444     }
445 
446     /**
447      * Sets the normal scaling factors to apply to the normal map.
448      * the higher the value the more small ripples will be visible on the waves.
449      * default is 1.0
450      * @param normalScale
451      */
setNormalScale(float normalScale)452     public void setNormalScale(float normalScale) {
453         this.normalScale = normalScale;
454         if (material != null) {
455             material.setFloat("NormalScale", normalScale);
456         }
457     }
458 
459     /**
460      * returns the refractoin constant
461      * @return
462      */
getRefractionConstant()463     public float getRefractionConstant() {
464         return refractionConstant;
465     }
466 
467     /**
468      * This is a constant related to the index of refraction (IOR) used to compute the fresnel term.
469      * F = R0 + (1-R0)( 1 - N.V)^5
470      * where F is the fresnel term, R0 the constant, N the normal vector and V tne view vector.
471      * It usually depend on the material you are lookinh through (here water).
472      * Default value is 0.3f
473      * In practice, the lowest the value and the less the reflection can be seen on water
474      * @param refractionConstant
475      */
setRefractionConstant(float refractionConstant)476     public void setRefractionConstant(float refractionConstant) {
477         this.refractionConstant = refractionConstant;
478         if (material != null) {
479             material.setFloat("R0", refractionConstant);
480         }
481     }
482 
483     /**
484      * return the maximum wave amplitude
485      * @return
486      */
getMaxAmplitude()487     public float getMaxAmplitude() {
488         return maxAmplitude;
489     }
490 
491     /**
492      * Sets the maximum waves amplitude
493      * default is 1.0
494      * @param maxAmplitude
495      */
setMaxAmplitude(float maxAmplitude)496     public void setMaxAmplitude(float maxAmplitude) {
497         this.maxAmplitude = maxAmplitude;
498         if (material != null) {
499             material.setFloat("MaxAmplitude", maxAmplitude);
500         }
501     }
502 
503     /**
504      * gets the light direction
505      * @return
506      */
getLightDirection()507     public Vector3f getLightDirection() {
508         return lightDirection;
509     }
510 
511     /**
512      * Sets the light direction
513      * @param lightDirection
514      */
setLightDirection(Vector3f lightDirection)515     public void setLightDirection(Vector3f lightDirection) {
516         this.lightDirection = lightDirection;
517         if (material != null) {
518             material.setVector3("LightDir", lightDirection);
519         }
520     }
521 
522     /**
523      * returns the light color
524      * @return
525      */
getLightColor()526     public ColorRGBA getLightColor() {
527         return lightColor;
528     }
529 
530     /**
531      * Sets the light color to use
532      * default is white
533      * @param lightColor
534      */
setLightColor(ColorRGBA lightColor)535     public void setLightColor(ColorRGBA lightColor) {
536         this.lightColor = lightColor;
537         if (material != null) {
538             material.setColor("LightColor", lightColor);
539         }
540     }
541 
542     /**
543      * Return the shoreHardeness
544      * @return
545      */
getShoreHardness()546     public float getShoreHardness() {
547         return shoreHardness;
548     }
549 
550     /**
551      * The smaller this value is, the softer the transition between
552      * shore and water. If you want hard edges use very big value.
553      * Default is 0.1f.
554      * @param shoreHardness
555      */
setShoreHardness(float shoreHardness)556     public void setShoreHardness(float shoreHardness) {
557         this.shoreHardness = shoreHardness;
558         if (material != null) {
559             material.setFloat("ShoreHardness", shoreHardness);
560         }
561     }
562 
563     /**
564      * returns the foam hardness
565      * @return
566      */
getFoamHardness()567     public float getFoamHardness() {
568         return foamHardness;
569     }
570 
571     /**
572      * Sets the foam hardness : How much the foam will blend with the shore to avoid hard edged water plane.
573      * Default is 1.0
574      * @param foamHardness
575      */
setFoamHardness(float foamHardness)576     public void setFoamHardness(float foamHardness) {
577         this.foamHardness = foamHardness;
578         if (material != null) {
579             material.setFloat("FoamHardness", foamHardness);
580         }
581     }
582 
583     /**
584      * returns the refractionStrenght
585      * @return
586      */
getRefractionStrength()587     public float getRefractionStrength() {
588         return refractionStrength;
589     }
590 
591     /**
592      * This value modifies current fresnel term. If you want to weaken
593      * reflections use bigger value. If you want to empasize them use
594      * value smaller then 0. Default is 0.0f.
595      * @param refractionStrength
596      */
setRefractionStrength(float refractionStrength)597     public void setRefractionStrength(float refractionStrength) {
598         this.refractionStrength = refractionStrength;
599         if (material != null) {
600             material.setFloat("RefractionStrength", refractionStrength);
601         }
602     }
603 
604     /**
605      * returns the scale factor of the waves height map
606      * @return
607      */
getWaveScale()608     public float getWaveScale() {
609         return waveScale;
610     }
611 
612     /**
613      * Sets the scale factor of the waves height map
614      * the smaller the value the bigger the waves
615      * default is 0.005f
616      * @param waveScale
617      */
setWaveScale(float waveScale)618     public void setWaveScale(float waveScale) {
619         this.waveScale = waveScale;
620         if (material != null) {
621             material.setFloat("WaveScale", waveScale);
622         }
623     }
624 
625     /**
626      * returns the foam existance vector
627      * @return
628      */
getFoamExistence()629     public Vector3f getFoamExistence() {
630         return foamExistence;
631     }
632 
633     /**
634      * Describes at what depth foam starts to fade out and
635      * at what it is completely invisible. The third value is at
636      * what height foam for waves appear (+ waterHeight).
637      * default is (0.45, 4.35, 1.0);
638      * @param foamExistence
639      */
setFoamExistence(Vector3f foamExistence)640     public void setFoamExistence(Vector3f foamExistence) {
641         this.foamExistence = foamExistence;
642         if (material != null) {
643             material.setVector3("FoamExistence", foamExistence);
644         }
645     }
646 
647     /**
648      * gets the scale of the sun
649      * @return
650      */
getSunScale()651     public float getSunScale() {
652         return sunScale;
653     }
654 
655     /**
656      * Sets the scale of the sun for specular effect
657      * @param sunScale
658      */
setSunScale(float sunScale)659     public void setSunScale(float sunScale) {
660         this.sunScale = sunScale;
661         if (material != null) {
662             material.setFloat("SunScale", sunScale);
663         }
664     }
665 
666     /**
667      * Returns the color exctinction vector of the water
668      * @return
669      */
getColorExtinction()670     public Vector3f getColorExtinction() {
671         return colorExtinction;
672     }
673 
674     /**
675      * Return at what depth the refraction color extinct
676      * the first value is for red
677      * the second is for green
678      * the third is for blue
679      * Play with thos parameters to "trouble" the water
680      * default is (5.0, 20.0, 30.0f);
681      * @param colorExtinction
682      */
setColorExtinction(Vector3f colorExtinction)683     public void setColorExtinction(Vector3f colorExtinction) {
684         this.colorExtinction = colorExtinction;
685         if (material != null) {
686             material.setVector3("ColorExtinction", colorExtinction);
687         }
688     }
689 
690     /**
691      * Sets the foam texture
692      * @param foamTexture
693      */
setFoamTexture(Texture2D foamTexture)694     public void setFoamTexture(Texture2D foamTexture) {
695         this.foamTexture = foamTexture;
696         foamTexture.setWrap(WrapMode.Repeat);
697         if (material != null) {
698             material.setTexture("FoamMap", foamTexture);
699         }
700     }
701 
702     /**
703      * Sets the height texture
704      * @param heightTexture
705      */
setHeightTexture(Texture2D heightTexture)706     public void setHeightTexture(Texture2D heightTexture) {
707         this.heightTexture = heightTexture;
708         heightTexture.setWrap(WrapMode.Repeat);
709     }
710 
711     /**
712      * Sets the normal Texture
713      * @param normalTexture
714      */
setNormalTexture(Texture2D normalTexture)715     public void setNormalTexture(Texture2D normalTexture) {
716         this.normalTexture = normalTexture;
717         normalTexture.setWrap(WrapMode.Repeat);
718     }
719 
720     /**
721      * return the shininess factor of the water
722      * @return
723      */
getShininess()724     public float getShininess() {
725         return shininess;
726     }
727 
728     /**
729      * Sets the shinines factor of the water
730      * default is 0.7f
731      * @param shininess
732      */
setShininess(float shininess)733     public void setShininess(float shininess) {
734         this.shininess = shininess;
735         if (material != null) {
736             material.setFloat("Shininess", shininess);
737         }
738     }
739 
740     /**
741      * retruns the speed of the waves
742      * @return
743      */
getSpeed()744     public float getSpeed() {
745         return speed;
746     }
747 
748     /**
749      * Set the speed of the waves (0.0 is still) default is 1.0
750      * @param speed
751      */
setSpeed(float speed)752     public void setSpeed(float speed) {
753         this.speed = speed;
754     }
755 
756     /**
757      * returns the color of the water
758      *
759      * @return
760      */
getWaterColor()761     public ColorRGBA getWaterColor() {
762         return waterColor;
763     }
764 
765     /**
766      * Sets the color of the water
767      * see setDeepWaterColor for deep water color
768      * default is (0.0078f, 0.5176f, 0.5f,1.0f) (greenish blue)
769      * @param waterColor
770      */
setWaterColor(ColorRGBA waterColor)771     public void setWaterColor(ColorRGBA waterColor) {
772         this.waterColor = waterColor;
773         if (material != null) {
774             material.setColor("WaterColor", waterColor);
775         }
776     }
777 
778     /**
779      * returns the deep water color
780      * @return
781      */
getDeepWaterColor()782     public ColorRGBA getDeepWaterColor() {
783         return deepWaterColor;
784     }
785 
786     /**
787      * sets the deep water color
788      * see setWaterColor for general color
789      * default is (0.0039f, 0.00196f, 0.145f,1.0f) (very dark blue)
790      * @param deepWaterColor
791      */
setDeepWaterColor(ColorRGBA deepWaterColor)792     public void setDeepWaterColor(ColorRGBA deepWaterColor) {
793         this.deepWaterColor = deepWaterColor;
794         if (material != null) {
795             material.setColor("DeepWaterColor", deepWaterColor);
796         }
797     }
798 
799     /**
800      * returns the wind direction
801      * @return
802      */
getWindDirection()803     public Vector2f getWindDirection() {
804         return windDirection;
805     }
806 
807     /**
808      * sets the wind direction
809      * the direction where the waves move
810      * default is (0.0f, -1.0f)
811      * @param windDirection
812      */
setWindDirection(Vector2f windDirection)813     public void setWindDirection(Vector2f windDirection) {
814         this.windDirection = windDirection;
815         if (material != null) {
816             material.setVector2("WindDirection", windDirection);
817         }
818     }
819 
820     /**
821      * returns the size of the reflection map
822      * @return
823      */
getReflectionMapSize()824     public int getReflectionMapSize() {
825         return reflectionMapSize;
826     }
827 
828     /**
829      * Sets the size of the reflection map
830      * default is 512, the higher, the better quality, but the slower the effect.
831      * @param reflectionMapSize
832      */
setReflectionMapSize(int reflectionMapSize)833     public void setReflectionMapSize(int reflectionMapSize) {
834         this.reflectionMapSize = reflectionMapSize;
835     }
836 
837     /**
838      * returns true if the water uses foam
839      * @return
840      */
isUseFoam()841     public boolean isUseFoam() {
842         return useFoam;
843     }
844 
845     /**
846      * set to true to use foam with water
847      * default true
848      * @param useFoam
849      */
setUseFoam(boolean useFoam)850     public void setUseFoam(boolean useFoam) {
851         this.useFoam = useFoam;
852         if (material != null) {
853             material.setBoolean("UseFoam", useFoam);
854         }
855 
856     }
857 
858     /**
859      * sets the texture to use to render caustics on the ground underwater
860      * @param causticsTexture
861      */
setCausticsTexture(Texture2D causticsTexture)862     public void setCausticsTexture(Texture2D causticsTexture) {
863         this.causticsTexture = causticsTexture;
864         if (material != null) {
865             material.setTexture("causticsMap", causticsTexture);
866         }
867     }
868 
869     /**
870      * returns true if caustics are rendered
871      * @return
872      */
isUseCaustics()873     public boolean isUseCaustics() {
874         return useCaustics;
875     }
876 
877     /**
878      * set to true if you want caustics to be rendered on the ground underwater, false otherwise
879      * @param useCaustics
880      */
setUseCaustics(boolean useCaustics)881     public void setUseCaustics(boolean useCaustics) {
882         this.useCaustics = useCaustics;
883         if (material != null) {
884             material.setBoolean("UseCaustics", useCaustics);
885         }
886     }
887 
888     /**
889      * return true
890      * @return
891      */
isUseHQShoreline()892     public boolean isUseHQShoreline() {
893         return useHQShoreline;
894     }
895 
setUseHQShoreline(boolean useHQShoreline)896     public void setUseHQShoreline(boolean useHQShoreline) {
897         this.useHQShoreline = useHQShoreline;
898         if (material != null) {
899             material.setBoolean("UseHQShoreline", useHQShoreline);
900         }
901 
902     }
903 
904     /**
905      * returns true if the water use the refraction
906      * @return
907      */
isUseRefraction()908     public boolean isUseRefraction() {
909         return useRefraction;
910     }
911 
912     /**
913      * set to true to use refraction (default is true)
914      * @param useRefraction
915      */
setUseRefraction(boolean useRefraction)916     public void setUseRefraction(boolean useRefraction) {
917         this.useRefraction = useRefraction;
918         if (material != null) {
919             material.setBoolean("UseRefraction", useRefraction);
920         }
921 
922     }
923 
924     /**
925      * returns true if the ater use ripples
926      * @return
927      */
isUseRipples()928     public boolean isUseRipples() {
929         return useRipples;
930     }
931 
932     /**
933      *
934      * Set to true tu use ripples
935      * @param useRipples
936      */
setUseRipples(boolean useRipples)937     public void setUseRipples(boolean useRipples) {
938         this.useRipples = useRipples;
939         if (material != null) {
940             material.setBoolean("UseRipples", useRipples);
941         }
942 
943     }
944 
945     /**
946      * returns true if the water use specular
947      * @return
948      */
isUseSpecular()949     public boolean isUseSpecular() {
950         return useSpecular;
951     }
952 
953     /**
954      * Set to true to use specular lightings on the water
955      * @param useSpecular
956      */
setUseSpecular(boolean useSpecular)957     public void setUseSpecular(boolean useSpecular) {
958         this.useSpecular = useSpecular;
959         if (material != null) {
960             material.setBoolean("UseSpecular", useSpecular);
961         }
962     }
963 
964     /**
965      * returns the foam intensity
966      * @return
967      */
getFoamIntensity()968     public float getFoamIntensity() {
969         return foamIntensity;
970     }
971 
972     /**
973      * sets the foam intensity default is 0.5f
974      * @param foamIntensity
975      */
setFoamIntensity(float foamIntensity)976     public void setFoamIntensity(float foamIntensity) {
977         this.foamIntensity = foamIntensity;
978         if (material != null) {
979             material.setFloat("FoamIntensity", foamIntensity);
980 
981         }
982     }
983 
984     /**
985      * returns the reflection displace
986      * see {@link setReflectionDisplace(float reflectionDisplace)}
987      * @return
988      */
getReflectionDisplace()989     public float getReflectionDisplace() {
990         return reflectionDisplace;
991     }
992 
993     /**
994      * Sets the reflection displace. define how troubled will look the reflection in the water. default is 30
995      * @param reflectionDisplace
996      */
setReflectionDisplace(float reflectionDisplace)997     public void setReflectionDisplace(float reflectionDisplace) {
998         this.reflectionDisplace = reflectionDisplace;
999         if (material != null) {
1000             material.setFloat("m_ReflectionDisplace", reflectionDisplace);
1001         }
1002     }
1003 
1004     /**
1005      * returns true if the camera is under the water level
1006      * @return
1007      */
isUnderWater()1008     public boolean isUnderWater() {
1009         return underWater;
1010     }
1011 
1012     /**
1013      * returns the distance of the fog when under water
1014      * @return
1015      */
getUnderWaterFogDistance()1016     public float getUnderWaterFogDistance() {
1017         return underWaterFogDistance;
1018     }
1019 
1020     /**
1021      * sets the distance of the fog when under water.
1022      * default is 120 (120 world units) use a high value to raise the view range under water
1023      * @param underWaterFogDistance
1024      */
setUnderWaterFogDistance(float underWaterFogDistance)1025     public void setUnderWaterFogDistance(float underWaterFogDistance) {
1026         this.underWaterFogDistance = underWaterFogDistance;
1027         if (material != null) {
1028             material.setFloat("UnderWaterFogDistance", underWaterFogDistance);
1029         }
1030     }
1031 
1032     /**
1033      * get the intensity of caustics under water
1034      * @return
1035      */
getCausticsIntensity()1036     public float getCausticsIntensity() {
1037         return causticsIntensity;
1038     }
1039 
1040     /**
1041      * sets the intensity of caustics under water. goes from 0 to 1, default is 0.5f
1042      * @param causticsIntensity
1043      */
setCausticsIntensity(float causticsIntensity)1044     public void setCausticsIntensity(float causticsIntensity) {
1045         this.causticsIntensity = causticsIntensity;
1046         if (material != null) {
1047             material.setFloat("CausticsIntensity", causticsIntensity);
1048         }
1049     }
1050 }
1051