All shadow renderers/filters are now properly savables

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@10005 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
3.0
rem..om 12 years ago
parent dd2b82c881
commit b88350a069
  1. 111
      engine/src/core/com/jme3/shadow/AbstractShadowRenderer.java
  2. 5
      engine/src/core/com/jme3/shadow/DirectionalLightShadowFilter.java
  3. 47
      engine/src/core/com/jme3/shadow/DirectionalLightShadowRenderer.java
  4. 13
      engine/src/core/com/jme3/shadow/PointLightShadowFilter.java
  5. 34
      engine/src/core/com/jme3/shadow/PointLightShadowRenderer.java
  6. 22
      engine/src/core/com/jme3/shadow/SpotLightShadowFilter.java
  7. 45
      engine/src/core/com/jme3/shadow/SpotLightShadowRenderer.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;
@ -80,8 +87,8 @@ public abstract class AbstractShadowRenderer implements SceneProcessor {
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,14 +158,14 @@ 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
*/
protected final void setPostShadowMaterial(Material 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,30 +307,37 @@ 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
*/
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
* 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
@ -407,7 +431,7 @@ public abstract class AbstractShadowRenderer implements SceneProcessor {
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);
}
}

@ -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
@ -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);
}
}

@ -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
@ -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();
}
@ -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);
}
}

@ -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);
}
}

@ -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);
}
}

@ -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,13 +56,12 @@ import java.io.IOException;
*/
public class SpotLightShadowFilter extends AbstractShadowFilter<SpotLightShadowRenderer> {
/**
* 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));
@ -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);
}
}

@ -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,9 +84,12 @@ public class SpotLightShadowRenderer extends AbstractShadowRenderer {
*/
public SpotLightShadowRenderer(AssetManager assetManager, int shadowMapSize) {
super(assetManager, shadowMapSize, 1);
init(shadowMapSize);
}
shadowCam = new Camera(shadowMapSize, shadowMapSize);
private void init(int shadowMapSize) {
shadowCam = new Camera(shadowMapSize, shadowMapSize);
for (int i = 0; i < points.length; i++) {
points[i] = new Vector3f();
}
@ -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);
}
}

Loading…
Cancel
Save