Browse Source

Merge branch 'master' of https://github.com/jMonkeyEngine/jmonkeyengine.git

jmekaelthas 9 years ago
parent
commit
a9a1544681

+ 46 - 1
jme3-core/src/main/java/com/jme3/shadow/AbstractShadowFilter.java

@@ -37,6 +37,7 @@ import com.jme3.export.JmeExporter;
 import com.jme3.export.JmeImporter;
 import com.jme3.export.OutputCapsule;
 import com.jme3.material.Material;
+import com.jme3.material.RenderState;
 import com.jme3.math.Matrix4f;
 import com.jme3.math.Vector4f;
 import com.jme3.post.Filter;
@@ -44,6 +45,7 @@ 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;
 
 /**
@@ -74,6 +76,9 @@ public abstract class AbstractShadowFilter<T extends AbstractShadowRenderer> ext
         material = new Material(manager, "Common/MatDefs/Shadow/PostShadowFilter.j3md");       
         this.shadowRenderer = shadowRenderer;
         this.shadowRenderer.setPostShadowMaterial(material);
+
+        //this is legacy setting for shadows with backface shadows
+        this.shadowRenderer.setRenderBackFacesShadows(true);
     }
 
     @Override
@@ -126,7 +131,7 @@ public abstract class AbstractShadowFilter<T extends AbstractShadowRenderer> ext
       /**
      * How far the shadows are rendered in the view
      *
-     * @see setShadowZExtend(float zFar)
+     * @see #setShadowZExtend(float zFar)
      * @return shadowZExtend
      */
     public float getShadowZExtend() {
@@ -248,6 +253,46 @@ public abstract class AbstractShadowFilter<T extends AbstractShadowRenderer> ext
         shadowRenderer.setEdgeFilteringMode(filterMode);
     }
 
+    /**
+     *
+     * !! WARNING !! this parameter is defaulted to true for the ShadowFilter.
+     * Setting it to true, may produce edges artifacts on shadows.     *
+     *
+     * Set to true if you want back faces shadows on geometries.
+     * Note that back faces shadows will be blended over dark lighten areas and may produce overly dark lighting.
+     *
+     * Setting this parameter will override this parameter for ALL materials in the scene.
+     * This also will automatically adjust the faceCullMode and the PolyOffset of the pre shadow pass.
+     * You can modify them by using {@link #getPreShadowForcedRenderState()}
+     *
+     * If you want to set it differently for each material in the scene you have to use the ShadowRenderer instead
+     * of the shadow filter.
+     *
+     * @param renderBackFacesShadows true or false.
+     */
+    public void setRenderBackFacesShadows(Boolean renderBackFacesShadows) {
+        shadowRenderer.setRenderBackFacesShadows(renderBackFacesShadows);
+    }
+
+    /**
+     * if this filter renders back faces shadows
+     * @return true if this filter renders back faces shadows
+     */
+    public boolean isRenderBackFacesShadows() {
+        return shadowRenderer.isRenderBackFacesShadows();
+    }
+
+    /**
+     * returns the pre shadows pass render state.
+     * use it to adjust the RenderState parameters of the pre shadow pass.
+     * Note that this will be overriden if the preShadow technique in the material has a ForcedRenderState
+     * @return the pre shadow render state.
+     */
+    public RenderState getPreShadowForcedRenderState() {
+        return shadowRenderer.getPreShadowForcedRenderState();
+    }
+
+
     /**
      * returns the the edge filtering mode
      *

+ 84 - 20
jme3-core/src/main/java/com/jme3/shadow/AbstractShadowRenderer.java

@@ -31,10 +31,6 @@
  */
 package com.jme3.shadow;
 
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
 import com.jme3.asset.AssetManager;
 import com.jme3.export.InputCapsule;
 import com.jme3.export.JmeExporter;
@@ -42,6 +38,7 @@ import com.jme3.export.JmeImporter;
 import com.jme3.export.OutputCapsule;
 import com.jme3.export.Savable;
 import com.jme3.material.Material;
+import com.jme3.material.RenderState;
 import com.jme3.math.ColorRGBA;
 import com.jme3.math.Matrix4f;
 import com.jme3.math.Vector2f;
@@ -67,6 +64,10 @@ 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
@@ -92,6 +93,8 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
     protected EdgeFilteringMode edgeFilteringMode = EdgeFilteringMode.Bilinear;
     protected CompareMode shadowCompareMode = CompareMode.Hardware;
     protected Picture[] dispPic;
+    protected RenderState forcedRenderState = new RenderState();
+    protected Boolean renderBackFacesShadows;
 
     /**
      * true if the fallback material should be used, otherwise false
@@ -182,6 +185,14 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
         setShadowCompareMode(shadowCompareMode);
         setEdgeFilteringMode(edgeFilteringMode);
         setShadowIntensity(shadowIntensity);
+        initForcedRenderState();
+    }
+
+    protected void initForcedRenderState() {
+        forcedRenderState.setFaceCullMode(RenderState.FaceCullMode.Front);
+        forcedRenderState.setColorWrite(false);
+        forcedRenderState.setDepthWrite(true);
+        forcedRenderState.setDepthTest(true);
     }
 
     /**
@@ -357,9 +368,7 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
      * 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 receivers of the whole scene
-     * @param shadowMapOcculders
+     * @param shadowMapOccluders the list of occluders
      * @return
      */
     protected abstract GeometryList getOccludersToRender(int shadowMapIndex, GeometryList shadowMapOccluders);
@@ -426,9 +435,11 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
 
         renderManager.getRenderer().setFrameBuffer(shadowFB[shadowMapIndex]);
         renderManager.getRenderer().clearBuffers(true, true, true);
+        renderManager.setForcedRenderState(forcedRenderState);
 
         // render shadow casters to shadow map
         viewPort.getQueue().renderShadowQueue(shadowMapOccluders, renderManager, shadowCam, true);
+        renderManager.setForcedRenderState(null);
     }
     boolean debugfrustums = false;
 
@@ -536,18 +547,7 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
     private void setMatParams(GeometryList l) {
         //iteration throught all the geometries of the list to gather the materials
 
-        matCache.clear();
-        for (int i = 0; i < l.size(); i++) {
-            Material mat = l.get(i).getMaterial();
-            //checking if the material has the post technique and adding it to the material cache
-            if (mat.getMaterialDef().getTechniqueDef(postTechniqueName) != null) {
-                if (!matCache.contains(mat)) {
-                    matCache.add(mat);
-                }
-            } else {
-                needsfallBackMaterial = true;
-            }
-        }
+        buildMatCache(l);
 
         //iterating through the mat cache and setting the parameters
         for (Material mat : matCache) {
@@ -567,6 +567,10 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
             if (fadeInfo != null) {
                mat.setVector2("FadeInfo", fadeInfo);
             }
+            if(renderBackFacesShadows != null){
+                mat.setBoolean("BackfaceShadows", renderBackFacesShadows);
+            }
+
             setMaterialParameters(mat);
         }
 
@@ -578,6 +582,21 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
 
     }
 
+    private void buildMatCache(GeometryList l) {
+        matCache.clear();
+        for (int i = 0; i < l.size(); i++) {
+            Material mat = l.get(i).getMaterial();
+            //checking if the material has the post technique and adding it to the material cache
+            if (mat.getMaterialDef().getTechniqueDef(postTechniqueName) != null) {
+                if (!matCache.contains(mat)) {
+                    matCache.add(mat);
+                }
+            } else {
+                needsfallBackMaterial = true;
+            }
+        }
+    }
+
     /**
      * for internal use only
      */
@@ -588,7 +607,10 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
             postshadowMat.setTexture(shadowMapStringCache[j], shadowMaps[j]);
         }
         if (fadeInfo != null) {
-              postshadowMat.setVector2("FadeInfo", fadeInfo);
+            postshadowMat.setVector2("FadeInfo", fadeInfo);
+        }
+        if(renderBackFacesShadows != null){
+            postshadowMat.setBoolean("BackfaceShadows", renderBackFacesShadows);
         }
     }
     
@@ -731,6 +753,48 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
     @Deprecated
     public void setFlushQueues(boolean flushQueues) {}
 
+
+    /**
+     * returns the pre shadows pass render state.
+     * use it to adjust the RenderState parameters of the pre shadow pass.
+     * Note that this will be overriden if the preShadow technique in the material has a ForcedRenderState
+     * @return the pre shadow render state.
+     */
+    public RenderState getPreShadowForcedRenderState() {
+        return forcedRenderState;
+    }
+
+    /**
+     * Set to true if you want back faces shadows on geometries.
+     * Note that back faces shadows will be blended over dark lighten areas and may produce overly dark lighting.
+     *
+     * Also note that setting this parameter will override this parameter for ALL materials in the scene.
+     * You can alternatively change this parameter on a single material using {@link Material#setBoolean(String, boolean)}
+     *
+     * This also will automatically adjust the faceCullMode and the PolyOffset of the pre shadow pass.
+     * You can modify them by using {@link #getPreShadowForcedRenderState()}
+     *
+     * @param renderBackFacesShadows true or false.
+     */
+    public void setRenderBackFacesShadows(Boolean renderBackFacesShadows) {
+        this.renderBackFacesShadows = renderBackFacesShadows;
+        if(renderBackFacesShadows) {
+            getPreShadowForcedRenderState().setPolyOffset(5, 3);
+            getPreShadowForcedRenderState().setFaceCullMode(RenderState.FaceCullMode.Back);
+        }else{
+            getPreShadowForcedRenderState().setPolyOffset(0, 0);
+            getPreShadowForcedRenderState().setFaceCullMode(RenderState.FaceCullMode.Front);
+        }
+    }
+
+    /**
+     * if this processor renders back faces shadows
+     * @return true if this processor renders back faces shadows
+     */
+    public boolean isRenderBackFacesShadows() {
+        return renderBackFacesShadows != null?renderBackFacesShadows:false;
+    }
+
     /**
      * De-serialize this instance, for example when loading from a J3O file.
      *

+ 2 - 0
jme3-core/src/main/java/com/jme3/shadow/DirectionalLightShadowRenderer.java

@@ -215,6 +215,7 @@ public class DirectionalLightShadowRenderer extends AbstractShadowRenderer {
     @Override
     protected void setMaterialParameters(Material material) {
         material.setColor("Splits", splits);
+        material.setVector3("LightDir", light.getDirection());
         if (fadeInfo != null) {
             material.setVector2("FadeInfo", fadeInfo);
         }
@@ -224,6 +225,7 @@ public class DirectionalLightShadowRenderer extends AbstractShadowRenderer {
     protected void clearMaterialParameters(Material material) {
         material.clearParam("Splits");
         material.clearParam("FadeInfo");
+        material.clearParam("LightDir");
     }
 
     /**

+ 5 - 8
jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md

@@ -113,6 +113,8 @@ MaterialDef Phong Lighting {
                 
         //For instancing
         Boolean UseInstancing
+
+        Boolean BackfaceShadows: false
     }
 
  Technique {
@@ -213,14 +215,6 @@ MaterialDef Phong Lighting {
             INSTANCING : UseInstancing
         }
 
-        ForcedRenderState {
-            FaceCull Off
-            DepthTest On
-            DepthWrite On
-            PolyOffset 5 3
-            ColorWrite Off
-        }
-
     }
 
 
@@ -233,6 +227,7 @@ MaterialDef Phong Lighting {
             WorldMatrix
             ViewProjectionMatrix
             ViewMatrix
+            NormalMatrix
         }
 
         Defines {
@@ -247,6 +242,7 @@ MaterialDef Phong Lighting {
             POINTLIGHT : LightViewProjectionMatrix5
             NUM_BONES : NumberOfBones
             INSTANCING : UseInstancing
+            BACKFACE_SHADOWS: BackfaceShadows
         }
 
         ForcedRenderState {
@@ -265,6 +261,7 @@ MaterialDef Phong Lighting {
             WorldMatrix
             ViewProjectionMatrix
             ViewMatrix
+            NormalMatrix
         }
 
         Defines {

+ 4 - 0
jme3-core/src/main/resources/Common/MatDefs/Misc/Unshaded.j3md

@@ -51,6 +51,8 @@ MaterialDef Unshaded {
         Float PCFEdge
 
         Float ShadowMapSize
+
+        Boolean BackfaceShadows: true
     }
 
     Technique {
@@ -169,6 +171,7 @@ MaterialDef Unshaded {
             POINTLIGHT : LightViewProjectionMatrix5
             NUM_BONES : NumberOfBones
 	    INSTANCING : UseInstancing
+	        BACKFACE_SHADOWS: BackfaceShadows
         }
 
         ForcedRenderState {
@@ -201,6 +204,7 @@ MaterialDef Unshaded {
             POINTLIGHT : LightViewProjectionMatrix5
             NUM_BONES : NumberOfBones
             INSTANCING : UseInstancing
+            BACKFACE_SHADOWS: BackfaceShadows
         }
 
         ForcedRenderState {

+ 13 - 4
jme3-core/src/main/resources/Common/MatDefs/Shadow/PostShadow.frag

@@ -9,6 +9,9 @@ varying vec4 projCoord0;
 varying vec4 projCoord1;
 varying vec4 projCoord2;
 varying vec4 projCoord3;
+#ifndef BACKFACE_SHADOWS
+    varying float nDotL;
+#endif
 
 #ifdef POINTLIGHT
     varying vec4 projCoord4;
@@ -46,9 +49,15 @@ void main(){
         if(alpha<=m_AlphaDiscardThreshold){
             discard;
         }
+    #endif
 
+    #ifndef BACKFACE_SHADOWS
+        if(nDotL > 0.0){
+            discard;
+        }
     #endif
-     
+
+
     float shadow = 1.0;
  
     #ifdef POINTLIGHT         
@@ -71,11 +80,11 @@ void main(){
     #endif   
 
     #ifdef FADE
-      shadow = max(0.0,mix(shadow,1.0,(shadowPosition - m_FadeInfo.x) * m_FadeInfo.y));    
+        shadow = max(0.0,mix(shadow,1.0,(shadowPosition - m_FadeInfo.x) * m_FadeInfo.y));
     #endif
-    shadow = shadow * m_ShadowIntensity + (1.0 - m_ShadowIntensity);
 
-  gl_FragColor = vec4(shadow, shadow, shadow, 1.0);
+    shadow = shadow * m_ShadowIntensity + (1.0 - m_ShadowIntensity);
+    gl_FragColor = vec4(shadow, shadow, shadow, 1.0);
 
 }
 

+ 4 - 0
jme3-core/src/main/resources/Common/MatDefs/Shadow/PostShadow.j3md

@@ -29,6 +29,8 @@ MaterialDef Post Shadow {
         Float PCFEdge
 
         Float ShadowMapSize
+
+        Boolean BackfaceShadows: false
 		
     }
 
@@ -49,6 +51,7 @@ MaterialDef Post Shadow {
             FADE : FadeInfo
             PSSM : Splits
             POINTLIGHT : LightViewProjectionMatrix5
+            BACKFACE_SHADOWS: BackfaceShadows
         }
 
         RenderState {
@@ -75,6 +78,7 @@ MaterialDef Post Shadow {
             FADE : FadeInfo
             PSSM : Splits
             POINTLIGHT : LightViewProjectionMatrix5
+            BACKFACE_SHADOWS: BackfaceShadows
         }
 
         RenderState {

+ 25 - 7
jme3-core/src/main/resources/Common/MatDefs/Shadow/PostShadow.vert

@@ -7,7 +7,6 @@ uniform mat4 m_LightViewProjectionMatrix1;
 uniform mat4 m_LightViewProjectionMatrix2;
 uniform mat4 m_LightViewProjectionMatrix3;
 
-uniform vec3 m_LightPos; 
 
 varying vec4 projCoord0;
 varying vec4 projCoord1;
@@ -17,12 +16,14 @@ varying vec4 projCoord3;
 #ifdef POINTLIGHT
     uniform mat4 m_LightViewProjectionMatrix4;
     uniform mat4 m_LightViewProjectionMatrix5;
+    uniform vec3 m_LightPos;
     varying vec4 projCoord4;
     varying vec4 projCoord5;
     varying vec4 worldPos;
 #else
+    uniform vec3 m_LightDir;
     #ifndef PSSM
-        uniform vec3 m_LightDir; 
+        uniform vec3 m_LightPos;
         varying float lightDot;
     #endif
 #endif
@@ -30,12 +31,15 @@ varying vec4 projCoord3;
 #if defined(PSSM) || defined(FADE)
 varying float shadowPosition;
 #endif
-varying vec3 lightVec;
 
 varying vec2 texCoord;
-
 attribute vec3 inPosition;
 
+#ifndef BACKFACE_SHADOWS
+    attribute vec3 inNormal;
+    varying float nDotL;
+#endif
+
 #ifdef DISCARD_ALPHA
     attribute vec2 inTexCoord;
 #endif
@@ -53,16 +57,17 @@ void main(){
        Skinning_Compute(modelSpacePos);
    #endif
     gl_Position = TransformWorldViewProjection(modelSpacePos);
+    vec3 lightDir;
 
     #if defined(PSSM) || defined(FADE)
-         shadowPosition = gl_Position.z;
+        shadowPosition = gl_Position.z;
     #endif  
 
     #ifndef POINTLIGHT
         vec4 worldPos=vec4(0.0);
     #endif
     // get the vertex in world space
-    worldPos = g_WorldMatrix * modelSpacePos;
+    worldPos = TransformWorld(modelSpacePos);
 
     #ifdef DISCARD_ALPHA
        texCoord = inTexCoord;
@@ -77,8 +82,21 @@ void main(){
         projCoord5 = biasMat * m_LightViewProjectionMatrix5 * worldPos;
     #else
         #ifndef PSSM
-            vec3 lightDir = worldPos.xyz - m_LightPos;
+            //Spot light
+            lightDir = worldPos.xyz - m_LightPos;
             lightDot = dot(m_LightDir,lightDir);
         #endif
     #endif
+
+    #ifndef BACKFACE_SHADOWS
+        vec3 normal = normalize(TransformWorld(vec4(inNormal,0.0))).xyz;
+        #ifdef POINTLIGHT
+            lightDir = worldPos.xyz - m_LightPos;
+        #else
+            #ifdef PSSM
+               lightDir = m_LightDir;
+            #endif
+        #endif
+        nDotL = dot(normal, lightDir);
+    #endif
 }

+ 29 - 0
jme3-core/src/main/resources/Common/MatDefs/Shadow/PostShadowFilter.frag

@@ -18,6 +18,8 @@ uniform mat4 m_LightViewProjectionMatrix1;
 uniform mat4 m_LightViewProjectionMatrix2;
 uniform mat4 m_LightViewProjectionMatrix3;
 
+uniform vec2 g_ResolutionInverse;
+
 #ifdef POINTLIGHT
     uniform vec3 m_LightPos;
     uniform mat4 m_LightViewProjectionMatrix4;
@@ -39,6 +41,19 @@ vec3 getPosition(in float depth, in vec2 uv){
     return pos.xyz / pos.w;
 }
 
+vec3 approximateNormal(in vec4 worldPos,in vec2 texCoord){
+    float step = g_ResolutionInverse.x ;
+    float stepy = g_ResolutionInverse.y ;
+    float depth2 = texture2D(m_DepthTexture,texCoord + vec2(step,-stepy)).r;
+    float depth3 = texture2D(m_DepthTexture,texCoord + vec2(-step,-stepy)).r;
+    vec4 worldPos2 = vec4(getPosition(depth2,texCoord + vec2(step,-stepy)),1.0);
+    vec4 worldPos3 = vec4(getPosition(depth3,texCoord + vec2(-step,-stepy)),1.0);
+
+    vec3 v1 = (worldPos - worldPos2).xyz;
+    vec3 v2 = (worldPos3 - worldPos2).xyz;
+    return normalize(cross(v1, v2));
+}
+
 void main(){    
     #if !defined( RENDER_SHADOWS )
           gl_FragColor = texture2D(m_Texture,texCoord);
@@ -48,6 +63,7 @@ void main(){
     float depth = texture2D(m_DepthTexture,texCoord).r;
     vec4 color = texture2D(m_Texture,texCoord);
 
+
     //Discard shadow computation on the sky
     if(depth == 1.0){
         gl_FragColor = color;
@@ -56,6 +72,19 @@ void main(){
 
     // get the vertex in world space
     vec4 worldPos = vec4(getPosition(depth,texCoord),1.0);
+    vec3 normal = approximateNormal(worldPos, texCoord);
+
+    vec3 lightDir;
+    #ifdef PSSM
+        lightDir = m_LightDir;
+    #else
+        lightDir = worldPos.xyz - m_LightPos;
+    #endif
+    float ndotl = dot(normal, lightDir);
+    if(ndotl > -0.0){
+        gl_FragColor = color;
+        return;
+    }
    
      #if (!defined(POINTLIGHT) && !defined(PSSM))
           vec3 lightDir = worldPos.xyz - m_LightPos;

+ 7 - 3
jme3-core/src/main/resources/Common/MatDefs/Shadow/PostShadowFilter.j3md

@@ -38,13 +38,15 @@ MaterialDef Post Shadow {
         Texture2D Texture        
         Texture2D DepthTexture
 
+        Boolean BackfaceShadows: true
     }
 
     Technique {
         VertexShader GLSL150:   Common/MatDefs/Shadow/PostShadowFilter15.vert
         FragmentShader GLSL150: Common/MatDefs/Shadow/PostShadowFilter15.frag
 
-        WorldParameters {           
+        WorldParameters {
+            ResolutionInverse
         }
 
         Defines {
@@ -59,7 +61,7 @@ MaterialDef Post Shadow {
             POINTLIGHT : LightViewProjectionMatrix5
             //if no shadow map don't render shadows
             RENDER_SHADOWS : ShadowMap0
-
+            BACKFACE_SHADOWS : BackfaceShadows
         }
       
     }
@@ -68,7 +70,8 @@ MaterialDef Post Shadow {
         VertexShader GLSL100:   Common/MatDefs/Shadow/PostShadowFilter.vert
         FragmentShader GLSL100: Common/MatDefs/Shadow/PostShadowFilter.frag
 
-        WorldParameters {         
+        WorldParameters {
+            ResolutionInverse
         }
 
         Defines {
@@ -79,6 +82,7 @@ MaterialDef Post Shadow {
             FADE : FadeInfo
             PSSM : Splits
             POINTLIGHT : LightViewProjectionMatrix5
+            BACKFACE_SHADOWS : BackfaceShadows
         }
       
     }

+ 41 - 7
jme3-core/src/main/resources/Common/MatDefs/Shadow/PostShadowFilter15.frag

@@ -20,14 +20,16 @@ uniform mat4 m_LightViewProjectionMatrix1;
 uniform mat4 m_LightViewProjectionMatrix2;
 uniform mat4 m_LightViewProjectionMatrix3;
 
+uniform vec2 g_ResolutionInverse;
+
 #ifdef POINTLIGHT
     uniform vec3 m_LightPos;
     uniform mat4 m_LightViewProjectionMatrix4;
     uniform mat4 m_LightViewProjectionMatrix5;
 #else
+    uniform vec3 m_LightDir;
     #ifndef PSSM    
-        uniform vec3 m_LightPos;    
-        uniform vec3 m_LightDir;       
+        uniform vec3 m_LightPos;
     #endif
 #endif
 
@@ -41,6 +43,23 @@ vec3 getPosition(in float depth, in vec2 uv){
     return pos.xyz / pos.w;
 }
 
+#ifndef BACKFACE_SHADOWS
+    vec3 approximateNormal(in float depth,in vec4 worldPos,in vec2 texCoord, in int numSample){
+        float step = g_ResolutionInverse.x ;
+        float stepy = g_ResolutionInverse.y ;
+        float depth1 = fetchTextureSample(m_DepthTexture,texCoord + vec2(-step,stepy),numSample).r;
+        float depth2 = fetchTextureSample(m_DepthTexture,texCoord + vec2(step,stepy),numSample).r;
+        vec3 v1, v2;
+        vec4 worldPos1 = vec4(getPosition(depth1,texCoord + vec2(-step,stepy)),1.0);
+        vec4 worldPos2 = vec4(getPosition(depth2,texCoord + vec2(step,stepy)),1.0);
+
+        v1 = normalize((worldPos1 - worldPos)).xyz;
+        v2 =  normalize((worldPos2 - worldPos)).xyz;
+        return normalize(cross(v2, v1));
+
+    }
+#endif
+
 vec4 main_multiSample(in int numSample){
     float depth = fetchTextureSample(m_DepthTexture,texCoord,numSample).r;//getDepth(m_DepthTexture,texCoord).r;
     vec4 color = fetchTextureSample(m_Texture,texCoord,numSample);
@@ -52,12 +71,27 @@ vec4 main_multiSample(in int numSample){
     
     // get the vertex in world space
     vec4 worldPos = vec4(getPosition(depth,texCoord),1.0);
-  
+
+
+    vec3 lightDir;
+    #ifdef PSSM
+        lightDir = m_LightDir;
+    #else
+        lightDir = worldPos.xyz - m_LightPos;
+    #endif
+
+    #ifndef BACKFACE_SHADOWS
+        vec3 normal = approximateNormal(depth, worldPos, texCoord, numSample);
+        float ndotl = dot(normal, lightDir);
+        if(ndotl > 0.0){
+            return color;
+        }
+    #endif
+
     #if (!defined(POINTLIGHT) && !defined(PSSM))
-          vec3 lightDir = worldPos.xyz - m_LightPos;
-          if( dot(m_LightDir,lightDir)<0){
-             return color;
-          }         
+        if( dot(m_LightDir,lightDir)<0){
+         return color;
+        }
     #endif
 
     // populate the light view matrices array and convert vertex to light viewProj space

+ 29 - 10
jme3-examples/src/main/java/jme3test/light/TestDirectionalLightShadow.java

@@ -40,12 +40,14 @@ import com.jme3.input.controls.KeyTrigger;
 import com.jme3.light.AmbientLight;
 import com.jme3.light.DirectionalLight;
 import com.jme3.material.Material;
+import com.jme3.material.RenderState;
 import com.jme3.math.ColorRGBA;
 import com.jme3.math.FastMath;
 import com.jme3.math.Quaternion;
 import com.jme3.math.Vector2f;
 import com.jme3.math.Vector3f;
 import com.jme3.post.FilterPostProcessor;
+import com.jme3.post.ssao.SSAOFilter;
 import com.jme3.renderer.queue.RenderQueue.ShadowMode;
 import com.jme3.scene.Geometry;
 import com.jme3.scene.Spatial;
@@ -69,6 +71,7 @@ public class TestDirectionalLightShadow extends SimpleApplication implements Act
     private Geometry ground;
     private Material matGroundU;
     private Material matGroundL;
+    private AmbientLight al;
 
     public static void main(String[] args) {
         TestDirectionalLightShadow app = new TestDirectionalLightShadow();
@@ -99,7 +102,7 @@ public class TestDirectionalLightShadow extends SimpleApplication implements Act
         mat[0] = assetManager.loadMaterial("Common/Materials/RedColor.j3m");
         mat[1] = assetManager.loadMaterial("Textures/Terrain/Pond/Pond.j3m");
         mat[1].setBoolean("UseMaterialColors", true);
-        mat[1].setColor("Ambient", ColorRGBA.White.mult(0.5f));
+        mat[1].setColor("Ambient", ColorRGBA.White);
         mat[1].setColor("Diffuse", ColorRGBA.White.clone());
 
 
@@ -110,9 +113,14 @@ public class TestDirectionalLightShadow extends SimpleApplication implements Act
         TangentBinormalGenerator.generate(obj[1]);
         TangentBinormalGenerator.generate(obj[0]);
 
+        Spatial t = obj[0].clone(false);
+        t.setLocalScale(10f);
+        t.setMaterial(mat[1]);
+        rootNode.attachChild(t);
+        t.setLocalTranslation(0, 25, 0);
 
         for (int i = 0; i < 60; i++) {
-            Spatial t = obj[FastMath.nextRandomInt(0, obj.length - 1)].clone(false);
+            t = obj[FastMath.nextRandomInt(0, obj.length - 1)].clone(false);
             t.setLocalScale(FastMath.nextRandomFloat() * 10f);
             t.setMaterial(mat[FastMath.nextRandomInt(0, mat.length - 1)]);
             rootNode.attachChild(t);
@@ -142,8 +150,8 @@ public class TestDirectionalLightShadow extends SimpleApplication implements Act
         rootNode.addLight(l);
 
 
-        AmbientLight al = new AmbientLight();
-        al.setColor(ColorRGBA.White.mult(0.5f));
+        al = new AmbientLight();
+        al.setColor(ColorRGBA.White.mult(0.02f));
         rootNode.addLight(al);
 
         Spatial sky = SkyFactory.createSky(assetManager, "Scenes/Beach/FullskiesSunset0068.dds", false);
@@ -156,8 +164,11 @@ public class TestDirectionalLightShadow extends SimpleApplication implements Act
     @Override
     public void simpleInitApp() {
         // put the camera in a bad position
-        cam.setLocation(new Vector3f(65.25412f, 44.38738f, 9.087874f));
-        cam.setRotation(new Quaternion(0.078139365f, 0.050241485f, -0.003942559f, 0.9956679f));
+//        cam.setLocation(new Vector3f(65.25412f, 44.38738f, 9.087874f));
+//        cam.setRotation(new Quaternion(0.078139365f, 0.050241485f, -0.003942559f, 0.9956679f));
+
+        cam.setLocation(new Vector3f(3.3720117f, 42.838284f, -83.43792f));
+        cam.setRotation(new Quaternion(0.13833192f, -0.08969371f, 0.012581267f, 0.9862358f));
 
         flyCam.setMoveSpeed(100);
 
@@ -166,7 +177,7 @@ public class TestDirectionalLightShadow extends SimpleApplication implements Act
         dlsr = new DirectionalLightShadowRenderer(assetManager, SHADOWMAP_SIZE, 3);
         dlsr.setLight(l);
         dlsr.setLambda(0.55f);
-        dlsr.setShadowIntensity(0.6f);
+        dlsr.setShadowIntensity(0.8f);
         dlsr.setEdgeFilteringMode(EdgeFilteringMode.Nearest);
         dlsr.displayDebug();
         viewPort.addProcessor(dlsr);
@@ -174,7 +185,7 @@ public class TestDirectionalLightShadow extends SimpleApplication implements Act
         dlsf = new DirectionalLightShadowFilter(assetManager, SHADOWMAP_SIZE, 3);
         dlsf.setLight(l);
         dlsf.setLambda(0.55f);
-        dlsf.setShadowIntensity(0.6f);
+        dlsf.setShadowIntensity(0.8f);
         dlsf.setEdgeFilteringMode(EdgeFilteringMode.Nearest);
         dlsf.setEnabled(false);
 
@@ -205,10 +216,11 @@ public class TestDirectionalLightShadow extends SimpleApplication implements Act
         inputManager.addMapping("fwd", new KeyTrigger(KeyInput.KEY_PGUP));
         inputManager.addMapping("back", new KeyTrigger(KeyInput.KEY_PGDN));
         inputManager.addMapping("pp", new KeyTrigger(KeyInput.KEY_P));
+        inputManager.addMapping("backShadows", new KeyTrigger(KeyInput.KEY_B));
 
 
         inputManager.addListener(this, "lambdaUp", "lambdaDown", "ThicknessUp", "ThicknessDown",
-                "switchGroundMat", "debug", "up", "down", "right", "left", "fwd", "back", "pp", "stabilize", "distance");
+                "switchGroundMat", "debug", "up", "down", "right", "left", "fwd", "back", "pp", "stabilize", "distance", "ShadowUp", "ShadowDown", "backShadows");
 
         ShadowTestUIManager uiMan = new ShadowTestUIManager(assetManager, dlsr, dlsf, guiNode, inputManager, viewPort);
 
@@ -255,12 +267,19 @@ public class TestDirectionalLightShadow extends SimpleApplication implements Act
             dlsf.setLambda(dlsr.getLambda() - 0.01f);
             System.out.println("Lambda : " + dlsr.getLambda());
         }
-
+        if ((name.equals("ShadowUp") || name.equals("ShadowDown")) && keyPressed) {
+            al.setColor(ColorRGBA.White.mult((1 - dlsr.getShadowIntensity()) * 0.2f));
+        }
 
         if (name.equals("debug") && keyPressed) {
             dlsr.displayFrustum();
         }
 
+        if (name.equals("backShadows") && keyPressed) {
+            dlsr.setRenderBackFacesShadows(!dlsr.isRenderBackFacesShadows());
+            dlsf.setRenderBackFacesShadows(!dlsf.isRenderBackFacesShadows());
+        }
+
         if (name.equals("stabilize") && keyPressed) {
             dlsr.setEnabledStabilization(!dlsr.isEnabledStabilization());
             dlsf.setEnabledStabilization(!dlsf.isEnabledStabilization());

+ 23 - 4
jme3-examples/src/main/java/jme3test/light/TestPointLightShadows.java

@@ -32,7 +32,10 @@
 package jme3test.light;
 
 import com.jme3.app.SimpleApplication;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.light.AmbientLight;
 import com.jme3.light.PointLight;
+import com.jme3.math.ColorRGBA;
 import com.jme3.math.Quaternion;
 import com.jme3.math.Vector3f;
 import com.jme3.post.FilterPostProcessor;
@@ -45,7 +48,7 @@ import com.jme3.shadow.EdgeFilteringMode;
 import com.jme3.shadow.PointLightShadowFilter;
 import com.jme3.shadow.PointLightShadowRenderer;
 
-public class TestPointLightShadows extends SimpleApplication {
+public class TestPointLightShadows extends SimpleApplication implements ActionListener{
     public static final int SHADOWMAP_SIZE = 512;
 
     public static void main(String[] args) {
@@ -55,15 +58,21 @@ public class TestPointLightShadows extends SimpleApplication {
     Node lightNode;
     PointLightShadowRenderer plsr;
     PointLightShadowFilter plsf;
+    AmbientLight al;
 
     @Override
-    public void simpleInitApp() {
+    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));
 
+        al = new AmbientLight(ColorRGBA.White.mult(0.02f));
+        rootNode.addLight(al);
 
-        Node scene = (Node) assetManager.loadModel("Models/Test/CornellBox.j3o");
+
+
+
+        Node scene = (Node) assetManager.loadModel("Models/Test/CornellBox_1.j3o");
         scene.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
         rootNode.attachChild(scene);
         rootNode.getChild("Cube").setShadowMode(RenderQueue.ShadowMode.Receive);
@@ -89,6 +98,7 @@ public class TestPointLightShadows extends SimpleApplication {
         plsr.setEdgeFilteringMode(EdgeFilteringMode.PCF4);
         plsr.setShadowZExtend(15);
         plsr.setShadowZFadeLength(5);
+        plsr.setShadowIntensity(0.9f);
        // plsr.setFlushQueues(false);
         //plsr.displayFrustum();
         plsr.displayDebug();
@@ -99,18 +109,27 @@ public class TestPointLightShadows extends SimpleApplication {
         plsf.setLight((PointLight) scene.getLocalLightList().get(0));    
         plsf.setShadowZExtend(15);
         plsf.setShadowZFadeLength(5);
+        plsf.setShadowIntensity(0.8f);
         plsf.setEdgeFilteringMode(EdgeFilteringMode.PCF4);
         plsf.setEnabled(false);
 
         FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
         fpp.addFilter(plsf);
         viewPort.addProcessor(fpp);
-              
+        inputManager.addListener(this,"ShadowUp","ShadowDown");
         ShadowTestUIManager uiMan = new ShadowTestUIManager(assetManager, plsr, plsf, guiNode, inputManager, viewPort);
+
     }
 
     @Override
     public void simpleUpdate(float tpf) {
  //      lightNode.move(FastMath.cos(tpf) * 0.4f, 0, FastMath.sin(tpf) * 0.4f);
     }
+
+    @Override
+    public void onAction(String name, boolean isPressed, float tpf) {
+        if ((name.equals("ShadowUp") || name.equals("ShadowDown")) && isPressed) {
+            al.setColor(ColorRGBA.White.mult((1 - plsr.getShadowIntensity()) * 0.2f));
+        }
+    }
 }