Added an option to not render backfaces shadows with the shadow renderer and the shadow filter. It's the default for the renderer but not for the filter as it may have some edges artifacts.

cleanup_build_scripts
Nehon 9 years ago
parent 32be69f3e6
commit dff4befafb
  1. 47
      jme3-core/src/main/java/com/jme3/shadow/AbstractShadowFilter.java
  2. 104
      jme3-core/src/main/java/com/jme3/shadow/AbstractShadowRenderer.java
  3. 2
      jme3-core/src/main/java/com/jme3/shadow/DirectionalLightShadowRenderer.java
  4. 13
      jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md
  5. 4
      jme3-core/src/main/resources/Common/MatDefs/Misc/Unshaded.j3md
  6. 17
      jme3-core/src/main/resources/Common/MatDefs/Shadow/PostShadow.frag
  7. 4
      jme3-core/src/main/resources/Common/MatDefs/Shadow/PostShadow.j3md
  8. 32
      jme3-core/src/main/resources/Common/MatDefs/Shadow/PostShadow.vert
  9. 29
      jme3-core/src/main/resources/Common/MatDefs/Shadow/PostShadowFilter.frag
  10. 10
      jme3-core/src/main/resources/Common/MatDefs/Shadow/PostShadowFilter.j3md
  11. 48
      jme3-core/src/main/resources/Common/MatDefs/Shadow/PostShadowFilter15.frag
  12. 39
      jme3-examples/src/main/java/jme3test/light/TestDirectionalLightShadow.java
  13. 27
      jme3-examples/src/main/java/jme3test/light/TestPointLightShadows.java

@ -37,6 +37,7 @@ import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter; import com.jme3.export.JmeImporter;
import com.jme3.export.OutputCapsule; import com.jme3.export.OutputCapsule;
import com.jme3.material.Material; import com.jme3.material.Material;
import com.jme3.material.RenderState;
import com.jme3.math.Matrix4f; import com.jme3.math.Matrix4f;
import com.jme3.math.Vector4f; import com.jme3.math.Vector4f;
import com.jme3.post.Filter; import com.jme3.post.Filter;
@ -44,6 +45,7 @@ import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort; import com.jme3.renderer.ViewPort;
import com.jme3.renderer.queue.RenderQueue; import com.jme3.renderer.queue.RenderQueue;
import com.jme3.texture.FrameBuffer; import com.jme3.texture.FrameBuffer;
import java.io.IOException; 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"); material = new Material(manager, "Common/MatDefs/Shadow/PostShadowFilter.j3md");
this.shadowRenderer = shadowRenderer; this.shadowRenderer = shadowRenderer;
this.shadowRenderer.setPostShadowMaterial(material); this.shadowRenderer.setPostShadowMaterial(material);
//this is legacy setting for shadows with backface shadows
this.shadowRenderer.setRenderBackFacesShadows(true);
} }
@Override @Override
@ -126,7 +131,7 @@ public abstract class AbstractShadowFilter<T extends AbstractShadowRenderer> ext
/** /**
* How far the shadows are rendered in the view * How far the shadows are rendered in the view
* *
* @see setShadowZExtend(float zFar) * @see #setShadowZExtend(float zFar)
* @return shadowZExtend * @return shadowZExtend
*/ */
public float getShadowZExtend() { public float getShadowZExtend() {
@ -248,6 +253,46 @@ public abstract class AbstractShadowFilter<T extends AbstractShadowRenderer> ext
shadowRenderer.setEdgeFilteringMode(filterMode); 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 * returns the the edge filtering mode
* *

@ -31,10 +31,6 @@
*/ */
package com.jme3.shadow; package com.jme3.shadow;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import com.jme3.asset.AssetManager; import com.jme3.asset.AssetManager;
import com.jme3.export.InputCapsule; import com.jme3.export.InputCapsule;
import com.jme3.export.JmeExporter; import com.jme3.export.JmeExporter;
@ -42,6 +38,7 @@ import com.jme3.export.JmeImporter;
import com.jme3.export.OutputCapsule; import com.jme3.export.OutputCapsule;
import com.jme3.export.Savable; import com.jme3.export.Savable;
import com.jme3.material.Material; import com.jme3.material.Material;
import com.jme3.material.RenderState;
import com.jme3.math.ColorRGBA; import com.jme3.math.ColorRGBA;
import com.jme3.math.Matrix4f; import com.jme3.math.Matrix4f;
import com.jme3.math.Vector2f; import com.jme3.math.Vector2f;
@ -67,6 +64,10 @@ import com.jme3.texture.Texture.ShadowCompareMode;
import com.jme3.texture.Texture2D; import com.jme3.texture.Texture2D;
import com.jme3.ui.Picture; 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 * abstract shadow renderer that holds commons feature to have for a shadow
* renderer * renderer
@ -92,6 +93,8 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
protected EdgeFilteringMode edgeFilteringMode = EdgeFilteringMode.Bilinear; protected EdgeFilteringMode edgeFilteringMode = EdgeFilteringMode.Bilinear;
protected CompareMode shadowCompareMode = CompareMode.Hardware; protected CompareMode shadowCompareMode = CompareMode.Hardware;
protected Picture[] dispPic; protected Picture[] dispPic;
protected RenderState forcedRenderState = new RenderState();
protected Boolean renderBackFacesShadows;
/** /**
* true if the fallback material should be used, otherwise false * true if the fallback material should be used, otherwise false
@ -182,6 +185,14 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
setShadowCompareMode(shadowCompareMode); setShadowCompareMode(shadowCompareMode);
setEdgeFilteringMode(edgeFilteringMode); setEdgeFilteringMode(edgeFilteringMode);
setShadowIntensity(shadowIntensity); 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 * rendered in the shadow map
* *
* @param shadowMapIndex the index of the shadow map being rendered * @param shadowMapIndex the index of the shadow map being rendered
* @param sceneOccluders the occluders of the whole scene * @param shadowMapOccluders the list of occluders
* @param sceneReceivers the receivers of the whole scene
* @param shadowMapOcculders
* @return * @return
*/ */
protected abstract GeometryList getOccludersToRender(int shadowMapIndex, GeometryList shadowMapOccluders); 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().setFrameBuffer(shadowFB[shadowMapIndex]);
renderManager.getRenderer().clearBuffers(true, true, true); renderManager.getRenderer().clearBuffers(true, true, true);
renderManager.setForcedRenderState(forcedRenderState);
// render shadow casters to shadow map // render shadow casters to shadow map
viewPort.getQueue().renderShadowQueue(shadowMapOccluders, renderManager, shadowCam, true); viewPort.getQueue().renderShadowQueue(shadowMapOccluders, renderManager, shadowCam, true);
renderManager.setForcedRenderState(null);
} }
boolean debugfrustums = false; boolean debugfrustums = false;
@ -536,18 +547,7 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
private void setMatParams(GeometryList l) { private void setMatParams(GeometryList l) {
//iteration throught all the geometries of the list to gather the materials //iteration throught all the geometries of the list to gather the materials
matCache.clear(); buildMatCache(l);
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;
}
}
//iterating through the mat cache and setting the parameters //iterating through the mat cache and setting the parameters
for (Material mat : matCache) { for (Material mat : matCache) {
@ -567,6 +567,10 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
if (fadeInfo != null) { if (fadeInfo != null) {
mat.setVector2("FadeInfo", fadeInfo); mat.setVector2("FadeInfo", fadeInfo);
} }
if(renderBackFacesShadows != null){
mat.setBoolean("BackfaceShadows", renderBackFacesShadows);
}
setMaterialParameters(mat); 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 * for internal use only
*/ */
@ -588,7 +607,10 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
postshadowMat.setTexture(shadowMapStringCache[j], shadowMaps[j]); postshadowMat.setTexture(shadowMapStringCache[j], shadowMaps[j]);
} }
if (fadeInfo != null) { 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 @Deprecated
public void setFlushQueues(boolean flushQueues) {} 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. * De-serialize this instance, for example when loading from a J3O file.
* *

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

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

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

@ -9,6 +9,9 @@ varying vec4 projCoord0;
varying vec4 projCoord1; varying vec4 projCoord1;
varying vec4 projCoord2; varying vec4 projCoord2;
varying vec4 projCoord3; varying vec4 projCoord3;
#ifndef BACKFACE_SHADOWS
varying float nDotL;
#endif
#ifdef POINTLIGHT #ifdef POINTLIGHT
varying vec4 projCoord4; varying vec4 projCoord4;
@ -46,9 +49,15 @@ void main(){
if(alpha<=m_AlphaDiscardThreshold){ if(alpha<=m_AlphaDiscardThreshold){
discard; discard;
} }
#endif
#ifndef BACKFACE_SHADOWS
if(nDotL > 0.0){
discard;
}
#endif #endif
float shadow = 1.0; float shadow = 1.0;
#ifdef POINTLIGHT #ifdef POINTLIGHT
@ -71,11 +80,11 @@ void main(){
#endif #endif
#ifdef FADE #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 #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);
} }

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

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

@ -18,6 +18,8 @@ uniform mat4 m_LightViewProjectionMatrix1;
uniform mat4 m_LightViewProjectionMatrix2; uniform mat4 m_LightViewProjectionMatrix2;
uniform mat4 m_LightViewProjectionMatrix3; uniform mat4 m_LightViewProjectionMatrix3;
uniform vec2 g_ResolutionInverse;
#ifdef POINTLIGHT #ifdef POINTLIGHT
uniform vec3 m_LightPos; uniform vec3 m_LightPos;
uniform mat4 m_LightViewProjectionMatrix4; uniform mat4 m_LightViewProjectionMatrix4;
@ -39,6 +41,19 @@ vec3 getPosition(in float depth, in vec2 uv){
return pos.xyz / pos.w; 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(){ void main(){
#if !defined( RENDER_SHADOWS ) #if !defined( RENDER_SHADOWS )
gl_FragColor = texture2D(m_Texture,texCoord); gl_FragColor = texture2D(m_Texture,texCoord);
@ -48,6 +63,7 @@ void main(){
float depth = texture2D(m_DepthTexture,texCoord).r; float depth = texture2D(m_DepthTexture,texCoord).r;
vec4 color = texture2D(m_Texture,texCoord); vec4 color = texture2D(m_Texture,texCoord);
//Discard shadow computation on the sky //Discard shadow computation on the sky
if(depth == 1.0){ if(depth == 1.0){
gl_FragColor = color; gl_FragColor = color;
@ -56,6 +72,19 @@ void main(){
// get the vertex in world space // get the vertex in world space
vec4 worldPos = vec4(getPosition(depth,texCoord),1.0); 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)) #if (!defined(POINTLIGHT) && !defined(PSSM))
vec3 lightDir = worldPos.xyz - m_LightPos; vec3 lightDir = worldPos.xyz - m_LightPos;

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

@ -20,14 +20,16 @@ uniform mat4 m_LightViewProjectionMatrix1;
uniform mat4 m_LightViewProjectionMatrix2; uniform mat4 m_LightViewProjectionMatrix2;
uniform mat4 m_LightViewProjectionMatrix3; uniform mat4 m_LightViewProjectionMatrix3;
uniform vec2 g_ResolutionInverse;
#ifdef POINTLIGHT #ifdef POINTLIGHT
uniform vec3 m_LightPos; uniform vec3 m_LightPos;
uniform mat4 m_LightViewProjectionMatrix4; uniform mat4 m_LightViewProjectionMatrix4;
uniform mat4 m_LightViewProjectionMatrix5; uniform mat4 m_LightViewProjectionMatrix5;
#else #else
uniform vec3 m_LightDir;
#ifndef PSSM #ifndef PSSM
uniform vec3 m_LightPos; uniform vec3 m_LightPos;
uniform vec3 m_LightDir;
#endif #endif
#endif #endif
@ -41,6 +43,23 @@ vec3 getPosition(in float depth, in vec2 uv){
return pos.xyz / pos.w; 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){ vec4 main_multiSample(in int numSample){
float depth = fetchTextureSample(m_DepthTexture,texCoord,numSample).r;//getDepth(m_DepthTexture,texCoord).r; float depth = fetchTextureSample(m_DepthTexture,texCoord,numSample).r;//getDepth(m_DepthTexture,texCoord).r;
vec4 color = fetchTextureSample(m_Texture,texCoord,numSample); vec4 color = fetchTextureSample(m_Texture,texCoord,numSample);
@ -52,12 +71,27 @@ vec4 main_multiSample(in int numSample){
// get the vertex in world space // get the vertex in world space
vec4 worldPos = vec4(getPosition(depth,texCoord),1.0); 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)) #if (!defined(POINTLIGHT) && !defined(PSSM))
vec3 lightDir = worldPos.xyz - m_LightPos; if( dot(m_LightDir,lightDir)<0){
if( dot(m_LightDir,lightDir)<0){ return color;
return color; }
}
#endif #endif
// populate the light view matrices array and convert vertex to light viewProj space // populate the light view matrices array and convert vertex to light viewProj space

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

@ -32,7 +32,10 @@
package jme3test.light; package jme3test.light;
import com.jme3.app.SimpleApplication; import com.jme3.app.SimpleApplication;
import com.jme3.input.controls.ActionListener;
import com.jme3.light.AmbientLight;
import com.jme3.light.PointLight; import com.jme3.light.PointLight;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Quaternion; import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
import com.jme3.post.FilterPostProcessor; import com.jme3.post.FilterPostProcessor;
@ -45,7 +48,7 @@ import com.jme3.shadow.EdgeFilteringMode;
import com.jme3.shadow.PointLightShadowFilter; import com.jme3.shadow.PointLightShadowFilter;
import com.jme3.shadow.PointLightShadowRenderer; 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 final int SHADOWMAP_SIZE = 512;
public static void main(String[] args) { public static void main(String[] args) {
@ -55,15 +58,21 @@ public class TestPointLightShadows extends SimpleApplication {
Node lightNode; Node lightNode;
PointLightShadowRenderer plsr; PointLightShadowRenderer plsr;
PointLightShadowFilter plsf; PointLightShadowFilter plsf;
AmbientLight al;
@Override @Override
public void simpleInitApp() { public void simpleInitApp () {
flyCam.setMoveSpeed(10); flyCam.setMoveSpeed(10);
cam.setLocation(new Vector3f(0.040581334f, 1.7745866f, 6.155161f)); cam.setLocation(new Vector3f(0.040581334f, 1.7745866f, 6.155161f));
cam.setRotation(new Quaternion(4.3868728E-5f, 0.9999293f, -0.011230096f, 0.0039059948f)); 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); scene.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
rootNode.attachChild(scene); rootNode.attachChild(scene);
rootNode.getChild("Cube").setShadowMode(RenderQueue.ShadowMode.Receive); rootNode.getChild("Cube").setShadowMode(RenderQueue.ShadowMode.Receive);
@ -89,6 +98,7 @@ public class TestPointLightShadows extends SimpleApplication {
plsr.setEdgeFilteringMode(EdgeFilteringMode.PCF4); plsr.setEdgeFilteringMode(EdgeFilteringMode.PCF4);
plsr.setShadowZExtend(15); plsr.setShadowZExtend(15);
plsr.setShadowZFadeLength(5); plsr.setShadowZFadeLength(5);
plsr.setShadowIntensity(0.9f);
// plsr.setFlushQueues(false); // plsr.setFlushQueues(false);
//plsr.displayFrustum(); //plsr.displayFrustum();
plsr.displayDebug(); plsr.displayDebug();
@ -99,18 +109,27 @@ public class TestPointLightShadows extends SimpleApplication {
plsf.setLight((PointLight) scene.getLocalLightList().get(0)); plsf.setLight((PointLight) scene.getLocalLightList().get(0));
plsf.setShadowZExtend(15); plsf.setShadowZExtend(15);
plsf.setShadowZFadeLength(5); plsf.setShadowZFadeLength(5);
plsf.setShadowIntensity(0.8f);
plsf.setEdgeFilteringMode(EdgeFilteringMode.PCF4); plsf.setEdgeFilteringMode(EdgeFilteringMode.PCF4);
plsf.setEnabled(false); plsf.setEnabled(false);
FilterPostProcessor fpp = new FilterPostProcessor(assetManager); FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
fpp.addFilter(plsf); fpp.addFilter(plsf);
viewPort.addProcessor(fpp); viewPort.addProcessor(fpp);
inputManager.addListener(this,"ShadowUp","ShadowDown");
ShadowTestUIManager uiMan = new ShadowTestUIManager(assetManager, plsr, plsf, guiNode, inputManager, viewPort); ShadowTestUIManager uiMan = new ShadowTestUIManager(assetManager, plsr, plsf, guiNode, inputManager, viewPort);
} }
@Override @Override
public void simpleUpdate(float tpf) { public void simpleUpdate(float tpf) {
// lightNode.move(FastMath.cos(tpf) * 0.4f, 0, FastMath.sin(tpf) * 0.4f); // 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));
}
}
} }
Loading…
Cancel
Save