Update the water filter (#693)
WaterFilter now serializes the different textures textures, and can optionally serialize the reflection scene
This commit is contained in:
parent
3058c218c5
commit
6e5e85f7ac
@ -31,7 +31,9 @@
|
|||||||
*/
|
*/
|
||||||
package com.jme3.water;
|
package com.jme3.water;
|
||||||
|
|
||||||
|
import com.jme3.asset.AssetKey;
|
||||||
import com.jme3.asset.AssetManager;
|
import com.jme3.asset.AssetManager;
|
||||||
|
import com.jme3.asset.TextureKey;
|
||||||
import com.jme3.export.InputCapsule;
|
import com.jme3.export.InputCapsule;
|
||||||
import com.jme3.export.JmeExporter;
|
import com.jme3.export.JmeExporter;
|
||||||
import com.jme3.export.JmeImporter;
|
import com.jme3.export.JmeImporter;
|
||||||
@ -41,7 +43,6 @@ import com.jme3.light.Light;
|
|||||||
import com.jme3.material.Material;
|
import com.jme3.material.Material;
|
||||||
import com.jme3.math.*;
|
import com.jme3.math.*;
|
||||||
import com.jme3.post.Filter;
|
import com.jme3.post.Filter;
|
||||||
import com.jme3.post.Filter.Pass;
|
|
||||||
import com.jme3.renderer.Camera;
|
import com.jme3.renderer.Camera;
|
||||||
import com.jme3.renderer.RenderManager;
|
import com.jme3.renderer.RenderManager;
|
||||||
import com.jme3.renderer.Renderer;
|
import com.jme3.renderer.Renderer;
|
||||||
@ -51,28 +52,35 @@ import com.jme3.scene.Spatial;
|
|||||||
import com.jme3.texture.Image.Format;
|
import com.jme3.texture.Image.Format;
|
||||||
import com.jme3.texture.Texture.WrapMode;
|
import com.jme3.texture.Texture.WrapMode;
|
||||||
import com.jme3.texture.Texture2D;
|
import com.jme3.texture.Texture2D;
|
||||||
import com.jme3.util.TempVars;
|
import com.jme3.util.clone.Cloner;
|
||||||
|
import com.jme3.util.clone.JmeCloneable;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The WaterFilter is a 2D post process that simulate water.
|
* The WaterFilter is a 2D post process that simulate water.
|
||||||
* It renders water above and under water.
|
* It renders water above and under water.
|
||||||
* See the jMonkeyEngine wiki for more info <a href="https://jmonkeyengine.github.io/wiki/jme3/advanced/post-processor_water.html">https://jmonkeyengine.github.io/wiki/jme3/advanced/post-processor_water.html</a>.
|
* See the jMonkeyEngine wiki for more info <a href="https://jmonkeyengine.github.io/wiki/jme3/advanced/post-processor_water.html">https://jmonkeyengine.github.io/wiki/jme3/advanced/post-processor_water.html</a>.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @author Rémy Bouquet aka Nehon
|
* @author Rémy Bouquet aka Nehon
|
||||||
*/
|
*/
|
||||||
public class WaterFilter extends Filter {
|
public class WaterFilter extends Filter implements JmeCloneable, Cloneable {
|
||||||
|
|
||||||
|
public static final String DEFAULT_NORMAL_MAP = "Common/MatDefs/Water/Textures/water_normalmap.dds";
|
||||||
|
public static final String DEFAULT_FOAM = "Common/MatDefs/Water/Textures/foam.jpg";
|
||||||
|
public static final String DEFAULT_CAUSTICS = "Common/MatDefs/Water/Textures/caustics.jpg";
|
||||||
|
public static final String DEFAULT_HEIGHT_MAP = "Common/MatDefs/Water/Textures/heightmap.jpg";
|
||||||
|
|
||||||
private Pass reflectionPass;
|
private Pass reflectionPass;
|
||||||
protected Spatial reflectionScene;
|
protected Spatial reflectionScene;
|
||||||
|
protected Spatial rootScene;
|
||||||
protected ViewPort reflectionView;
|
protected ViewPort reflectionView;
|
||||||
private Texture2D normalTexture;
|
private Texture2D normalTexture;
|
||||||
private Texture2D foamTexture;
|
private Texture2D foamTexture;
|
||||||
private Texture2D causticsTexture;
|
private Texture2D causticsTexture;
|
||||||
private Texture2D heightTexture;
|
private Texture2D heightTexture;
|
||||||
private Camera reflectionCam;
|
private Camera reflectionCam;
|
||||||
protected Ray ray = new Ray();
|
|
||||||
private Vector3f targetLocation = new Vector3f();
|
private Vector3f targetLocation = new Vector3f();
|
||||||
private ReflectionProcessor reflectionProcessor;
|
private ReflectionProcessor reflectionProcessor;
|
||||||
private Matrix4f biasMatrix = new Matrix4f(0.5f, 0.0f, 0.0f, 0.5f,
|
private Matrix4f biasMatrix = new Matrix4f(0.5f, 0.0f, 0.0f, 0.5f,
|
||||||
@ -120,7 +128,9 @@ public class WaterFilter extends Filter {
|
|||||||
private Vector3f center;
|
private Vector3f center;
|
||||||
private float radius;
|
private float radius;
|
||||||
private AreaShape shapeType = AreaShape.Circular;
|
private AreaShape shapeType = AreaShape.Circular;
|
||||||
|
|
||||||
|
private boolean needSaveReflectionScene;
|
||||||
|
|
||||||
public enum AreaShape{
|
public enum AreaShape{
|
||||||
Circular,
|
Circular,
|
||||||
Square
|
Square
|
||||||
@ -201,16 +211,23 @@ public class WaterFilter extends Filter {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if need to try to use direction light from a scene.
|
||||||
|
*/
|
||||||
|
protected boolean useDirectionLightFromScene() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
|
protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
|
||||||
|
rootScene = vp.getScenes().get(0);
|
||||||
|
|
||||||
if (reflectionScene == null) {
|
if (reflectionScene == null) {
|
||||||
reflectionScene = vp.getScenes().get(0);
|
reflectionScene = rootScene;
|
||||||
DirectionalLight l = findLight((Node) reflectionScene);
|
DirectionalLight directionalLight = findLight((Node) reflectionScene);
|
||||||
if (l != null) {
|
if (directionalLight != null && useDirectionLightFromScene()) {
|
||||||
lightDirection = l.getDirection();
|
lightDirection = directionalLight.getDirection();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.renderManager = renderManager;
|
this.renderManager = renderManager;
|
||||||
@ -227,19 +244,25 @@ public class WaterFilter extends Filter {
|
|||||||
reflectionProcessor.setReflectionClipPlane(plane);
|
reflectionProcessor.setReflectionClipPlane(plane);
|
||||||
reflectionView.addProcessor(reflectionProcessor);
|
reflectionView.addProcessor(reflectionProcessor);
|
||||||
|
|
||||||
normalTexture = (Texture2D) manager.loadTexture("Common/MatDefs/Water/Textures/water_normalmap.dds");
|
if (normalTexture == null) {
|
||||||
if (foamTexture == null) {
|
normalTexture = (Texture2D) manager.loadTexture(DEFAULT_NORMAL_MAP);
|
||||||
foamTexture = (Texture2D) manager.loadTexture("Common/MatDefs/Water/Textures/foam.jpg");
|
normalTexture.setWrap(WrapMode.Repeat);
|
||||||
}
|
}
|
||||||
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);
|
if (foamTexture == null) {
|
||||||
foamTexture.setWrap(WrapMode.Repeat);
|
foamTexture = (Texture2D) manager.loadTexture(DEFAULT_FOAM);
|
||||||
causticsTexture.setWrap(WrapMode.Repeat);
|
foamTexture.setWrap(WrapMode.Repeat);
|
||||||
heightTexture.setWrap(WrapMode.Repeat);
|
}
|
||||||
|
|
||||||
|
if (causticsTexture == null) {
|
||||||
|
causticsTexture = (Texture2D) manager.loadTexture(DEFAULT_CAUSTICS);
|
||||||
|
causticsTexture.setWrap(WrapMode.Repeat);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (heightTexture == null) {
|
||||||
|
heightTexture = (Texture2D) manager.loadTexture(DEFAULT_HEIGHT_MAP);
|
||||||
|
heightTexture.setWrap(WrapMode.Repeat);
|
||||||
|
}
|
||||||
|
|
||||||
material = new Material(manager, "Common/MatDefs/Water/Water.j3md");
|
material = new Material(manager, "Common/MatDefs/Water/Water.j3md");
|
||||||
material.setTexture("HeightMap", heightTexture);
|
material.setTexture("HeightMap", heightTexture);
|
||||||
@ -278,10 +301,9 @@ public class WaterFilter extends Filter {
|
|||||||
if (center != null) {
|
if (center != null) {
|
||||||
material.setVector3("Center", center);
|
material.setVector3("Center", center);
|
||||||
material.setFloat("Radius", radius * radius);
|
material.setFloat("Radius", radius * radius);
|
||||||
material.setBoolean("SquareArea", shapeType==AreaShape.Square);
|
material.setBoolean("SquareArea", shapeType == AreaShape.Square);
|
||||||
}
|
}
|
||||||
material.setFloat("WaterHeight", waterHeight);
|
material.setFloat("WaterHeight", waterHeight);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -292,8 +314,36 @@ public class WaterFilter extends Filter {
|
|||||||
@Override
|
@Override
|
||||||
public void write(JmeExporter ex) throws IOException {
|
public void write(JmeExporter ex) throws IOException {
|
||||||
super.write(ex);
|
super.write(ex);
|
||||||
|
|
||||||
OutputCapsule oc = ex.getCapsule(this);
|
OutputCapsule oc = ex.getCapsule(this);
|
||||||
|
|
||||||
|
final Spatial reflectionScene = getReflectionScene();
|
||||||
|
final boolean needSaveReflectionScene = isNeedSaveReflectionScene();
|
||||||
|
|
||||||
|
final AssetKey causticsTextureKey = causticsTexture.getKey();
|
||||||
|
final AssetKey heightTextureKey = heightTexture.getKey();
|
||||||
|
final AssetKey normalTextureKey = normalTexture.getKey();
|
||||||
|
final AssetKey foamTextureKey = foamTexture.getKey();
|
||||||
|
|
||||||
|
if (causticsTextureKey != null && !DEFAULT_CAUSTICS.equals(causticsTextureKey.getName())) {
|
||||||
|
oc.write(causticsTextureKey, "causticsTexture", null);
|
||||||
|
}
|
||||||
|
if (heightTextureKey != null && !DEFAULT_HEIGHT_MAP.equals(heightTextureKey.getName())) {
|
||||||
|
oc.write(heightTextureKey, "heightTexture", null);
|
||||||
|
}
|
||||||
|
if (normalTextureKey != null && !DEFAULT_NORMAL_MAP.equals(normalTextureKey.getName())) {
|
||||||
|
oc.write(normalTextureKey, "normalTexture", null);
|
||||||
|
}
|
||||||
|
if (foamTextureKey != null && !DEFAULT_FOAM.equals(foamTextureKey.getName())) {
|
||||||
|
oc.write(foamTextureKey, "foamTexture", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
oc.write(needSaveReflectionScene, "needSaveReflectionScene", false);
|
||||||
|
|
||||||
|
if (needSaveReflectionScene) {
|
||||||
|
oc.write(reflectionScene, "reflectionScene", null);
|
||||||
|
}
|
||||||
|
|
||||||
oc.write(speed, "speed", 1f);
|
oc.write(speed, "speed", 1f);
|
||||||
oc.write(lightDirection, "lightDirection", new Vector3f(0, -1, 0));
|
oc.write(lightDirection, "lightDirection", new Vector3f(0, -1, 0));
|
||||||
oc.write(lightColor, "lightColor", ColorRGBA.White);
|
oc.write(lightColor, "lightColor", ColorRGBA.White);
|
||||||
@ -382,6 +432,29 @@ public class WaterFilter extends Filter {
|
|||||||
|
|
||||||
useCaustics = ic.readBoolean("useCaustics", true);
|
useCaustics = ic.readBoolean("useCaustics", true);
|
||||||
|
|
||||||
|
final TextureKey causticsTextureKey = (TextureKey) ic.readSavable("causticsTexture", null);
|
||||||
|
final TextureKey heightTextureKey = (TextureKey) ic.readSavable("heightTexture", null);
|
||||||
|
final TextureKey normalTextureKey = (TextureKey) ic.readSavable("normalTexture", null);
|
||||||
|
final TextureKey foamTextureKey = (TextureKey) ic.readSavable("foamTexture", null);
|
||||||
|
|
||||||
|
needSaveReflectionScene = ic.readBoolean("needSaveReflectionScene", false);
|
||||||
|
reflectionScene = (Spatial) ic.readSavable("reflectionScene", null);
|
||||||
|
|
||||||
|
final AssetManager assetManager = im.getAssetManager();
|
||||||
|
|
||||||
|
if (causticsTextureKey != null) {
|
||||||
|
setCausticsTexture((Texture2D) assetManager.loadTexture(causticsTextureKey));
|
||||||
|
}
|
||||||
|
if (heightTextureKey != null) {
|
||||||
|
setHeightTexture((Texture2D) assetManager.loadTexture(heightTextureKey));
|
||||||
|
}
|
||||||
|
if (normalTextureKey != null) {
|
||||||
|
setNormalTexture((Texture2D) assetManager.loadTexture(normalTextureKey));
|
||||||
|
}
|
||||||
|
if (foamTextureKey != null) {
|
||||||
|
setFoamTexture((Texture2D) assetManager.loadTexture(foamTextureKey));
|
||||||
|
}
|
||||||
|
|
||||||
//positional attributes
|
//positional attributes
|
||||||
center = (Vector3f) ic.readSavable("center", null);
|
center = (Vector3f) ic.readSavable("center", null);
|
||||||
radius = ic.readFloat("radius", 0f);
|
radius = ic.readFloat("radius", 0f);
|
||||||
@ -410,15 +483,36 @@ public class WaterFilter extends Filter {
|
|||||||
}
|
}
|
||||||
if (reflectionProcessor != null) {
|
if (reflectionProcessor != null) {
|
||||||
reflectionProcessor.setReflectionClipPlane(plane);
|
reflectionProcessor.setReflectionClipPlane(plane);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sets the scene to render in the reflection map
|
* Sets the scene to render in the reflection map.
|
||||||
* @param reflectionScene
|
*
|
||||||
|
* @param reflectionScene the refraction scene.
|
||||||
*/
|
*/
|
||||||
public void setReflectionScene(Spatial reflectionScene) {
|
public void setReflectionScene(final Spatial reflectionScene) {
|
||||||
|
|
||||||
|
final Spatial currentScene = getReflectionScene();
|
||||||
|
|
||||||
|
if (reflectionView != null) {
|
||||||
|
reflectionView.detachScene(currentScene == null? rootScene : currentScene);
|
||||||
|
}
|
||||||
|
|
||||||
this.reflectionScene = reflectionScene;
|
this.reflectionScene = reflectionScene;
|
||||||
|
|
||||||
|
if (reflectionView != null) {
|
||||||
|
reflectionView.attachScene(reflectionScene == null? rootScene : reflectionScene);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the scene which is used to render in the reflection map.
|
||||||
|
*
|
||||||
|
* @return the refraction scene.
|
||||||
|
*/
|
||||||
|
public Spatial getReflectionScene() {
|
||||||
|
return reflectionScene;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -696,8 +790,9 @@ public class WaterFilter extends Filter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the foam texture
|
* Sets the foam texture.
|
||||||
* @param foamTexture
|
*
|
||||||
|
* @param foamTexture the foam texture.
|
||||||
*/
|
*/
|
||||||
public void setFoamTexture(Texture2D foamTexture) {
|
public void setFoamTexture(Texture2D foamTexture) {
|
||||||
this.foamTexture = foamTexture;
|
this.foamTexture = foamTexture;
|
||||||
@ -707,8 +802,18 @@ public class WaterFilter extends Filter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the foam texture.
|
||||||
|
*
|
||||||
|
* @return the foam texture.
|
||||||
|
*/
|
||||||
|
public Texture2D getFoamTexture() {
|
||||||
|
return foamTexture;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the height texture
|
* Sets the height texture
|
||||||
|
*
|
||||||
* @param heightTexture
|
* @param heightTexture
|
||||||
*/
|
*/
|
||||||
public void setHeightTexture(Texture2D heightTexture) {
|
public void setHeightTexture(Texture2D heightTexture) {
|
||||||
@ -720,8 +825,18 @@ public class WaterFilter extends Filter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the normal Texture
|
* Gets the height texture.
|
||||||
* @param normalTexture
|
*
|
||||||
|
* @return the height texture.
|
||||||
|
*/
|
||||||
|
public Texture2D getHeightTexture() {
|
||||||
|
return heightTexture;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the normal texture.
|
||||||
|
*
|
||||||
|
* @param normalTexture the normal texture.
|
||||||
*/
|
*/
|
||||||
public void setNormalTexture(Texture2D normalTexture) {
|
public void setNormalTexture(Texture2D normalTexture) {
|
||||||
this.normalTexture = normalTexture;
|
this.normalTexture = normalTexture;
|
||||||
@ -731,6 +846,15 @@ public class WaterFilter extends Filter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the normal texture.
|
||||||
|
*
|
||||||
|
* @return the normal texture.
|
||||||
|
*/
|
||||||
|
public Texture2D getNormalTexture() {
|
||||||
|
return normalTexture;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* return the shininess factor of the water
|
* return the shininess factor of the water
|
||||||
* @return
|
* @return
|
||||||
@ -878,8 +1002,9 @@ public class WaterFilter extends Filter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sets the texture to use to render caustics on the ground underwater
|
* Sets the texture to use to render caustics on the ground underwater.
|
||||||
* @param causticsTexture
|
*
|
||||||
|
* @param causticsTexture the caustics texture.
|
||||||
*/
|
*/
|
||||||
public void setCausticsTexture(Texture2D causticsTexture) {
|
public void setCausticsTexture(Texture2D causticsTexture) {
|
||||||
this.causticsTexture = causticsTexture;
|
this.causticsTexture = causticsTexture;
|
||||||
@ -888,6 +1013,15 @@ public class WaterFilter extends Filter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the texture which is used to render caustics on the ground underwater.
|
||||||
|
*
|
||||||
|
* @return the caustics texture.
|
||||||
|
*/
|
||||||
|
public Texture2D getCausticsTexture() {
|
||||||
|
return causticsTexture;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not caustics are rendered
|
* Whether or not caustics are rendered
|
||||||
* @return true if caustics are rendered
|
* @return true if caustics are rendered
|
||||||
@ -1132,6 +1266,47 @@ public class WaterFilter extends Filter {
|
|||||||
material.setBoolean("SquareArea", shapeType==AreaShape.Square);
|
material.setBoolean("SquareArea", shapeType==AreaShape.Square);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
}
|
public Object jmeClone() {
|
||||||
|
try {
|
||||||
|
return super.clone();
|
||||||
|
} catch (final CloneNotSupportedException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cloneFields(final Cloner cloner, final Object original) {
|
||||||
|
this.normalTexture = cloner.clone(normalTexture);
|
||||||
|
this.foamTexture = cloner.clone(foamTexture);
|
||||||
|
this.causticsTexture = cloner.clone(causticsTexture);
|
||||||
|
this.heightTexture = cloner.clone(heightTexture);
|
||||||
|
this.targetLocation = cloner.clone(targetLocation);
|
||||||
|
this.biasMatrix = cloner.clone(biasMatrix);
|
||||||
|
this.textureProjMatrix = cloner.clone(textureProjMatrix);
|
||||||
|
this.lightDirection = cloner.clone(lightDirection);
|
||||||
|
this.lightColor = cloner.clone(lightColor);
|
||||||
|
this.waterColor = cloner.clone(waterColor);
|
||||||
|
this.deepWaterColor = cloner.clone(deepWaterColor);
|
||||||
|
this.colorExtinction = cloner.clone(colorExtinction);
|
||||||
|
this.foamExistence = cloner.clone(foamExistence);
|
||||||
|
this.windDirection = cloner.clone(windDirection);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the flag.
|
||||||
|
*
|
||||||
|
* @param needSaveReflectionScene true if need to save reflection scene.
|
||||||
|
*/
|
||||||
|
public void setNeedSaveReflectionScene(final boolean needSaveReflectionScene) {
|
||||||
|
this.needSaveReflectionScene = needSaveReflectionScene;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if need to save reflection scene.
|
||||||
|
*/
|
||||||
|
public boolean isNeedSaveReflectionScene() {
|
||||||
|
return needSaveReflectionScene;
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user