Преглед на файлове

Update the water filter (#693)

WaterFilter now serializes the different textures textures, and can optionally serialize the reflection scene
Alexandr Brui преди 8 години
родител
ревизия
6e5e85f7ac
променени са 1 файла, в които са добавени 210 реда и са изтрити 35 реда
  1. 210 35
      jme3-effects/src/main/java/com/jme3/water/WaterFilter.java

+ 210 - 35
jme3-effects/src/main/java/com/jme3/water/WaterFilter.java

@@ -31,7 +31,9 @@
  */
 package com.jme3.water;
 
+import com.jme3.asset.AssetKey;
 import com.jme3.asset.AssetManager;
+import com.jme3.asset.TextureKey;
 import com.jme3.export.InputCapsule;
 import com.jme3.export.JmeExporter;
 import com.jme3.export.JmeImporter;
@@ -41,7 +43,6 @@ 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.Renderer;
@@ -51,28 +52,35 @@ 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 com.jme3.util.clone.Cloner;
+import com.jme3.util.clone.JmeCloneable;
+
 import java.io.IOException;
 
 /**
  * The WaterFilter is a 2D post process that simulate 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>.
- * 
- * 
+ *
+ *
  * @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;
     protected Spatial reflectionScene;
+    protected Spatial rootScene;
     protected ViewPort reflectionView;
     private Texture2D normalTexture;
     private Texture2D foamTexture;
     private Texture2D causticsTexture;
     private Texture2D heightTexture;
     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,
@@ -120,7 +128,9 @@ public class WaterFilter extends Filter {
     private Vector3f center;
     private float radius;
     private AreaShape shapeType = AreaShape.Circular;
-    
+
+    private boolean needSaveReflectionScene;
+
     public enum AreaShape{
         Circular,
         Square
@@ -201,16 +211,23 @@ public class WaterFilter extends Filter {
         return null;
     }
 
+    /**
+     * @return true if need to try to use direction light from a scene.
+     */
+    protected boolean useDirectionLightFromScene() {
+        return true;
+    }
+
     @Override
     protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
+        rootScene = vp.getScenes().get(0);
 
         if (reflectionScene == null) {
-            reflectionScene = vp.getScenes().get(0);
-            DirectionalLight l = findLight((Node) reflectionScene);
-            if (l != null) {
-                lightDirection = l.getDirection();
+            reflectionScene = rootScene;
+            DirectionalLight directionalLight = findLight((Node) reflectionScene);
+            if (directionalLight != null && useDirectionLightFromScene()) {
+                lightDirection = directionalLight.getDirection();
             }
-
         }
 
         this.renderManager = renderManager;
@@ -227,19 +244,25 @@ public class WaterFilter extends Filter {
         reflectionProcessor.setReflectionClipPlane(plane);
         reflectionView.addProcessor(reflectionProcessor);
 
-        normalTexture = (Texture2D) manager.loadTexture("Common/MatDefs/Water/Textures/water_normalmap.dds");
+        if (normalTexture == null) {
+            normalTexture = (Texture2D) manager.loadTexture(DEFAULT_NORMAL_MAP);
+            normalTexture.setWrap(WrapMode.Repeat);
+        }
+
         if (foamTexture == null) {
-            foamTexture = (Texture2D) manager.loadTexture("Common/MatDefs/Water/Textures/foam.jpg");
+            foamTexture = (Texture2D) manager.loadTexture(DEFAULT_FOAM);
+            foamTexture.setWrap(WrapMode.Repeat);
         }
+
         if (causticsTexture == null) {
-            causticsTexture = (Texture2D) manager.loadTexture("Common/MatDefs/Water/Textures/caustics.jpg");
+            causticsTexture = (Texture2D) manager.loadTexture(DEFAULT_CAUSTICS);
+            causticsTexture.setWrap(WrapMode.Repeat);
         }
-        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);
+        if (heightTexture == null) {
+            heightTexture = (Texture2D) manager.loadTexture(DEFAULT_HEIGHT_MAP);
+            heightTexture.setWrap(WrapMode.Repeat);
+        }
 
         material = new Material(manager, "Common/MatDefs/Water/Water.j3md");
         material.setTexture("HeightMap", heightTexture);
@@ -278,10 +301,9 @@ public class WaterFilter extends Filter {
         if (center != null) {
             material.setVector3("Center", center);
             material.setFloat("Radius", radius * radius);
-            material.setBoolean("SquareArea", shapeType==AreaShape.Square);
+            material.setBoolean("SquareArea", shapeType == AreaShape.Square);
         }
         material.setFloat("WaterHeight", waterHeight);
-
     }
 
     @Override
@@ -292,8 +314,36 @@ public class WaterFilter extends Filter {
     @Override
     public void write(JmeExporter ex) throws IOException {
         super.write(ex);
+
         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(lightDirection, "lightDirection", new Vector3f(0, -1, 0));
         oc.write(lightColor, "lightColor", ColorRGBA.White);
@@ -382,6 +432,29 @@ public class WaterFilter extends Filter {
 
         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
         center = (Vector3f) ic.readSavable("center", null);
         radius = ic.readFloat("radius", 0f);
@@ -410,15 +483,36 @@ public class WaterFilter extends Filter {
         }
         if (reflectionProcessor != null) {
             reflectionProcessor.setReflectionClipPlane(plane);
-        }                
+        }
     }
 
     /**
-     * sets the scene to render in the reflection map
-     * @param reflectionScene 
+     * Sets the scene to render in the reflection map.
+     *
+     * @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;
+
+        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
-     * @param foamTexture
+     * Sets the foam texture.
+     *
+     * @param foamTexture the foam texture.
      */
     public void setFoamTexture(Texture2D 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
+     *
      * @param heightTexture
      */
     public void setHeightTexture(Texture2D heightTexture) {
@@ -720,8 +825,18 @@ public class WaterFilter extends Filter {
     }
 
     /**
-     * Sets the normal Texture
-     * @param normalTexture
+     * Gets the height texture.
+     *
+     * @return the height texture.
+     */
+    public Texture2D getHeightTexture() {
+        return heightTexture;
+    }
+
+    /**
+     * Sets the normal texture.
+     *
+     * @param normalTexture the normal texture.
      */
     public void setNormalTexture(Texture2D 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
@@ -878,8 +1002,9 @@ public class WaterFilter extends Filter {
     }
 
     /**
-     * sets the texture to use to render caustics on the ground underwater
-     * @param causticsTexture 
+     * Sets the texture to use to render caustics on the ground underwater.
+     *
+     * @param causticsTexture the caustics texture.
      */
     public void setCausticsTexture(Texture2D 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
      * @return true if caustics are rendered
@@ -1132,6 +1266,47 @@ public class WaterFilter extends Filter {
             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;
+    }
+}