Lighting and Shadows (PSSM only) :

- re introduced the alphaDiscardThreshold as explained in prvious commit. It's not binded to the AlphaTestFallOff fixedfunc binding
- Added a small poly offset to post shadow technique, this greatly help in fixing shadow acne.
- Added Poisson disc sampling PCF Filtering for shadows
- Properly passed the shadow map size as a define in the shaders and remove the hardcoded value
- Pssm15 don't use the textureSize function anymore and use the same shadow map size define ( this increased performance quite a bit)
- Optimized the shaders code a bit
- Better PSSM test

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9750 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
3.0
rem..om 12 years ago
parent 2915316e45
commit 384f4ac1c2
  1. 31
      engine/src/core-data/Common/MatDefs/Light/Lighting.j3md
  2. 2
      engine/src/core-data/Common/MatDefs/Shadow/PostShadow.j3md
  3. 112
      engine/src/core-data/Common/MatDefs/Shadow/PostShadowPSSM.frag
  4. 12
      engine/src/core-data/Common/MatDefs/Shadow/PostShadowPSSM.j3md
  5. 5
      engine/src/core-data/Common/MatDefs/Shadow/PostShadowPSSM.vert
  6. 103
      engine/src/core-data/Common/MatDefs/Shadow/PostShadowPSSM15.frag
  7. 35
      engine/src/core-data/Common/MatDefs/Shadow/PreShadow.frag
  8. 10
      engine/src/core-effects/Common/MatDefs/SSAO/normal.frag
  9. 34
      engine/src/core/com/jme3/shadow/PssmShadowRenderer.java
  10. 173
      engine/src/test/jme3test/light/TestPssmShadow.java
  11. 4
      engine/src/test/jme3test/light/TestTransparentShadow.java
  12. 4
      engine/src/test/jme3test/post/TestTransparentSSAO.java
  13. 3
      engine/test-data/Models/Tree/Leaves.j3m

@ -15,6 +15,9 @@ MaterialDef Phong Lighting {
// Output alpha from the diffuse map
Boolean UseAlpha
// Apha threshold for fragment discarding
Float AlphaDiscardThreshold (AlphaTestFallOff)
// Normal map is in BC5/ATI2n/LATC/3Dc compression format
Boolean LATC
@ -115,6 +118,7 @@ MaterialDef Phong Lighting {
Matrix4 LightViewProjectionMatrix3
Float PCFEdge
Float ShadowMapSize
}
Technique {
@ -157,7 +161,7 @@ MaterialDef Phong Lighting {
SEPARATE_TEXCOORD : SeparateTexCoord
USE_REFLECTION : EnvMap
SPHERE_MAP : EnvMapAsSphereMap
SPHERE_MAP : SphereMap
}
}
@ -171,8 +175,9 @@ MaterialDef Phong Lighting {
WorldViewMatrix
}
Defines {
DIFFUSEMAP : DiffuseMap
Defines {
COLOR_MAP : ColorMap
DISCARD_ALPHA : AlphaDiscardThreshold
}
RenderState {
@ -199,11 +204,15 @@ MaterialDef Phong Lighting {
HARDWARE_SHADOWS : HardwareShadows
FILTER_MODE : FilterMode
PCFEDGE : PCFEdge
DIFFUSEMAP : DiffuseMap
DISCARD_ALPHA : AlphaDiscardThreshold
COLOR_MAP : ColorMap
SHADOWMAP_SIZE : ShadowMapSize
}
RenderState {
Blend Alpha
ForcedRenderState {
Blend Modulate
DepthWrite Off
PolyOffset -0.1 0
}
}
@ -220,11 +229,15 @@ MaterialDef Phong Lighting {
HARDWARE_SHADOWS : HardwareShadows
FILTER_MODE : FilterMode
PCFEDGE : PCFEdge
DIFFUSEMAP : DiffuseMap
DISCARD_ALPHA : AlphaDiscardThreshold
COLOR_MAP : ColorMap
SHADOWMAP_SIZE : ShadowMapSize
}
RenderState {
Blend Alpha
ForcedRenderState {
Blend Modulate
DepthWrite Off
PolyOffset -0.1 0
}
}

@ -20,6 +20,8 @@ MaterialDef Post Shadow {
RenderState {
Blend Modulate
DepthWrite Off
PolyOffset -0.1 0
}
}

@ -23,6 +23,9 @@
#define GETSHADOW Shadow_DoPCF
#define KERNEL 4.0
#elif FILTER_MODE == 4
#define GETSHADOW Shadow_DoPCFPoisson
#define KERNEL 4
#elif FILTER_MODE == 5
#define GETSHADOW Shadow_DoPCF
#define KERNEL 8.0
#endif
@ -44,9 +47,9 @@ varying vec4 projCoord3;
varying float shadowPosition;
const float texSize = 1024.0;
const float pixSize = 1.0 / texSize;
const vec2 pixSize2 = vec2(pixSize);
const vec2 pixSize2 = vec2(1.0 / SHADOWMAP_SIZE);
float scale = 1.0;
float Shadow_DoShadowCompareOffset(in SHADOWMAP tex, in vec4 projCoord, in vec2 offset){
vec4 coord = vec4(projCoord.xy + offset.xy * pixSize2, projCoord.zw);
@ -90,7 +93,7 @@ float Shadow_DoBilinear_2x2(in SHADOWMAP tex, in vec4 projCoord){
gather.z = Shadow_DoShadowCompareOffset(tex, projCoord, vec2(0.0, 1.0));
gather.w = Shadow_DoShadowCompareOffset(tex, projCoord, vec2(1.0, 1.0));
vec2 f = fract( projCoord.xy * texSize );
vec2 f = fract( projCoord.xy * SHADOWMAP_SIZE );
vec2 mx = mix( gather.xz, gather.yw, f.x );
return mix( mx.x, mx.y, f.y );
}
@ -114,39 +117,102 @@ float Shadow_DoPCF(in SHADOWMAP tex, in vec4 projCoord){
return shadow;
}
#ifdef COLOR_MAP
uniform sampler2D m_ColorMap;
varying vec2 texCoord;
#endif
#ifdef DIFFUSEMAP
uniform sampler2D m_DiffuseMap;
//12 tap poisson disk
const vec2 poissonDisk[12] =vec2[12]( vec2(-0.1711046, -0.425016),
vec2(-0.7829809, 0.2162201),
vec2(-0.2380269, -0.8835521),
vec2(0.4198045, 0.1687819),
vec2(-0.684418, -0.3186957),
vec2(0.6026866, -0.2587841),
vec2(-0.2412762, 0.3913516),
vec2(0.4720655, -0.7664126),
vec2(0.9571564, 0.2680693),
vec2(-0.5238616, 0.802707),
vec2(0.5653144, 0.60262),
vec2(0.0123658, 0.8627419));
float Shadow_DoPCFPoisson(in SHADOWMAP tex, in vec4 projCoord){
float shadow = 0.0;
float border = Shadow_BorderCheck(projCoord.xy);
if (border > 0.0)
return 1.0;
vec2 texelSize = vec2( 4.0 * PCFEDGE * scale);
shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk[0] * texelSize);
shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk[1] * texelSize);
shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk[2] * texelSize);
shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk[3] * texelSize);
shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk[4] * texelSize);
shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk[5] * texelSize);
shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk[6] * texelSize);
shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk[7] * texelSize);
shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk[8] * texelSize);
shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk[9] * texelSize);
shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk[10] * texelSize);
shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk[11] * texelSize);
shadow = shadow * 0.08333333333;//this is divided by 12
return shadow;
}
#ifdef DISCARD_ALPHA
#ifdef COLOR_MAP
uniform sampler2D m_ColorMap;
#else
uniform sampler2D m_DiffuseMap;
#endif
uniform float m_AlphaDiscardThreshold;
varying vec2 texCoord;
#endif
void main(){
float alpha =1.0;
#ifdef COLOR_MAP
alpha = texture2D(m_ColorMap,texCoord).a;
#ifdef DISCARD_ALPHA
#ifdef COLOR_MAP
float alpha = texture2D(m_ColorMap,texCoord).a;
#else
float alpha = texture2D(m_DiffuseMap,texCoord).a;
#endif
if(alpha<=m_AlphaDiscardThreshold){
discard;
}
#endif
#ifdef DIFFUSEMAP
alpha = texture2D(m_DiffuseMap,texCoord).a;
#endif
vec4 shadowPerSplit = vec4(0.0);
shadowPerSplit.x = GETSHADOW(m_ShadowMap0, projCoord0);
float shadow;
//shadowPosition
if(shadowPosition < m_Splits.x){
shadow= GETSHADOW(m_ShadowMap0, projCoord0);
}else if( shadowPosition < m_Splits.y){
scale = 0.5;
shadow = GETSHADOW(m_ShadowMap1, projCoord1);
}else if( shadowPosition < m_Splits.z){
scale = 0.25;
shadow= GETSHADOW(m_ShadowMap2, projCoord2);
}else if( shadowPosition < m_Splits.w){
scale = 0.125;
shadow= GETSHADOW(m_ShadowMap3, projCoord3);
}
/*
shadowPerSplit.x = GETSHADOW(m_ShadowMap0, projCoord0);
shadowPerSplit.y = GETSHADOW(m_ShadowMap1, projCoord1);
shadowPerSplit.z = GETSHADOW(m_ShadowMap2, projCoord2);
shadowPerSplit.w = GETSHADOW(m_ShadowMap3, projCoord3);
*/
/*
vec4 less = step( shadowPosition, m_Splits );
vec4 more = vec4(1.0) - step( shadowPosition, vec4(0.0, m_Splits.xyz) );
float shadow = dot(shadowPerSplit, less * more );
*/
shadow = shadow * m_ShadowIntensity + (1.0 - m_ShadowIntensity);
gl_FragColor = vec4(0.0, 0.0, 0.0, min(1.0 - shadow,alpha));
gl_FragColor = vec4(shadow, shadow, shadow, 1.0);
}

@ -18,6 +18,8 @@ MaterialDef Post Shadow {
Matrix4 LightViewProjectionMatrix3
Float PCFEdge
Float ShadowMapSize
}
Technique {
@ -33,10 +35,13 @@ MaterialDef Post Shadow {
HARDWARE_SHADOWS : HardwareShadows
FILTER_MODE : FilterMode
PCFEDGE : PCFEdge
SHADOWMAP_SIZE : ShadowMapSize
}
RenderState {
Blend Alpha
Blend Modulate
DepthWrite Off
PolyOffset -0.1 0
}
}
@ -53,10 +58,13 @@ MaterialDef Post Shadow {
HARDWARE_SHADOWS : HardwareShadows
FILTER_MODE : FilterMode
PCFEDGE : PCFEdge
SHADOWMAP_SIZE : ShadowMapSize
}
RenderState {
Blend Alpha
Blend Modulate
DepthWrite Off
PolyOffset -0.1 0
}
}

@ -16,7 +16,8 @@ varying float shadowPosition;
varying vec2 texCoord;
attribute vec3 inPosition;
#if defined(DIFFUSEMAP) || defined(COLOR_MAP)
#ifdef DISCARD_ALPHA
attribute vec2 inTexCoord;
#endif
@ -33,7 +34,7 @@ void main(){
// get the vertex in world space
vec4 worldPos = g_WorldMatrix * vec4(inPosition, 1.0);
#if defined(DIFFUSEMAP) || defined(COLOR_MAP)
#ifdef DISCARD_ALPHA
texCoord = inTexCoord;
#endif
// populate the light view matrices array and convert vertex to light viewProj space

@ -32,6 +32,9 @@
#define GETSHADOW Shadow_DoPCF
#define KERNEL 4
#elif FILTER_MODE == 4
#define GETSHADOW Shadow_DoPCFPoisson
#define KERNEL 4
#elif FILTER_MODE == 5
#define GETSHADOW Shadow_DoPCF
#define KERNEL 8
#endif
@ -51,6 +54,8 @@ in vec4 projCoord1;
in vec4 projCoord2;
in vec4 projCoord3;
in float shadowPosition;
const vec2 pixSize2 = vec2(1.0 / SHADOWMAP_SIZE);
float scale = 1.0;
float Shadow_BorderCheck(in vec2 coord){
// Fastest, "hack" method (uses 4-5 instructions)
@ -64,9 +69,8 @@ float Shadow_DoDither_2x2(in SHADOWMAP tex, in vec4 projCoord){
if (border > 0.0)
return 1.0;
ivec2 texSize = textureSize(tex, 0);
vec2 pixSize = 1.0 / vec2(texSize);
vec2 pixSize = pixSize2 * scale;
float shadow = 0.0;
ivec2 o = ivec2(mod(floor(gl_FragCoord.xy), 2.0));
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy+pixSize*(vec2(-1.5, 1.5)+o), projCoord.zw));
@ -81,8 +85,7 @@ float Shadow_DoBilinear_2x2(in SHADOWMAP tex, in vec4 projCoord){
float border = Shadow_BorderCheck(projCoord.xy);
if (border > 0.0)
return 1.0;
ivec2 texSize = textureSize(tex, 0);
#ifdef GL_ARB_gpu_shader5
vec4 coord = vec4(projCoord.xyz / projCoord.www,0.0);
vec4 gather = SHADOWGATHER(tex, coord);
@ -94,14 +97,14 @@ float Shadow_DoBilinear_2x2(in SHADOWMAP tex, in vec4 projCoord){
gather.w = SHADOWCOMPAREOFFSET(tex, projCoord, ivec2(1, 1));
#endif
vec2 f = fract( projCoord.xy * texSize );
vec2 f = fract( projCoord.xy * SHADOWMAP_SIZE );
vec2 mx = mix( gather.xz, gather.yw, f.x );
return mix( mx.x, mx.y, f.y );
}
float Shadow_DoPCF(in SHADOWMAP tex, in vec4 projCoord){
float pixSize = 1.0 / textureSize(tex,0).x;
vec2 pixSize = pixSize2 * scale;
float shadow = 0.0;
float border = Shadow_BorderCheck(projCoord.xy);
if (border > 0.0)
@ -121,38 +124,90 @@ float Shadow_DoPCF(in SHADOWMAP tex, in vec4 projCoord){
}
#ifdef COLOR_MAP
uniform sampler2D m_ColorMap;
varying vec2 texCoord;
#endif
#ifdef DIFFUSEMAP
uniform sampler2D m_DiffuseMap;
varying vec2 texCoord;
#endif
void main(){
//12 tap poisson disk
const vec2 poissonDisk[12] =vec2[12]( vec2(-0.1711046, -0.425016),
vec2(-0.7829809, 0.2162201),
vec2(-0.2380269, -0.8835521),
vec2(0.4198045, 0.1687819),
vec2(-0.684418, -0.3186957),
vec2(0.6026866, -0.2587841),
vec2(-0.2412762, 0.3913516),
vec2(0.4720655, -0.7664126),
vec2(0.9571564, 0.2680693),
vec2(-0.5238616, 0.802707),
vec2(0.5653144, 0.60262),
vec2(0.0123658, 0.8627419));
float Shadow_DoPCFPoisson(in SHADOWMAP tex, in vec4 projCoord){
float shadow = 0.0;
float border = Shadow_BorderCheck(projCoord.xy);
if (border > 0.0)
return 1.0;
float alpha = 1.0;
//failed attempt to rotate the poisson disk to add jitter
//vec2 jitterFactor = vec2(sin(projCoord.x),cos(projCoord.x));// * 2.0f - 1.0f;
vec2 texelSize = pixSize2 * 4.0 * PCFEDGE * scale;
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk[0] * texelSize, projCoord.zw));
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk[1] * texelSize, projCoord.zw));
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk[2] * texelSize, projCoord.zw));
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk[3] * texelSize, projCoord.zw));
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk[4] * texelSize, projCoord.zw));
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk[5] * texelSize, projCoord.zw));
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk[6] * texelSize, projCoord.zw));
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk[7] * texelSize, projCoord.zw));
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk[8] * texelSize, projCoord.zw));
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk[9] * texelSize, projCoord.zw));
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk[10] * texelSize, projCoord.zw));
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk[11] * texelSize, projCoord.zw));
shadow = shadow * 0.08333333333;//this is divided by 12
return shadow;
}
#ifdef DISCARD_ALPHA
#ifdef COLOR_MAP
alpha = texture2D(m_ColorMap,texCoord).a;
uniform sampler2D m_ColorMap;
#else
uniform sampler2D m_DiffuseMap;
#endif
#ifdef DIFFUSEMAP
alpha = texture2D(m_DiffuseMap,texCoord).a;
uniform float m_AlphaDiscardThreshold;
varying vec2 texCoord;
#endif
void main(){
float shadow = 0.0;
#ifdef DISCARD_ALPHA
#ifdef COLOR_MAP
float alpha = texture2D(m_ColorMap,texCoord).a;
#else
float alpha = texture2D(m_DiffuseMap,texCoord).a;
#endif
if(alpha < m_AlphaDiscardThreshold){
discard;
}
#endif
if(shadowPosition < m_Splits.x){
shadow = GETSHADOW(m_ShadowMap0, projCoord0);
}else if( shadowPosition < m_Splits.y){
scale = 0.5;
shadow = GETSHADOW(m_ShadowMap1, projCoord1);
}else if( shadowPosition < m_Splits.z){
scale = 0.25;
shadow = GETSHADOW(m_ShadowMap2, projCoord2);
}else if( shadowPosition < m_Splits.w){
scale = 0.125;
shadow = GETSHADOW(m_ShadowMap3, projCoord3);
}
shadow = shadow * m_ShadowIntensity + (1.0 - m_ShadowIntensity);
outFragColor = vec4(0.0, 0.0, 0.0, min(1.0 - shadow,alpha));
outFragColor = vec4(shadow, shadow, shadow, 1.0);
}

@ -1,24 +1,27 @@
varying vec2 texCoord;
#ifdef COLOR_MAP
uniform sampler2D m_ColorMap;
#endif
#ifdef DIFFUSEMAP
uniform sampler2D m_DiffuseMap;
#ifdef DISCARD_ALPHA
#ifdef COLOR_MAP
uniform sampler2D m_ColorMap;
#else
uniform sampler2D m_DiffuseMap;
#endif
uniform float m_AlphaDiscardThreshold;
#endif
void main(){
float a = 1.0;
#ifdef COLOR_MAP
a = texture2D(m_ColorMap, texCoord).a;
#endif
#ifdef DIFFUSEMAP
a = texture2D(m_DiffuseMap, texCoord).a;
#endif
#ifdef DISCARD_ALPHA
#ifdef COLOR_MAP
if (texture2D(m_ColorMap, texCoord).a <= m_AlphaDiscardThreshold){
discard;
}
#else
if (texture2D(m_DiffuseMap, texCoord).a <= m_AlphaDiscardThreshold){
discard;
}
#endif
#endif
gl_FragColor = vec4(a);
gl_FragColor = vec4(1.0);
}

@ -4,15 +4,17 @@ varying vec2 texCoord;
#ifdef DIFFUSEMAP_ALPHA
uniform sampler2D m_DiffuseMap;
uniform float m_AlphaDiscardThreshold;
#endif
void main(void)
{
float alpha= 1.0;
#ifdef DIFFUSEMAP_ALPHA
alpha=texture2D(m_DiffuseMap,texCoord).a;
if(texture2D(m_DiffuseMap,texCoord).a<m_AlphaDiscardThreshold){
discard;
}
#endif
gl_FragColor = vec4(normal.xy* 0.5 + 0.5,-normal.z* 0.5 + 0.5, alpha);
gl_FragColor = vec4(normal.xy* 0.5 + 0.5,-normal.z* 0.5 + 0.5, 1.0);
}

@ -31,6 +31,7 @@ package com.jme3.shadow;
import com.jme3.asset.AssetManager;
import com.jme3.material.Material;
import com.jme3.material.RenderState;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Matrix4f;
import com.jme3.math.Vector3f;
@ -47,6 +48,7 @@ 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.shader.VarType;
import com.jme3.texture.FrameBuffer;
import com.jme3.texture.Image.Format;
import com.jme3.texture.Texture.MagFilter;
@ -93,11 +95,17 @@ public class PssmShadowRenderer implements SceneProcessor {
* at the cost of performance
*/
PCF4,
/**
* 8x8 percentage-closer filtering is used. Shadows will be smoother
* at the cost of performance
*/
PCFPOISSON,
/**
* 8x8 percentage-closer filtering is used. Shadows will be smoother
* at the cost of performance
*/
PCF8
}
/**
@ -116,6 +124,7 @@ public class PssmShadowRenderer implements SceneProcessor {
Hardware;
}
private int nbSplits = 3;
private float shadowMapSize;
private float lambda = 0.65f;
private float shadowIntensity = 0.7f;
private float zFarOverride = 0;
@ -172,6 +181,7 @@ public class PssmShadowRenderer implements SceneProcessor {
assetManager = manager;
nbSplits = Math.max(Math.min(nbSplits, 4), 1);
this.nbSplits = nbSplits;
shadowMapSize = size;
shadowFB = new FrameBuffer[nbSplits];
shadowMaps = new Texture2D[nbSplits];
@ -185,7 +195,8 @@ public class PssmShadowRenderer implements SceneProcessor {
preshadowMat = new Material(manager, "Common/MatDefs/Shadow/PreShadow.j3md");
this.postshadowMat = postShadowMat;
postshadowMat.setFloat("ShadowMapSize", size);
for (int i = 0; i < nbSplits; i++) {
lightViewProjectionsMatrices[i] = new Matrix4f();
shadowFB[i] = new FrameBuffer(size, size, 1);
@ -213,7 +224,7 @@ public class PssmShadowRenderer implements SceneProcessor {
for (int i = 0; i < points.length; i++) {
points[i] = new Vector3f();
}
}
/**
@ -315,7 +326,7 @@ public class PssmShadowRenderer implements SceneProcessor {
//checking for caps to chosse the appropriate post material technique
if (renderManager.getRenderer().getCaps().contains(Caps.GLSL150)) {
postTechniqueName = "PostShadow15";
}else{
} else {
postTechniqueName = "PostShadow";
}
}
@ -423,7 +434,7 @@ public class PssmShadowRenderer implements SceneProcessor {
renderManager.setCamera(cam, true);
int h = cam.getHeight();
for (int i = 0; i < dispPic.length; i++) {
dispPic[i].setPosition(64 * (i + 1) + 128 * i, h / 20f);
dispPic[i].setPosition((128 * i) +(150 + 64 * (i + 1) ), h / 20f);
dispPic[i].setWidth(128);
dispPic[i].setHeight(128);
dispPic[i].updateGeometricState();
@ -448,16 +459,16 @@ public class PssmShadowRenderer implements SceneProcessor {
if (needsfallBackMaterial) {
renderManager.setForcedMaterial(postshadowMat);
}
//forcing the post shadow technique
//forcing the post shadow technique and render state
renderManager.setForcedTechnique(postTechniqueName);
//rendering the post shadow pass
viewPort.getQueue().renderShadowQueue(ShadowMode.Receive, renderManager, cam, flushQueues);
//resetting renderManager settings
renderManager.setForcedTechnique(null);
renderManager.setForcedMaterial(null);
renderManager.setForcedMaterial(null);
renderManager.setCamera(cam, false);
}
@ -469,7 +480,7 @@ public class PssmShadowRenderer implements SceneProcessor {
private void setMatParams() {
GeometryList l = viewPort.getQueue().getShadowQueueContent(ShadowMode.Receive);
//iteratin throught all the geometries of the list to set the material params
for (int i = 0; i < l.size(); i++) {
Material mat = l.get(i).getMaterial();
@ -485,7 +496,10 @@ public class PssmShadowRenderer implements SceneProcessor {
mat.setInt("FilterMode", filterMode.ordinal());
mat.setFloat("PCFEdge", edgesThickness);
mat.setFloat("ShadowIntensity", shadowIntensity);
} else {
if(mat.getParam("ShadowMapSize") == null){
mat.setFloat("ShadowMapSize", shadowMapSize);
}
} else {
needsfallBackMaterial = true;
}
}

@ -29,98 +29,143 @@
* 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.font.BitmapText;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
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.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.AbstractControl;
import com.jme3.scene.control.Control;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Sphere;
import com.jme3.shadow.PssmShadowRenderer;
import com.jme3.shadow.PssmShadowRenderer.CompareMode;
import com.jme3.shadow.PssmShadowRenderer.FilterMode;
import java.util.Random;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture.WrapMode;
import com.jme3.util.SkyFactory;
import com.jme3.util.TangentBinormalGenerator;
public class TestPssmShadow extends SimpleApplication implements ActionListener {
private Spatial teapot;
private Spatial[] obj;
private Material[] mat;
private boolean renderShadows = true;
private boolean hardwareShadows = false;
private PssmShadowRenderer pssmRenderer;
private Geometry ground;
private Material matGroundU;
private Material matGroundL;
public static void main(String[] args){
public static void main(String[] args) {
TestPssmShadow app = new TestPssmShadow();
app.start();
}
public void loadScene(){
Material mat = assetManager.loadMaterial("Common/Materials/RedColor.j3m");
Material matSoil = new Material(assetManager,"Common/MatDefs/Misc/Unshaded.j3md");
matSoil.setColor("Color", ColorRGBA.Cyan);
public void loadScene() {
obj = new Spatial[2];
mat = new Material[2];
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("Diffuse", ColorRGBA.White.clone());
teapot = new Geometry("sphere", new Sphere(30, 30, 2));
// teapot = new Geometry("cube", new Box(1.0f, 1.0f, 1.0f));
// teapot = assetManager.loadModel("Models/Teapot/Teapot.obj");
teapot.setLocalTranslation(0,0,10);
teapot.setMaterial(mat);
teapot.setShadowMode(ShadowMode.CastAndReceive);
rootNode.attachChild(teapot);
obj[0] = new Geometry("sphere", new Sphere(30, 30, 2));
obj[0].setShadowMode(ShadowMode.CastAndReceive);
obj[1] = new Geometry("cube", new Box(1.0f, 1.0f, 1.0f));
obj[1].setShadowMode(ShadowMode.CastAndReceive);
TangentBinormalGenerator.generate(obj[1]);
TangentBinormalGenerator.generate(obj[0]);
long seed = 1294719330150L; //System.currentTimeMillis();
Random random = new Random(seed);
System.out.println(seed);
for (int i = 0; i < 30; i++) {
Spatial t = teapot.clone(false);
for (int i = 0; i < 60; i++) {
Spatial 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);
teapot.setLocalTranslation((float) random.nextFloat() * 3, (float) random.nextFloat() * 3, (i + 2));
t.setLocalTranslation(FastMath.nextRandomFloat() * 200f, FastMath.nextRandomFloat() * 30f + 20, 30f * (i + 2f));
}
Geometry soil = new Geometry("soil", new Box(new Vector3f(0, -13, 550), 800, 10, 700));
soil.setMaterial(matSoil);
soil.setShadowMode(ShadowMode.Receive);
rootNode.attachChild(soil);
Box b = new Box(new Vector3f(0, 10, 550), 1000, 2, 1000);
b.scaleTextureCoordinates(new Vector2f(10, 10));
ground = new Geometry("soil", b);
matGroundU = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
matGroundU.setColor("Color", ColorRGBA.Green);
matGroundL = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg");
grass.setWrap(WrapMode.Repeat);
matGroundL.setTexture("DiffuseMap", grass);
ground.setMaterial(matGroundL);
ground.setShadowMode(ShadowMode.CastAndReceive);
rootNode.attachChild(ground);
for (int i = 0; i < 30; i++) {
Spatial t = teapot.clone(false);
t.setLocalScale(10.0f);
rootNode.attachChild(t);
teapot.setLocalTranslation((float) random.nextFloat() * 300, (float) random.nextFloat() * 30, 30 * (i + 2));
}
DirectionalLight l = new DirectionalLight();
l.setDirection(new Vector3f(-1, -1, -1));
rootNode.addLight(l);
AmbientLight al = new AmbientLight();
al.setColor(ColorRGBA.White.mult(0.5f));
rootNode.addLight(al);
Spatial sky = SkyFactory.createSky(assetManager, "Scenes/Beach/FullskiesSunset0068.dds", false);
sky.setLocalScale(350);
rootNode.attachChild(sky);
}
@Override
public void simpleInitApp() {
// put the camera in a bad position
cam.setLocation(new Vector3f(41.59757f, 34.38738f, 11.528807f));
cam.setRotation(new Quaternion(0.2905285f, 0.3816416f, -0.12772122f, 0.86811876f));
cam.setLocation(new Vector3f(65.25412f, 44.38738f, 9.087874f));
cam.setRotation(new Quaternion(0.078139365f, 0.050241485f, -0.003942559f, 0.9956679f));
flyCam.setMoveSpeed(100);
loadScene();
pssmRenderer = new PssmShadowRenderer(assetManager, 1024, 3);
pssmRenderer.setDirection(new Vector3f(-1, -1, -1).normalizeLocal());
pssmRenderer.setLambda(0.55f);
pssmRenderer.setShadowIntensity(0.6f);
pssmRenderer.setCompareMode(CompareMode.Software);
pssmRenderer.setFilterMode(FilterMode.Bilinear);
pssmRenderer.setFilterMode(FilterMode.Dither);
pssmRenderer.displayDebug();
viewPort.addProcessor(pssmRenderer);
initInputs();
}
BitmapText infoText;
private void initInputs() {
/** Write text on the screen (HUD) */
guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
infoText = new BitmapText(guiFont, false);
infoText.setSize(guiFont.getCharSet().getRenderedSize());
private void initInputs() {
inputManager.addMapping("toggle", new KeyTrigger(KeyInput.KEY_SPACE));
inputManager.addMapping("changeFiltering", new KeyTrigger(KeyInput.KEY_F));
inputManager.addMapping("ShadowUp", new KeyTrigger(KeyInput.KEY_T));
inputManager.addMapping("ShadowDown", new KeyTrigger(KeyInput.KEY_G));
inputManager.addMapping("ThicknessUp", new KeyTrigger(KeyInput.KEY_Y));
@ -128,9 +173,46 @@ public class TestPssmShadow extends SimpleApplication implements ActionListener
inputManager.addMapping("lambdaUp", new KeyTrigger(KeyInput.KEY_U));
inputManager.addMapping("lambdaDown", new KeyTrigger(KeyInput.KEY_J));
inputManager.addMapping("toggleHW", new KeyTrigger(KeyInput.KEY_RETURN));
inputManager.addListener(this, "lambdaUp", "lambdaDown", "toggleHW", "toggle", "ShadowUp","ShadowDown","ThicknessUp","ThicknessDown");
inputManager.addMapping("switchGroundMat", new KeyTrigger(KeyInput.KEY_M));
inputManager.addListener(this, "lambdaUp", "lambdaDown", "toggleHW", "toggle", "ShadowUp", "ShadowDown", "ThicknessUp", "ThicknessDown","changeFiltering","switchGroundMat");
}
private void print(String str) {
infoText.setText(str);
infoText.setLocalTranslation(cam.getWidth() * 0.5f - infoText.getLineWidth() * 0.5f, infoText.getLineHeight(), 0);
guiNode.attachChild(infoText);
infoText.removeControl(ctrl);
infoText.addControl(ctrl);
}
AbstractControl ctrl = new AbstractControl() {
float time;
@Override
protected void controlUpdate(float tpf) {
time += tpf;
if (time > 3) {
spatial.removeFromParent();
spatial.removeControl(this);
}
}
@Override
public void setSpatial(Spatial spatial) {
super.setSpatial(spatial);
time = 0;
}
@Override
protected void controlRender(RenderManager rm, ViewPort vp) {
}
public Control cloneForSpatial(Spatial spatial) {
return null;
}
};
int filteringIndex = 2;
public void onAction(String name, boolean keyPressed, float tpf) {
if (name.equals("toggle") && keyPressed) {
if (renderShadows) {
@ -146,6 +228,13 @@ public class TestPssmShadow extends SimpleApplication implements ActionListener
System.out.println("HW Shadows: " + hardwareShadows);
}
if (name.equals("changeFiltering") && keyPressed) {
filteringIndex = (filteringIndex + 1) % FilterMode.values().length;
FilterMode m = FilterMode.values()[filteringIndex];
pssmRenderer.setFilterMode(m);
print("Filter mode : " + m.toString());
}
if (name.equals("lambdaUp") && keyPressed) {
pssmRenderer.setLambda(pssmRenderer.getLambda() + 0.01f);
System.out.println("Lambda : " + pssmRenderer.getLambda());
@ -170,7 +259,13 @@ public class TestPssmShadow extends SimpleApplication implements ActionListener
pssmRenderer.setEdgesThickness(pssmRenderer.getEdgesThickness() - 1);
System.out.println("Shadow thickness : " + pssmRenderer.getEdgesThickness());
}
if (name.equals("switchGroundMat") && keyPressed) {
if(ground.getMaterial() == matGroundL){
ground.setMaterial(matGroundU);
}else{
ground.setMaterial(matGroundL);
}
}
}
}

@ -72,7 +72,7 @@ public class TestTransparentShadow extends SimpleApplication {
geom.rotate(-FastMath.HALF_PI, 0, 0);
geom.center();
geom.setShadowMode(ShadowMode.Receive);
geom.setShadowMode(ShadowMode.CastAndReceive);
rootNode.attachChild(geom);
// create the geometry and attach it
@ -132,6 +132,6 @@ public class TestTransparentShadow extends SimpleApplication {
pssmRenderer.setCompareMode(CompareMode.Software);
pssmRenderer.setFilterMode(FilterMode.PCF4);
//pssmRenderer.displayDebug();
viewPort.addProcessor(pssmRenderer);
viewPort.addProcessor(pssmRenderer);
}
}

@ -12,6 +12,7 @@ import com.jme3.renderer.queue.RenderQueue.ShadowMode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Quad;
import com.jme3.util.TangentBinormalGenerator;
public class TestTransparentSSAO extends SimpleApplication {
@ -39,6 +40,7 @@ public class TestTransparentSSAO extends SimpleApplication {
geom.rotate(-FastMath.HALF_PI, 0, 0);
geom.center();
geom.setShadowMode(ShadowMode.Receive);
TangentBinormalGenerator.generate(geom);
rootNode.attachChild(geom);
// create the geometry and attach it
@ -64,7 +66,7 @@ public class TestTransparentSSAO extends SimpleApplication {
FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
SSAOFilter ssao = new SSAOFilter(0.49997783f, 42.598858f, 35.999966f, 0.39299846f);
SSAOFilter ssao = new SSAOFilter();//0.49997783f, 42.598858f, 35.999966f, 0.39299846f
fpp.addFilter(ssao);
SSAOUI ui = new SSAOUI(inputManager, ssao);

@ -4,7 +4,8 @@ Material Leaves : Common/MatDefs/Light/Lighting.j3md {
MaterialParameters {
DiffuseMap : Models/Tree/Leaves.png
UseAlpha : true
UseAlpha : true
AlphaDiscardThreshold : 0.5
UseMaterialColors : true
Ambient : .5 .5 .5 .5
Diffuse : 0.7 0.7 0.7 1

Loading…
Cancel
Save