Parcourir la source

All shadow renderers/filters are now properly savables

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@10005 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
rem..om il y a 13 ans
Parent
commit
b88350a069

+ 88 - 37
engine/src/core/com/jme3/shadow/AbstractShadowRenderer.java

@@ -32,6 +32,11 @@
 package com.jme3.shadow;
 
 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.export.Savable;
 import com.jme3.material.Material;
 import com.jme3.math.ColorRGBA;
 import com.jme3.math.Matrix4f;
@@ -49,7 +54,6 @@ import com.jme3.renderer.queue.RenderQueue.ShadowMode;
 import com.jme3.scene.Geometry;
 import com.jme3.scene.Spatial;
 import com.jme3.scene.debug.WireFrustum;
-import com.jme3.shadow.PssmShadowRenderer.FilterMode;
 import com.jme3.texture.FrameBuffer;
 import com.jme3.texture.Image.Format;
 import com.jme3.texture.Texture.MagFilter;
@@ -57,14 +61,17 @@ import com.jme3.texture.Texture.MinFilter;
 import com.jme3.texture.Texture.ShadowCompareMode;
 import com.jme3.texture.Texture2D;
 import com.jme3.ui.Picture;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 
 /**
- * abstract shadow renderer that holds commons feature to have for a shadow renderer
+ * abstract shadow renderer that holds commons feature to have for a shadow
+ * renderer
+ *
  * @author Rémy Bouquet aka Nehon
  */
-public abstract class AbstractShadowRenderer implements SceneProcessor {
+public abstract class AbstractShadowRenderer implements SceneProcessor, Savable {
 
     protected int nbShadowMaps = 1;
     protected float shadowMapSize;
@@ -76,12 +83,12 @@ public abstract class AbstractShadowRenderer implements SceneProcessor {
     protected Texture2D dummyTex;
     protected Material preshadowMat;
     protected Material postshadowMat;
-    protected Matrix4f[] lightViewProjectionsMatrices;    
+    protected Matrix4f[] lightViewProjectionsMatrices;
     protected AssetManager assetManager;
     protected boolean debug = false;
     protected float edgesThickness = 1.0f;
-    protected EdgeFilteringMode edgeFilteringMode;
-    protected CompareMode shadowCompareMode;
+    protected EdgeFilteringMode edgeFilteringMode = EdgeFilteringMode.Bilinear;
+    protected CompareMode shadowCompareMode = CompareMode.Hardware;
     protected Picture[] dispPic;
     protected boolean flushQueues = true;
     // define if the fallback material should be used.
@@ -95,8 +102,17 @@ public abstract class AbstractShadowRenderer implements SceneProcessor {
     protected GeometryList lightReceivers = new GeometryList(new OpaqueComparator());
     protected GeometryList shadowMapOccluders = new GeometryList(new OpaqueComparator());
 
+    
+    /**
+     * used for serialization
+     */
+    protected AbstractShadowRenderer(){        
+    }    
+    
     /**
-     * Create an abstract shadow renderer, this is to be called in extending classes
+     * Create an abstract shadow renderer, this is to be called in extending
+     * classes
+     *
      * @param assetManager the application asset manager
      * @param shadowMapSize the size of the rendered shadowmaps (512,1024,2048,
      * etc...)
@@ -106,9 +122,14 @@ public abstract class AbstractShadowRenderer implements SceneProcessor {
     protected AbstractShadowRenderer(AssetManager assetManager, int shadowMapSize, int nbShadowMaps) {
 
         this.assetManager = assetManager;
-        this.postshadowMat = new Material(assetManager, "Common/MatDefs/Shadow/PostShadow.j3md");
         this.nbShadowMaps = nbShadowMaps;
         this.shadowMapSize = shadowMapSize;
+        init(assetManager, nbShadowMaps, shadowMapSize);
+
+    }
+
+    private void init(AssetManager assetManager, int nbShadowMaps, int shadowMapSize) {
+        this.postshadowMat = new Material(assetManager, "Common/MatDefs/Shadow/PostShadow.j3md");
         shadowFB = new FrameBuffer[nbShadowMaps];
         shadowMaps = new Texture2D[nbShadowMaps];
         dispPic = new Picture[nbShadowMaps];
@@ -137,15 +158,15 @@ public abstract class AbstractShadowRenderer implements SceneProcessor {
             dispPic[i].setTexture(assetManager, shadowMaps[i], false);
         }
 
-        setShadowCompareMode(CompareMode.Hardware);
-        setEdgeFilteringMode(EdgeFilteringMode.Bilinear);
-        setShadowIntensity(0.7f);
-
+        setShadowCompareMode(shadowCompareMode);
+        setEdgeFilteringMode(edgeFilteringMode);
+        setShadowIntensity(shadowIntensity);
     }
 
     /**
      * set the post shadow material for this renderer
-     * @param postShadowMat 
+     *
+     * @param postShadowMat
      */
     protected final void setPostShadowMaterial(Material postShadowMat) {
         this.postshadowMat = postShadowMat;
@@ -159,10 +180,10 @@ public abstract class AbstractShadowRenderer implements SceneProcessor {
     }
 
     /**
-     * Sets the filtering mode for shadow edges see {@link FilterMode} for more
-     * info
+     * Sets the filtering mode for shadow edges see {@link EdgeFilteringMode}
+     * for more info
      *
-     * @param filterMode
+     * @param EdgeFilteringMode
      */
     final public void setEdgeFilteringMode(EdgeFilteringMode filterMode) {
         if (filterMode == null) {
@@ -206,11 +227,7 @@ public abstract class AbstractShadowRenderer implements SceneProcessor {
      */
     final public void setShadowCompareMode(CompareMode compareMode) {
         if (compareMode == null) {
-            throw new NullPointerException();
-        }
-
-        if (this.shadowCompareMode == compareMode) {
-            return;
+            throw new IllegalArgumentException("Shadow compare mode cannot be null");
         }
 
         this.shadowCompareMode = compareMode;
@@ -290,31 +307,38 @@ public abstract class AbstractShadowRenderer implements SceneProcessor {
     }
 
     /**
-     * This mehtod is called once per frame.
-     * it is responsible for updating the shadow cams according to the light view.
+     * This mehtod is called once per frame. it is responsible for updating the
+     * shadow cams according to the light view.
+     *
      * @param viewCam the scene cam
      */
     protected abstract void updateShadowCams(Camera viewCam);
 
     /**
-     * this method must return the geomtryList that contains the oclluders to be rendered in the shadow map
+     * this method must return the geomtryList that contains the oclluders to be
+     * rendered in the shadow map
+     *
      * @param shadowMapIndex the index of the shadow map being rendered
      * @param sceneOccluders the occluders of the whole scene
      * @param sceneReceivers the recievers of the whole scene
-     * @return 
+     * @return
      */
-    protected abstract GeometryList getOccludersToRender(int shadowMapIndex, GeometryList sceneOccluders, GeometryList sceneReceivers,GeometryList shadowMapOccluders);
+    protected abstract GeometryList getOccludersToRender(int shadowMapIndex, GeometryList sceneOccluders, GeometryList sceneReceivers, GeometryList shadowMapOccluders);
 
     /**
-     * return the shadow camera to use for rendering the shadow map according the given index
+     * return the shadow camera to use for rendering the shadow map according
+     * the given index
+     *
      * @param shadowMapIndex the index of the shadow map being rendered
      * @return the shadowCam
      */
     protected abstract Camera getShadowCam(int shadowMapIndex);
 
     /**
-     * responsible for displaying the frustum of the shadow cam for debug purpose
-     * @param shadowMapIndex 
+     * responsible for displaying the frustum of the shadow cam for debug
+     * purpose
+     *
+     * @param shadowMapIndex
      */
     protected void doDisplayFrustumDebug(int shadowMapIndex) {
     }
@@ -355,7 +379,7 @@ public abstract class AbstractShadowRenderer implements SceneProcessor {
     }
 
     protected void renderShadowMap(int shadowMapIndex, GeometryList occluders, GeometryList receivers) {
-        shadowMapOccluders = getOccludersToRender(shadowMapIndex, occluders, receivers,shadowMapOccluders);
+        shadowMapOccluders = getOccludersToRender(shadowMapIndex, occluders, receivers, shadowMapOccluders);
         Camera shadowCam = getShadowCam(shadowMapIndex);
 
         //saving light view projection matrix for this split            
@@ -396,7 +420,7 @@ public abstract class AbstractShadowRenderer implements SceneProcessor {
     public void displayDebug() {
         debug = true;
     }
-    
+
     abstract GeometryList getReceivers(GeometryList sceneReceivers, GeometryList lightReceivers);
 
     public void postFrame(FrameBuffer out) {
@@ -404,10 +428,10 @@ public abstract class AbstractShadowRenderer implements SceneProcessor {
         if (debug) {
             displayShadowMap(renderManager.getRenderer());
         }
-        
+
         lightReceivers = getReceivers(sceneReceivers, lightReceivers);
-        
-        if (lightReceivers.size()!=0) {
+
+        if (lightReceivers.size() != 0) {
             //setting params to recieving geometry list
             setMatParams();
 
@@ -422,7 +446,7 @@ public abstract class AbstractShadowRenderer implements SceneProcessor {
 
             //rendering the post shadow pass
             viewPort.getQueue().renderShadowQueue(lightReceivers, renderManager, cam, true);
-            if(flushQueues){
+            if (flushQueues) {
                 sceneReceivers.clear();
             }
 
@@ -436,8 +460,9 @@ public abstract class AbstractShadowRenderer implements SceneProcessor {
     }
 
     /**
-     * This method is called once per frame and is responsible of setting the material 
-     * parameters than sub class may need to set on the post material
+     * This method is called once per frame and is responsible of setting the
+     * material parameters than sub class may need to set on the post material
+     *
      * @param material the materail to use for the post shadow pass
      */
     protected abstract void setMaterialParameters(Material material);
@@ -571,4 +596,30 @@ public abstract class AbstractShadowRenderer implements SceneProcessor {
     public void setFlushQueues(boolean flushQueues) {
         this.flushQueues = flushQueues;
     }
+
+    public void read(JmeImporter im) throws IOException {
+        InputCapsule ic = (InputCapsule) im.getCapsule(this);
+        assetManager = im.getAssetManager();
+        nbShadowMaps = ic.readInt("nbShadowMaps", 1);
+        shadowMapSize = ic.readInt("shadowMapSize", 0);
+        shadowIntensity = ic.readFloat("shadowIntensity", 0.7f);
+        edgeFilteringMode = ic.readEnum("edgeFilteringMode", EdgeFilteringMode.class, EdgeFilteringMode.Bilinear);
+        shadowCompareMode = ic.readEnum("shadowCompareMode", CompareMode.class, CompareMode.Hardware);
+        flushQueues = ic.readBoolean("flushQueues", false);
+        init(assetManager, nbShadowMaps, (int) shadowMapSize);
+        edgesThickness = ic.readFloat("edgesThickness", 1.0f);
+        postshadowMat.setFloat("PCFEdge", edgesThickness);
+
+    }
+
+    public void write(JmeExporter ex) throws IOException {
+        OutputCapsule oc = (OutputCapsule) ex.getCapsule(this);
+        oc.write(nbShadowMaps, "nbShadowMaps", 1);
+        oc.write(shadowMapSize, "shadowMapSize", 0);
+        oc.write(shadowIntensity, "shadowIntensity", 0.7f);
+        oc.write(edgeFilteringMode, "edgeFilteringMode", EdgeFilteringMode.Bilinear);
+        oc.write(shadowCompareMode, "shadowCompareMode", CompareMode.Hardware);
+        oc.write(flushQueues, "flushQueues", false);
+        oc.write(edgesThickness, "edgesThickness", 1.0f);
+    }
 }

+ 3 - 4
engine/src/core/com/jme3/shadow/DirectionalLightShadowFilter.java

@@ -57,8 +57,6 @@ import java.io.IOException;
  */
 public class DirectionalLightShadowFilter extends AbstractShadowFilter<DirectionalLightShadowRenderer> {
 
-
-
     /**
      * Creates a DirectionalLightShadowFilter Shadow Filter More info on the
      * technique at <a
@@ -71,7 +69,7 @@ public class DirectionalLightShadowFilter extends AbstractShadowFilter<Direction
      * the more quality, the less fps).
      */
     public DirectionalLightShadowFilter(AssetManager assetManager, int shadowMapSize, int nbSplits) {
-        super(assetManager, shadowMapSize, new DirectionalLightShadowRenderer(assetManager, shadowMapSize, nbSplits));  
+        super(assetManager, shadowMapSize, new DirectionalLightShadowRenderer(assetManager, shadowMapSize, nbSplits));
     }
 
     /**
@@ -162,6 +160,7 @@ public class DirectionalLightShadowFilter extends AbstractShadowFilter<Direction
     public void write(JmeExporter ex) throws IOException {
         super.write(ex);
         OutputCapsule oc = ex.getCapsule(this);
+        oc.write(shadowRenderer, "shadowRenderer", null);
 
     }
 
@@ -169,6 +168,6 @@ public class DirectionalLightShadowFilter extends AbstractShadowFilter<Direction
     public void read(JmeImporter im) throws IOException {
         super.read(im);
         InputCapsule ic = im.getCapsule(this);
-
+        shadowRenderer = (DirectionalLightShadowRenderer) ic.readSavable("shadowRenderer", null);
     }
 }

+ 47 - 6
engine/src/core/com/jme3/shadow/DirectionalLightShadowRenderer.java

@@ -32,6 +32,10 @@
 package com.jme3.shadow;
 
 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.material.Material;
 import com.jme3.math.ColorRGBA;
@@ -39,8 +43,8 @@ import com.jme3.math.Vector2f;
 import com.jme3.math.Vector3f;
 import com.jme3.renderer.Camera;
 import com.jme3.renderer.queue.GeometryList;
-import com.jme3.renderer.queue.OpaqueComparator;
 import com.jme3.scene.Node;
+import java.io.IOException;
 
 /**
  * DirectionalLightShadowRenderer renderer use Parrallel Split Shadow Mapping
@@ -58,7 +62,7 @@ public class DirectionalLightShadowRenderer extends AbstractShadowRenderer {
     protected float lambda = 0.65f;
     protected float zFarOverride = 0;
     protected Camera shadowCam;
-    protected ColorRGBA splits;  
+    protected ColorRGBA splits;
     protected float[] splitsArray;
     protected DirectionalLight light;
     protected Vector3f[] points = new Vector3f[8];
@@ -66,25 +70,39 @@ public class DirectionalLightShadowRenderer extends AbstractShadowRenderer {
     protected Vector2f fadeInfo;
     protected float fadeLength;
 
+    /**
+     * Used for serialzation use
+     * DirectionalLightShadowRenderer#DirectionalLightShadowRenderer(AssetManager
+     * assetManager, int shadowMapSize, int nbSplits)
+     */
+    public DirectionalLightShadowRenderer() {
+        super();
+    }
 
     /**
      * Create a DirectionalLightShadowRenderer More info on the technique at <a
      * href="http://http.developer.nvidia.com/GPUGems3/gpugems3_ch10.html">http://http.developer.nvidia.com/GPUGems3/gpugems3_ch10.html</a>
      *
      * @param assetManager the application asset manager
-     * @param shadowMapSize the size of the rendered shadowmaps (512,1024,2048, etc...)
+     * @param shadowMapSize the size of the rendered shadowmaps (512,1024,2048,
+     * etc...)
      * @param nbSplits the number of shadow maps rendered (the more shadow maps
      * the more quality, the less fps).
      */
     public DirectionalLightShadowRenderer(AssetManager assetManager, int shadowMapSize, int nbSplits) {
         super(assetManager, shadowMapSize, nbSplits);
+        init(nbSplits, shadowMapSize);
+    }
 
+    private void init(int nbSplits, int shadowMapSize) {
         nbShadowMaps = Math.max(Math.min(nbSplits, 4), 1);
+        if (nbShadowMaps != nbSplits) {
+            throw new IllegalArgumentException("Number of splits must be between 1 and 4. Given value : " + nbSplits);
+        }
         splits = new ColorRGBA();
         splitsArray = new float[nbSplits + 1];
         shadowCam = new Camera(shadowMapSize, shadowMapSize);
         shadowCam.setParallelProjection(true);
-
         for (int i = 0; i < points.length; i++) {
             points[i] = new Vector3f();
         }
@@ -154,7 +172,7 @@ public class DirectionalLightShadowRenderer extends AbstractShadowRenderer {
 
         return shadowMapOccluders;
     }
-        
+
     @Override
     GeometryList getReceivers(GeometryList sceneReceivers, GeometryList lightReceivers) {
         return sceneReceivers;
@@ -163,7 +181,7 @@ public class DirectionalLightShadowRenderer extends AbstractShadowRenderer {
     @Override
     protected Camera getShadowCam(int shadowMapIndex) {
         return shadowCam;
-    }    
+    }
 
     @Override
     protected void doDisplayFrustumDebug(int shadowMapIndex) {
@@ -258,4 +276,27 @@ public class DirectionalLightShadowRenderer extends AbstractShadowRenderer {
         }
         return 0f;
     }
+
+    @Override
+    public void read(JmeImporter im) throws IOException {
+        super.read(im);
+        InputCapsule ic = (InputCapsule) im.getCapsule(this);
+        lambda = ic.readFloat("lambda", 0.65f);
+        zFarOverride = ic.readInt("zFarOverride", 0);
+        light = (DirectionalLight) ic.readSavable("light", null);
+        fadeInfo = (Vector2f) ic.readSavable("fadeInfo", null);
+        fadeLength = ic.readFloat("fadeLength", 0f);
+        init(nbShadowMaps, (int) shadowMapSize);
+    }
+
+    @Override
+    public void write(JmeExporter ex) throws IOException {
+        super.write(ex);
+        OutputCapsule oc = (OutputCapsule) ex.getCapsule(this);
+        oc.write(lambda, "lambda", 0.65f);
+        oc.write(zFarOverride, "zFarOverride", 0);
+        oc.write(light, "light", null);
+        oc.write(fadeInfo, "fadeInfo", null);
+        oc.write(fadeLength, "fadeLength", 0f);
+    }
 }

+ 3 - 10
engine/src/core/com/jme3/shadow/PointLightShadowFilter.java

@@ -37,14 +37,6 @@ import com.jme3.export.JmeExporter;
 import com.jme3.export.JmeImporter;
 import com.jme3.export.OutputCapsule;
 import com.jme3.light.PointLight;
-import com.jme3.material.Material;
-import com.jme3.math.Matrix4f;
-import com.jme3.math.Vector4f;
-import com.jme3.post.Filter;
-import com.jme3.renderer.RenderManager;
-import com.jme3.renderer.ViewPort;
-import com.jme3.renderer.queue.RenderQueue;
-import com.jme3.texture.FrameBuffer;
 import java.io.IOException;
 
 /**
@@ -72,7 +64,7 @@ public class PointLightShadowFilter extends AbstractShadowFilter<PointLightShado
      * etc...)
      */
     public PointLightShadowFilter(AssetManager assetManager, int shadowMapSize) {
-        super(assetManager, shadowMapSize,new PointLightShadowRenderer(assetManager, shadowMapSize));
+        super(assetManager, shadowMapSize, new PointLightShadowRenderer(assetManager, shadowMapSize));
     }
 
     /**
@@ -97,6 +89,7 @@ public class PointLightShadowFilter extends AbstractShadowFilter<PointLightShado
     public void write(JmeExporter ex) throws IOException {
         super.write(ex);
         OutputCapsule oc = ex.getCapsule(this);
+        oc.write(shadowRenderer, "shadowRenderer", null);
 
     }
 
@@ -104,6 +97,6 @@ public class PointLightShadowFilter extends AbstractShadowFilter<PointLightShado
     public void read(JmeImporter im) throws IOException {
         super.read(im);
         InputCapsule ic = im.getCapsule(this);
-
+        shadowRenderer = (PointLightShadowRenderer) ic.readSavable("shadowRenderer", null);
     }
 }

+ 33 - 1
engine/src/core/com/jme3/shadow/PointLightShadowRenderer.java

@@ -32,14 +32,18 @@
 package com.jme3.shadow;
 
 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.PointLight;
 import com.jme3.material.Material;
 import com.jme3.math.Vector3f;
 import com.jme3.renderer.Camera;
 import com.jme3.renderer.queue.GeometryList;
-import com.jme3.renderer.queue.OpaqueComparator;
 import com.jme3.scene.Geometry;
 import com.jme3.scene.Node;
+import java.io.IOException;
 
 /**
  * PointLightShadowRenderer renders shadows for a point light
@@ -53,6 +57,15 @@ public class PointLightShadowRenderer extends AbstractShadowRenderer {
     protected Camera[] shadowCams;
     private Geometry[] frustums = null;
 
+    /**
+     * Used for serialization use
+     * PointLightShadowRenderer"PointLightShadowRenderer(AssetManager
+     * assetManager, int shadowMapSize)
+     */
+    public PointLightShadowRenderer() {
+        super();
+    }
+
     /**
      * Creates a PointLightShadowRenderer
      *
@@ -62,6 +75,10 @@ public class PointLightShadowRenderer extends AbstractShadowRenderer {
      */
     public PointLightShadowRenderer(AssetManager assetManager, int shadowMapSize) {
         super(assetManager, shadowMapSize, CAM_NUMBER);
+        init(shadowMapSize);
+    }
+
+    private void init(int shadowMapSize) {
         shadowCams = new Camera[CAM_NUMBER];
         for (int i = 0; i < CAM_NUMBER; i++) {
             shadowCams[i] = new Camera(shadowMapSize, shadowMapSize);
@@ -159,4 +176,19 @@ public class PointLightShadowRenderer extends AbstractShadowRenderer {
     public void setLight(PointLight light) {
         this.light = light;
     }
+
+    @Override
+    public void read(JmeImporter im) throws IOException {
+        super.read(im);
+        InputCapsule ic = (InputCapsule) im.getCapsule(this);
+        light = (PointLight) ic.readSavable("light", null);
+        init((int) shadowMapSize);
+    }
+
+    @Override
+    public void write(JmeExporter ex) throws IOException {
+        super.write(ex);
+        OutputCapsule oc = (OutputCapsule) ex.getCapsule(this);
+        oc.write(light, "light", null);
+    }
 }

+ 13 - 13
engine/src/core/com/jme3/shadow/SpotLightShadowFilter.java

@@ -41,13 +41,13 @@ import java.io.IOException;
 
 /**
  *
- * This Filter does basically the same as a SpotLightShadowRenderer
- * except it renders the post shadow pass as a fulscreen quad pass instead of a
- * geometry pass. It's mostly faster than PssmShadowRenderer as long as you have
- * more than a about ten shadow recieving objects. The expense is the draw back
- * that the shadow Recieve mode set on spatial is ignored. So basically all and
- * only objects that render depth in the scene receive shadows. See this post
- * for more details
+ * This Filter does basically the same as a SpotLightShadowRenderer except it
+ * renders the post shadow pass as a fulscreen quad pass instead of a geometry
+ * pass. It's mostly faster than PssmShadowRenderer as long as you have more
+ * than a about ten shadow recieving objects. The expense is the draw back that
+ * the shadow Recieve mode set on spatial is ignored. So basically all and only
+ * objects that render depth in the scene receive shadows. See this post for
+ * more details
  * http://jmonkeyengine.org/groups/general-2/forum/topic/silly-question-about-shadow-rendering/#post-191599
  *
  * API is basically the same as the PssmShadowRenderer;
@@ -56,16 +56,15 @@ import java.io.IOException;
  */
 public class SpotLightShadowFilter extends AbstractShadowFilter<SpotLightShadowRenderer> {
 
-
     /**
-     * Creates a SpotLight Shadow Filter    
+     * Creates a SpotLight Shadow Filter
+     *
      * @param assetManager the application asset manager
      * @param shadowMapSize the size of the rendered shadowmaps (512,1024,2048,
-     * etc...)
-     * the more quality, the less fps).
+     * etc...) the more quality, the less fps).
      */
     public SpotLightShadowFilter(AssetManager assetManager, int shadowMapSize) {
-        super(assetManager, shadowMapSize, new SpotLightShadowRenderer(assetManager, shadowMapSize));     
+        super(assetManager, shadowMapSize, new SpotLightShadowRenderer(assetManager, shadowMapSize));
     }
 
     /**
@@ -131,6 +130,7 @@ public class SpotLightShadowFilter extends AbstractShadowFilter<SpotLightShadowR
     public void write(JmeExporter ex) throws IOException {
         super.write(ex);
         OutputCapsule oc = ex.getCapsule(this);
+        oc.write(shadowRenderer, "shadowRenderer", null);
 
     }
 
@@ -138,6 +138,6 @@ public class SpotLightShadowFilter extends AbstractShadowFilter<SpotLightShadowR
     public void read(JmeImporter im) throws IOException {
         super.read(im);
         InputCapsule ic = im.getCapsule(this);
-
+        shadowRenderer = (SpotLightShadowRenderer) ic.readSavable("shadowRenderer", null);
     }
 }

+ 41 - 6
engine/src/core/com/jme3/shadow/SpotLightShadowRenderer.java

@@ -32,18 +32,19 @@
 package com.jme3.shadow;
 
 import com.jme3.asset.AssetManager;
-import com.jme3.light.DirectionalLight;
+import com.jme3.export.InputCapsule;
+import com.jme3.export.JmeExporter;
+import com.jme3.export.JmeImporter;
+import com.jme3.export.OutputCapsule;
 import com.jme3.light.SpotLight;
 import com.jme3.material.Material;
-import com.jme3.math.ColorRGBA;
 import com.jme3.math.FastMath;
 import com.jme3.math.Vector2f;
 import com.jme3.math.Vector3f;
-import com.jme3.math.Vector4f;
 import com.jme3.renderer.Camera;
 import com.jme3.renderer.queue.GeometryList;
-import com.jme3.renderer.queue.OpaqueComparator;
 import com.jme3.scene.Node;
+import java.io.IOException;
 
 /**
  * SpotLightShadowRenderer renderer use Parrallel Split Shadow Mapping technique
@@ -66,6 +67,14 @@ public class SpotLightShadowRenderer extends AbstractShadowRenderer {
     protected Vector2f fadeInfo;
     protected float fadeLength;
 
+    
+    /**
+     * Used for serialization use SpotLightShadowRenderer#SpotLightShadowRenderer(AssetManager assetManager, int shadowMapSize)
+     */
+    public SpotLightShadowRenderer() {
+        super();
+    }
+    
     /**
      * Create a SpotLightShadowRenderer This use standard shadow mapping
      *
@@ -75,14 +84,17 @@ public class SpotLightShadowRenderer extends AbstractShadowRenderer {
      */
     public SpotLightShadowRenderer(AssetManager assetManager, int shadowMapSize) {
         super(assetManager, shadowMapSize, 1);
+        init(shadowMapSize);
+    }
 
+    
+    private void init(int shadowMapSize) {
         shadowCam = new Camera(shadowMapSize, shadowMapSize);
-
         for (int i = 0; i < points.length; i++) {
             points[i] = new Vector3f();
         }
     }
-
+    
     /**
      * return the light used to cast shadows
      *
@@ -213,4 +225,27 @@ public class SpotLightShadowRenderer extends AbstractShadowRenderer {
         }
         return 0f;
     }
+    
+    @Override
+    public void read(JmeImporter im) throws IOException {
+        super.read(im);
+        InputCapsule ic = (InputCapsule) im.getCapsule(this);
+        zFarOverride = ic.readInt("zFarOverride", 0);
+        light = (SpotLight) ic.readSavable("light", null);
+        fadeInfo = (Vector2f) ic.readSavable("fadeInfo", null);
+        fadeLength = ic.readFloat("fadeLength", 0f);
+        init((int) shadowMapSize);
+
+    }
+
+    @Override
+    public void write(JmeExporter ex) throws IOException {
+        super.write(ex);
+        OutputCapsule oc = (OutputCapsule) ex.getCapsule(this);        
+        oc.write(zFarOverride, "zFarOverride", 0);
+        oc.write(light, "light", null);
+        oc.write(fadeInfo, "fadeInfo", null);
+        oc.write(fadeLength, "fadeLength", 0f);
+    }
+
 }