From d8bbb4e9f9c790217419a92683c5a2476101e668 Mon Sep 17 00:00:00 2001 From: Nehon Date: Sat, 7 Jun 2014 21:26:15 +0200 Subject: [PATCH] Fixed an issue where you couldn't chain several shadow renderers. Thanks to Perjin for narrowing down the issue. Now a shadow renderer properly cleanup the parameters set to a material when the post shadow pass in done --- .../jme3/shadow/AbstractShadowRenderer.java | 34 +++- .../DirectionalLightShadowRenderer.java | 5 + .../jme3/shadow/PointLightShadowRenderer.java | 5 + .../jme3/shadow/SpotLightShadowRenderer.java | 6 + ...stPointDirectionalAndSpotLightShadows.java | 182 ++++++++++++++++++ 5 files changed, 229 insertions(+), 3 deletions(-) create mode 100644 jme3-examples/src/main/java/jme3test/light/TestPointDirectionalAndSpotLightShadows.java diff --git a/jme3-core/src/main/java/com/jme3/shadow/AbstractShadowRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/AbstractShadowRenderer.java index c81fab22a..6a9865da0 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/AbstractShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/AbstractShadowRenderer.java @@ -484,14 +484,42 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable renderManager.setForcedTechnique(null); renderManager.setForcedMaterial(null); renderManager.setCamera(cam, false); - + + //clearing the params in case there are some other shadow renderers + clearMatParams(); } } + + /** + * This method is called once per frame and is responsible for clearing any + * material parameters that subclasses may need to clear on the post material. + * + * @param material the material that was used for the post shadow pass + */ + protected abstract void clearMaterialParameters(Material material); + + private void clearMatParams(){ + for (Material mat : matCache) { + + //clearing only necessary params, the others may be set by other + //renderers + //Note that j start at 1 because other shadow renderers will have + //at least 1 shadow map and will set it on each frame anyway. + for (int j = 1; j < nbShadowMaps; j++) { + mat.clearParam(lightViewStringCache[j]); + } + for (int j = 1; j < nbShadowMaps; j++) { + mat.clearParam(shadowMapStringCache[j]); + } + clearMaterialParameters(mat); + } + //No need to clear the postShadowMat params as the instance is locale to each renderer + } /** * This method is called once per frame and is responsible for setting any - * material parameters than subclass may need to set on the post material. + * material parameters that subclasses may need to set on the post material. * * @param material the material to use for the post shadow pass */ @@ -553,7 +581,7 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable postshadowMat.setTexture(shadowMapStringCache[j], shadowMaps[j]); } } - + public void preFrame(float tpf) { } diff --git a/jme3-core/src/main/java/com/jme3/shadow/DirectionalLightShadowRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/DirectionalLightShadowRenderer.java index 060ed5ea4..e296a7085 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/DirectionalLightShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/DirectionalLightShadowRenderer.java @@ -202,6 +202,11 @@ public class DirectionalLightShadowRenderer extends AbstractShadowRenderer { material.setColor("Splits", splits); } + @Override + protected void clearMaterialParameters(Material material) { + material.clearParam("Splits"); + } + /** * returns the labda parameter see #setLambda(float lambda) * diff --git a/jme3-core/src/main/java/com/jme3/shadow/PointLightShadowRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/PointLightShadowRenderer.java index d82ee837c..c5629f84d 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/PointLightShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/PointLightShadowRenderer.java @@ -160,6 +160,11 @@ public class PointLightShadowRenderer extends AbstractShadowRenderer { material.setVector3("LightPos", light.getPosition()); } + @Override + protected void clearMaterialParameters(Material material) { + material.clearParam("LightPos"); + } + /** * gets the point light used to cast shadows with this processor * diff --git a/jme3-core/src/main/java/com/jme3/shadow/SpotLightShadowRenderer.java b/jme3-core/src/main/java/com/jme3/shadow/SpotLightShadowRenderer.java index 5432a53f0..22bee0eca 100644 --- a/jme3-core/src/main/java/com/jme3/shadow/SpotLightShadowRenderer.java +++ b/jme3-core/src/main/java/com/jme3/shadow/SpotLightShadowRenderer.java @@ -168,6 +168,12 @@ public class SpotLightShadowRenderer extends AbstractShadowRenderer { material.setVector3("LightDir", light.getDirection()); } + @Override + protected void clearMaterialParameters(Material material) { + material.clearParam("LightPos"); + material.clearParam("LightDir"); + } + /** * How far the shadows are rendered in the view * diff --git a/jme3-examples/src/main/java/jme3test/light/TestPointDirectionalAndSpotLightShadows.java b/jme3-examples/src/main/java/jme3test/light/TestPointDirectionalAndSpotLightShadows.java new file mode 100644 index 000000000..e4d8eb363 --- /dev/null +++ b/jme3-examples/src/main/java/jme3test/light/TestPointDirectionalAndSpotLightShadows.java @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.light; + +import com.jme3.app.SimpleApplication; +import com.jme3.light.DirectionalLight; +import com.jme3.light.PointLight; +import com.jme3.light.SpotLight; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.post.FilterPostProcessor; +import com.jme3.renderer.queue.RenderQueue; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.shape.Box; +import com.jme3.scene.shape.Sphere; +import com.jme3.shadow.DirectionalLightShadowFilter; +import com.jme3.shadow.DirectionalLightShadowRenderer; +import com.jme3.shadow.EdgeFilteringMode; +import com.jme3.shadow.PointLightShadowFilter; +import com.jme3.shadow.PointLightShadowRenderer; +import com.jme3.shadow.SpotLightShadowFilter; +import com.jme3.shadow.SpotLightShadowRenderer; + +public class TestPointDirectionalAndSpotLightShadows extends SimpleApplication { + public static final int SHADOWMAP_SIZE = 512; + + public static void main(String[] args) { + TestPointDirectionalAndSpotLightShadows app = new TestPointDirectionalAndSpotLightShadows(); + app.start(); + } + Node lightNode; + PointLightShadowRenderer plsr; + PointLightShadowFilter plsf; + DirectionalLightShadowRenderer dlsr; + DirectionalLightShadowFilter dlsf; + SpotLightShadowRenderer slsr; + SpotLightShadowFilter slsf; + SpotLight spotLight; + + boolean useFilter = false; + + @Override + public void simpleInitApp() { + flyCam.setMoveSpeed(10); + cam.setLocation(new Vector3f(0.040581334f, 1.7745866f, 6.155161f)); + cam.setRotation(new Quaternion(4.3868728E-5f, 0.9999293f, -0.011230096f, 0.0039059948f)); + + + Node scene = (Node) assetManager.loadModel("Models/Test/CornellBox.j3o"); + scene.setShadowMode(RenderQueue.ShadowMode.CastAndReceive); + rootNode.attachChild(scene); + rootNode.getChild("Cube").setShadowMode(RenderQueue.ShadowMode.Receive); + lightNode = (Node) rootNode.getChild("Lamp"); + Geometry lightMdl = new Geometry("Light", new Sphere(10, 10, 0.1f)); + //Geometry lightMdl = new Geometry("Light", new Box(.1f,.1f,.1f)); + lightMdl.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m")); + lightMdl.setShadowMode(RenderQueue.ShadowMode.Off); + lightNode.attachChild(lightMdl); + //lightMdl.setLocalTranslation(lightNode.getLocalTranslation()); + + + Geometry box = new Geometry("box", new Box(0.2f, 0.2f, 0.2f)); + //Geometry lightMdl = new Geometry("Light", new Box(.1f,.1f,.1f)); + box.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m")); + box.setShadowMode(RenderQueue.ShadowMode.CastAndReceive); + rootNode.attachChild(box); + box.setLocalTranslation(-1f, 0.5f, -2); + + ((PointLight) scene.getLocalLightList().get(0)).setColor(ColorRGBA.Red); + + plsr = new PointLightShadowRenderer(assetManager, SHADOWMAP_SIZE); + plsr.setLight((PointLight) scene.getLocalLightList().get(0)); + plsr.setEdgeFilteringMode(EdgeFilteringMode.PCF4); + + + + plsf = new PointLightShadowFilter(assetManager, SHADOWMAP_SIZE); + plsf.setLight((PointLight) scene.getLocalLightList().get(0)); + plsf.setEdgeFilteringMode(EdgeFilteringMode.PCF4); + plsf.setEnabled(useFilter); + + //DIRECTIONAL LIGHT + DirectionalLight directionalLight = new DirectionalLight(); + rootNode.addLight(directionalLight); + directionalLight.setColor(ColorRGBA.Blue); + directionalLight.setDirection(new Vector3f(-1f, -.2f, 0f)); + dlsr = new DirectionalLightShadowRenderer(assetManager, SHADOWMAP_SIZE*2, 4); + dlsr.setLight(directionalLight); + dlsr.setEdgeFilteringMode(EdgeFilteringMode.PCF4); + + dlsf = new DirectionalLightShadowFilter(assetManager, SHADOWMAP_SIZE*2, 4); + dlsf.setEdgeFilteringMode(EdgeFilteringMode.PCF4); + dlsf.setLight(directionalLight); + dlsf.setEnabled(useFilter); + + //SPOT LIGHT + spotLight = new SpotLight(); + spotLight.setDirection(new Vector3f(1f,-1f,0f)); + spotLight.setPosition(new Vector3f(-1f,3f,0f)); + spotLight.setSpotOuterAngle(0.5f); + spotLight.setColor(ColorRGBA.Green); + Sphere sphere = new Sphere(8, 8, .1f); + Geometry sphereGeometry = new Geometry("Sphere", sphere); + sphereGeometry.setLocalTranslation(-1f, 3f, 0f); + sphereGeometry.setMaterial(assetManager.loadMaterial("Common/Materials/WhiteColor.j3m")); + rootNode.attachChild(sphereGeometry); + rootNode.addLight(spotLight); + + slsr = new SpotLightShadowRenderer(assetManager, SHADOWMAP_SIZE); + slsr.setLight(spotLight); + slsr.setEdgeFilteringMode(EdgeFilteringMode.PCF4); + + slsf = new SpotLightShadowFilter(assetManager, SHADOWMAP_SIZE); + slsf.setLight(spotLight); + slsf.setEdgeFilteringMode(EdgeFilteringMode.PCF4); + slsf.setEnabled(useFilter); + + + + slsr.setFlushQueues(false); + plsr.setFlushQueues(false); + dlsr.setFlushQueues(true); + slsf.setFlushQueues(false); + plsf.setFlushQueues(false); + dlsf.setFlushQueues(true); + if (!useFilter)viewPort.addProcessor(slsr); + if (!useFilter)viewPort.addProcessor(plsr); + if (!useFilter)viewPort.addProcessor(dlsr); + + FilterPostProcessor fpp = new FilterPostProcessor(assetManager); + fpp.addFilter(plsf); + fpp.addFilter(dlsf); + fpp.addFilter(slsf); + viewPort.addProcessor(fpp); + + ShadowTestUIManager uiMan = new ShadowTestUIManager(assetManager, plsr, plsf, guiNode, inputManager, viewPort); + ShadowTestUIManager uiManPls = new ShadowTestUIManager(assetManager, plsr, plsf, guiNode, inputManager, viewPort); + ShadowTestUIManager uiManDls = new ShadowTestUIManager(assetManager, dlsr, dlsf, guiNode, inputManager, viewPort); + ShadowTestUIManager uiManSls = new ShadowTestUIManager(assetManager, slsr, slsf, guiNode, inputManager, viewPort); + + } + + float timeElapsed = 0.0f; + @Override + public void simpleUpdate(float tpf) { + timeElapsed += tpf; + lightNode.setLocalTranslation(FastMath.cos(timeElapsed), lightNode.getLocalTranslation().y, FastMath.sin(timeElapsed)); + spotLight.setDirection(new Vector3f(FastMath.cos(-timeElapsed*.7f), -1.0f, FastMath.sin(-timeElapsed*.7f))); + } +} \ No newline at end of file