diff --git a/engine/src/core-data/Common/MatDefs/Shadow/PostShadowFilter.frag b/engine/src/core-data/Common/MatDefs/Shadow/PostShadowFilter.frag
new file mode 100644
index 000000000..a11d73d5b
--- /dev/null
+++ b/engine/src/core-data/Common/MatDefs/Shadow/PostShadowFilter.frag
@@ -0,0 +1,68 @@
+#import "Common/ShaderLib/PssmShadows.glsllib"
+
+uniform sampler2D m_Texture;
+uniform sampler2D m_DepthTexture;
+uniform mat4 m_ViewProjectionMatrixInverse;
+uniform vec4 m_ViewProjectionMatrixRow2;
+
+varying vec2 texCoord;
+
+
+const mat4 biasMat = mat4(0.5, 0.0, 0.0, 0.0,
+ 0.0, 0.5, 0.0, 0.0,
+ 0.0, 0.0, 0.5, 0.0,
+ 0.5, 0.5, 0.5, 1.0);
+
+uniform mat4 m_LightViewProjectionMatrix0;
+uniform mat4 m_LightViewProjectionMatrix1;
+uniform mat4 m_LightViewProjectionMatrix2;
+uniform mat4 m_LightViewProjectionMatrix3;
+
+vec3 getPosition(in float depth, in vec2 uv){
+ vec4 pos = vec4(uv, depth, 1.0) * 2.0 - 1.0;
+ pos = m_ViewProjectionMatrixInverse * pos;
+ return pos.xyz / pos.w;
+}
+
+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;
+ return;
+ }
+
+ // get the vertex in world space
+ vec4 worldPos = vec4(getPosition(depth,texCoord),1.0);
+
+ // populate the light view matrices array and convert vertex to light viewProj space
+ vec4 projCoord0 = biasMat * m_LightViewProjectionMatrix0 * worldPos;
+ vec4 projCoord1 = biasMat * m_LightViewProjectionMatrix1 * worldPos;
+ vec4 projCoord2 = biasMat * m_LightViewProjectionMatrix2 * worldPos;
+ vec4 projCoord3 = biasMat * m_LightViewProjectionMatrix3 * worldPos;
+
+
+ float shadowPosition = m_ViewProjectionMatrixRow2.x * worldPos.x + m_ViewProjectionMatrixRow2.y * worldPos.y + m_ViewProjectionMatrixRow2.z * worldPos.z + m_ViewProjectionMatrixRow2.w;
+
+ float shadow = 0.0;
+ if(shadowPosition < m_Splits.x){
+ shadow = GETSHADOW(m_ShadowMap0, projCoord0);
+ }else if( shadowPosition < m_Splits.y){
+ shadowBorderScale = 0.5;
+ shadow = GETSHADOW(m_ShadowMap1, projCoord1);
+ }else if( shadowPosition < m_Splits.z){
+ shadowBorderScale = 0.25;
+ shadow = GETSHADOW(m_ShadowMap2, projCoord2);
+ }else if( shadowPosition < m_Splits.w){
+ shadowBorderScale = 0.125;
+ shadow = GETSHADOW(m_ShadowMap3, projCoord3);
+ }
+
+ shadow= shadow * m_ShadowIntensity + (1.0 - m_ShadowIntensity);
+ gl_FragColor = color * vec4(shadow, shadow, shadow, 1.0);
+
+}
+
diff --git a/engine/src/core-data/Common/MatDefs/Shadow/PostShadowFilter.j3md b/engine/src/core-data/Common/MatDefs/Shadow/PostShadowFilter.j3md
new file mode 100644
index 000000000..1a611908a
--- /dev/null
+++ b/engine/src/core-data/Common/MatDefs/Shadow/PostShadowFilter.j3md
@@ -0,0 +1,73 @@
+MaterialDef Post Shadow {
+
+ MaterialParameters {
+ Int FilterMode
+ Boolean HardwareShadows
+
+ Texture2D ShadowMap0
+ Texture2D ShadowMap1
+ Texture2D ShadowMap2
+ Texture2D ShadowMap3
+
+ Float ShadowIntensity
+ Vector4 Splits
+
+ Matrix4 LightViewProjectionMatrix0
+ Matrix4 LightViewProjectionMatrix1
+ Matrix4 LightViewProjectionMatrix2
+ Matrix4 LightViewProjectionMatrix3
+
+ Float PCFEdge
+
+ Float ShadowMapSize
+
+ Matrix4 ViewProjectionMatrixInverse
+ Vector4 ViewProjectionMatrixRow2
+
+ Int NumSamples
+ Int NumSamplesDepth
+ Texture2D Texture
+ Texture2D DepthTexture
+
+ }
+
+ Technique {
+ VertexShader GLSL150: Common/MatDefs/Shadow/PostShadowFilter15.vert
+ FragmentShader GLSL150: Common/MatDefs/Shadow/PostShadowFilter15.frag
+
+ WorldParameters {
+ WorldViewProjectionMatrix
+ }
+
+ Defines {
+ RESOLVE_MS : NumSamples
+ RESOLVE_DEPTH_MS : NumSamplesDepth
+ HARDWARE_SHADOWS : HardwareShadows
+ FILTER_MODE : FilterMode
+ PCFEDGE : PCFEdge
+ SHADOWMAP_SIZE : ShadowMapSize
+ }
+
+ }
+
+ Technique {
+ VertexShader GLSL100: Common/MatDefs/Shadow/PostShadowFilter.vert
+ FragmentShader GLSL100: Common/MatDefs/Shadow/PostShadowFilter.frag
+
+ WorldParameters {
+ WorldViewProjectionMatrix
+ }
+
+ Defines {
+ HARDWARE_SHADOWS : HardwareShadows
+ FILTER_MODE : FilterMode
+ PCFEDGE : PCFEdge
+ SHADOWMAP_SIZE : ShadowMapSize
+ }
+
+ }
+
+
+
+
+}
\ No newline at end of file
diff --git a/engine/src/core-data/Common/MatDefs/Shadow/PostShadowFilter.vert b/engine/src/core-data/Common/MatDefs/Shadow/PostShadowFilter.vert
new file mode 100644
index 000000000..6d80905cd
--- /dev/null
+++ b/engine/src/core-data/Common/MatDefs/Shadow/PostShadowFilter.vert
@@ -0,0 +1,10 @@
+uniform mat4 g_WorldViewProjectionMatrix;
+
+attribute vec4 inPosition;
+attribute vec2 inTexCoord;
+varying vec2 texCoord;
+
+void main() {
+ gl_Position = inPosition * 2.0 - 1.0; //vec4(pos, 0.0, 1.0);
+ texCoord = inTexCoord;
+}
\ No newline at end of file
diff --git a/engine/src/core-data/Common/MatDefs/Shadow/PostShadowFilter15.frag b/engine/src/core-data/Common/MatDefs/Shadow/PostShadowFilter15.frag
new file mode 100644
index 000000000..00832ae90
--- /dev/null
+++ b/engine/src/core-data/Common/MatDefs/Shadow/PostShadowFilter15.frag
@@ -0,0 +1,84 @@
+#import "Common/ShaderLib/MultiSample.glsllib"
+#import "Common/ShaderLib/PssmShadows15.glsllib"
+
+
+uniform COLORTEXTURE m_Texture;
+uniform DEPTHTEXTURE m_DepthTexture;
+uniform mat4 m_ViewProjectionMatrixInverse;
+uniform vec4 m_ViewProjectionMatrixRow2;
+
+in vec2 texCoord;
+out vec4 outFragColor;
+
+const mat4 biasMat = mat4(0.5, 0.0, 0.0, 0.0,
+ 0.0, 0.5, 0.0, 0.0,
+ 0.0, 0.0, 0.5, 0.0,
+ 0.5, 0.5, 0.5, 1.0);
+
+uniform mat4 m_LightViewProjectionMatrix0;
+uniform mat4 m_LightViewProjectionMatrix1;
+uniform mat4 m_LightViewProjectionMatrix2;
+uniform mat4 m_LightViewProjectionMatrix3;
+
+
+vec3 getPosition(in float depth, in vec2 uv){
+ vec4 pos = vec4(uv, depth, 1.0) * 2.0 - 1.0;
+ pos = m_ViewProjectionMatrixInverse * pos;
+ return pos.xyz / pos.w;
+}
+
+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);
+
+ //Discard shadow computation on the sky
+ if(depth == 1.0){
+ return color;
+ }
+
+ // get the vertex in world space
+ vec4 worldPos = vec4(getPosition(depth,texCoord),1.0);
+
+ // populate the light view matrices array and convert vertex to light viewProj space
+ vec4 projCoord0 = biasMat * m_LightViewProjectionMatrix0 * worldPos;
+ vec4 projCoord1 = biasMat * m_LightViewProjectionMatrix1 * worldPos;
+ vec4 projCoord2 = biasMat * m_LightViewProjectionMatrix2 * worldPos;
+ vec4 projCoord3 = biasMat * m_LightViewProjectionMatrix3 * worldPos;
+
+ float shadowPosition = m_ViewProjectionMatrixRow2.x * worldPos.x + m_ViewProjectionMatrixRow2.y * worldPos.y + m_ViewProjectionMatrixRow2.z * worldPos.z + m_ViewProjectionMatrixRow2.w;
+
+float shadow = 0.0;
+ if(shadowPosition < m_Splits.x){
+ shadow = GETSHADOW(m_ShadowMap0, projCoord0);
+ }else if( shadowPosition < m_Splits.y){
+ shadowBorderScale = 0.5;
+ shadow = GETSHADOW(m_ShadowMap1, projCoord1);
+ }else if( shadowPosition < m_Splits.z){
+ shadowBorderScale = 0.25;
+ shadow = GETSHADOW(m_ShadowMap2, projCoord2);
+ }else if( shadowPosition < m_Splits.w){
+ shadowBorderScale = 0.125;
+ shadow = GETSHADOW(m_ShadowMap3, projCoord3);
+ }
+
+ shadow= shadow * m_ShadowIntensity + (1.0 - m_ShadowIntensity);
+
+ return color * vec4(shadow, shadow, shadow, 1.0);
+}
+
+void main(){
+
+ #ifdef RESOLVE_MS
+ vec4 color = vec4(0.0);
+ for (int i = 0; i < m_NumSamples; i++){
+ color += main_multiSample(i);
+ }
+ outFragColor = color / m_NumSamples;
+ #else
+ outFragColor = main_multiSample(0);
+ #endif
+
+}
+
+
+
diff --git a/engine/src/core-data/Common/MatDefs/Shadow/PostShadowFilter15.vert b/engine/src/core-data/Common/MatDefs/Shadow/PostShadowFilter15.vert
new file mode 100644
index 000000000..367c3306b
--- /dev/null
+++ b/engine/src/core-data/Common/MatDefs/Shadow/PostShadowFilter15.vert
@@ -0,0 +1,12 @@
+uniform mat4 g_WorldViewProjectionMatrix;
+
+in vec4 inPosition;
+in vec2 inTexCoord;
+
+out vec2 texCoord;
+
+void main() {
+ vec2 pos = (g_WorldViewProjectionMatrix * inPosition).xy;
+ gl_Position = vec4(pos, 0.0, 1.0);
+ texCoord = inTexCoord;
+}
\ No newline at end of file
diff --git a/engine/src/core-data/Common/MatDefs/Shadow/PostShadowPSSM.frag b/engine/src/core-data/Common/MatDefs/Shadow/PostShadowPSSM.frag
index 17413d1ad..27e768d71 100644
--- a/engine/src/core-data/Common/MatDefs/Shadow/PostShadowPSSM.frag
+++ b/engine/src/core-data/Common/MatDefs/Shadow/PostShadowPSSM.frag
@@ -1,176 +1,11 @@
-#ifdef HARDWARE_SHADOWS
- #define SHADOWMAP sampler2DShadow
- #define SHADOWCOMPARE(tex,coord) shadow2DProj(tex, coord).r
-#else
- #define SHADOWMAP sampler2D
- #define SHADOWCOMPARE(tex,coord) step(coord.z, texture2DProj(tex, coord).r)
-#endif
-
-#if FILTER_MODE == 0
- #define GETSHADOW Shadow_DoShadowCompare
- #define KERNEL 1.0
-#elif FILTER_MODE == 1
- #ifdef HARDWARE_SHADOWS
- #define GETSHADOW Shadow_DoShadowCompare
- #else
- #define GETSHADOW Shadow_DoBilinear_2x2
- #endif
- #define KERNEL 1.0
-#elif FILTER_MODE == 2
- #define GETSHADOW Shadow_DoDither_2x2
- #define KERNEL 1.0
-#elif FILTER_MODE == 3
- #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
-
-
-uniform SHADOWMAP m_ShadowMap0;
-uniform SHADOWMAP m_ShadowMap1;
-uniform SHADOWMAP m_ShadowMap2;
-uniform SHADOWMAP m_ShadowMap3;
-
-uniform vec4 m_Splits;
-
-uniform float m_ShadowIntensity;
+#import "Common/ShaderLib/PssmShadows.glsllib"
+varying float shadowPosition;
varying vec4 projCoord0;
varying vec4 projCoord1;
varying vec4 projCoord2;
varying vec4 projCoord3;
-varying float shadowPosition;
-
-
-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);
- return SHADOWCOMPARE(tex, coord);
-}
-
-float Shadow_DoShadowCompare(in SHADOWMAP tex, vec4 projCoord){
- return SHADOWCOMPARE(tex, projCoord);
-}
-
-float Shadow_BorderCheck(in vec2 coord){
- // Fastest, "hack" method (uses 4-5 instructions)
- vec4 t = vec4(coord.xy, 0.0, 1.0);
- t = step(t.wwxy, t.xyzz);
- return dot(t,t);
-}
-
-float Shadow_DoDither_2x2(in SHADOWMAP tex, in vec4 projCoord){
- float border = Shadow_BorderCheck(projCoord.xy);
- if (border > 0.0)
- return 1.0;
-
-
- float shadow = 0.0;
- vec2 o = mod(floor(gl_FragCoord.xy), 2.0);
- shadow += Shadow_DoShadowCompareOffset(tex,projCoord,vec2(-1.5, 1.5) + o);
- shadow += Shadow_DoShadowCompareOffset(tex,projCoord,vec2( 0.5, 1.5) + o);
- shadow += Shadow_DoShadowCompareOffset(tex,projCoord,vec2(-1.5, -0.5) + o);
- shadow += Shadow_DoShadowCompareOffset(tex,projCoord,vec2( 0.5, -0.5) + o);
- shadow *= 0.25 ;
- return shadow;
-}
-
-float Shadow_DoBilinear_2x2(in SHADOWMAP tex, in vec4 projCoord){
- float border = Shadow_BorderCheck(projCoord.xy);
- if (border > 0.0)
- return 1.0;
- vec4 gather = vec4(0.0);
- gather.x = Shadow_DoShadowCompareOffset(tex, projCoord, vec2(0.0, 0.0));
- gather.y = Shadow_DoShadowCompareOffset(tex, projCoord, vec2(1.0, 0.0));
- 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 * 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 shadow = 0.0;
- float border = Shadow_BorderCheck(projCoord.xy);
- if (border > 0.0)
- return 1.0;
- float bound = KERNEL * 0.5 - 0.5;
- bound *= PCFEDGE;
- for (float y = -bound; y <= bound; y += PCFEDGE){
- for (float x = -bound; x <= bound; x += PCFEDGE){
- shadow += clamp(Shadow_DoShadowCompareOffset(tex,projCoord,vec2(x,y)) +
- border,
- 0.0, 1.0);
- }
- }
-
- shadow = shadow / (KERNEL * KERNEL);
- return shadow;
-}
-
-
-//12 tap poisson disk
-/*
-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));
-*/
- const vec2 poissonDisk0 = vec2(-0.1711046, -0.425016);
- const vec2 poissonDisk1 = vec2(-0.7829809, 0.2162201);
- const vec2 poissonDisk2 = vec2(-0.2380269, -0.8835521);
- const vec2 poissonDisk3 = vec2(0.4198045, 0.1687819);
- const vec2 poissonDisk4 = vec2(-0.684418, -0.3186957);
- const vec2 poissonDisk5 = vec2(0.6026866, -0.2587841);
- const vec2 poissonDisk6 = vec2(-0.2412762, 0.3913516);
- const vec2 poissonDisk7 = vec2(0.4720655, -0.7664126);
- const vec2 poissonDisk8 = vec2(0.9571564, 0.2680693);
- const vec2 poissonDisk9 = vec2(-0.5238616, 0.802707);
- const vec2 poissonDisk10 = vec2(0.5653144, 0.60262);
- const vec2 poissonDisk11 = 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 , poissonDisk0 * texelSize);
- shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk1 * texelSize);
- shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk2 * texelSize);
- shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk3 * texelSize);
- shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk4 * texelSize);
- shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk5 * texelSize);
- shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk6 * texelSize);
- shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk7 * texelSize);
- shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk8 * texelSize);
- shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk9 * texelSize);
- shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk10 * texelSize);
- shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk11 * texelSize);
-
- shadow = shadow * 0.08333333333;//this is divided by 12
- return shadow;
-}
-
#ifdef DISCARD_ALPHA
#ifdef COLOR_MAP
uniform sampler2D m_ColorMap;
@@ -194,37 +29,22 @@ void main(){
}
#endif
-
-
- vec4 shadowPerSplit = vec4(0.0);
-float shadow;
-//shadowPosition
+
+ float shadow = 0.0;
if(shadowPosition < m_Splits.x){
- shadow= GETSHADOW(m_ShadowMap0, projCoord0);
+ shadow = GETSHADOW(m_ShadowMap0, projCoord0);
}else if( shadowPosition < m_Splits.y){
- scale = 0.5;
+ shadowBorderScale = 0.5;
shadow = GETSHADOW(m_ShadowMap1, projCoord1);
}else if( shadowPosition < m_Splits.z){
- scale = 0.25;
- shadow= GETSHADOW(m_ShadowMap2, projCoord2);
+ shadowBorderScale = 0.25;
+ shadow = GETSHADOW(m_ShadowMap2, projCoord2);
}else if( shadowPosition < m_Splits.w){
- scale = 0.125;
- shadow= GETSHADOW(m_ShadowMap3, projCoord3);
+ shadowBorderScale = 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(shadow, shadow, shadow, 1.0);
diff --git a/engine/src/core-data/Common/MatDefs/Shadow/PostShadowPSSM15.frag b/engine/src/core-data/Common/MatDefs/Shadow/PostShadowPSSM15.frag
index 816e9387c..c2c256078 100644
--- a/engine/src/core-data/Common/MatDefs/Shadow/PostShadowPSSM15.frag
+++ b/engine/src/core-data/Common/MatDefs/Shadow/PostShadowPSSM15.frag
@@ -1,172 +1,11 @@
-// Because gpu_shader5 is actually where those
-// gather functions are declared to work on shadowmaps
-#extension GL_ARB_gpu_shader5 : enable
-
-#ifdef HARDWARE_SHADOWS
- #define SHADOWMAP sampler2DShadow
- #define SHADOWCOMPAREOFFSET(tex,coord,offset) textureProjOffset(tex, coord, offset)
- #define SHADOWCOMPARE(tex,coord) textureProj(tex, coord)
- #define SHADOWGATHER(tex,coord) textureGather(tex, coord.xy, coord.z)
-#else
- #define SHADOWMAP sampler2D
- #define SHADOWCOMPAREOFFSET(tex,coord,offset) step(coord.z, textureProjOffset(tex, coord, offset).r)
- #define SHADOWCOMPARE(tex,coord) step(coord.z, textureProj(tex, coord).r)
- #define SHADOWGATHER(tex,coord) step(coord.z, textureGather(tex, coord.xy))
-#endif
-
-
-#if FILTER_MODE == 0
- #define GETSHADOW SHADOWCOMPARE
- #define KERNEL 1
-#elif FILTER_MODE == 1
- #ifdef HARDWARE_SHADOWS
- #define GETSHADOW SHADOWCOMPARE
- #else
- #define GETSHADOW Shadow_DoBilinear_2x2
- #endif
- #define KERNEL 1
-#elif FILTER_MODE == 2
- #define GETSHADOW Shadow_DoDither_2x2
- #define KERNEL 1
-#elif FILTER_MODE == 3
- #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
+#import "Common/ShaderLib/PssmShadows15.glsllib"
out vec4 outFragColor;
-
-uniform SHADOWMAP m_ShadowMap0;
-uniform SHADOWMAP m_ShadowMap1;
-uniform SHADOWMAP m_ShadowMap2;
-uniform SHADOWMAP m_ShadowMap3;
-
-uniform vec4 m_Splits;
-uniform float m_ShadowIntensity;
-
+in float shadowPosition;
in vec4 projCoord0;
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)
- vec4 t = vec4(coord.xy, 0.0, 1.0);
- t = step(t.wwxy, t.xyzz);
- return dot(t,t);
-}
-
-float Shadow_DoDither_2x2(in SHADOWMAP tex, in vec4 projCoord){
- float border = Shadow_BorderCheck(projCoord.xy);
- if (border > 0.0)
- return 1.0;
-
- 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));
- shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy+pixSize*(vec2( 0.5, 1.5)+o), projCoord.zw));
- shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy+pixSize*(vec2(-1.5, -0.5)+o), projCoord.zw));
- shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy+pixSize*(vec2( 0.5, -0.5)+o), projCoord.zw));
- shadow *= 0.25;
- return shadow;
-}
-
-float Shadow_DoBilinear_2x2(in SHADOWMAP tex, in vec4 projCoord){
- float border = Shadow_BorderCheck(projCoord.xy);
- if (border > 0.0)
- return 1.0;
-
- #ifdef GL_ARB_gpu_shader5
- vec4 coord = vec4(projCoord.xyz / projCoord.www,0.0);
- vec4 gather = SHADOWGATHER(tex, coord);
- #else
- vec4 gather = vec4(0.0);
- gather.x = SHADOWCOMPAREOFFSET(tex, projCoord, ivec2(0, 0));
- gather.y = SHADOWCOMPAREOFFSET(tex, projCoord, ivec2(1, 0));
- gather.z = SHADOWCOMPAREOFFSET(tex, projCoord, ivec2(0, 1));
- gather.w = SHADOWCOMPAREOFFSET(tex, projCoord, ivec2(1, 1));
- #endif
-
- 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){
-
- vec2 pixSize = pixSize2 * scale;
- float shadow = 0.0;
- float border = Shadow_BorderCheck(projCoord.xy);
- if (border > 0.0)
- return 1.0;
-
- float bound = KERNEL * 0.5 - 0.5;
- bound *= PCFEDGE;
- for (float y = -bound; y <= bound; y += PCFEDGE){
- for (float x = -bound; x <= bound; x += PCFEDGE){
- vec4 coord = vec4(projCoord.xy + vec2(x,y) * pixSize, projCoord.zw);
- shadow += SHADOWCOMPARE(tex, coord);
- }
- }
-
- shadow = shadow / (KERNEL * KERNEL);
- return shadow;
-}
-
-
-//12 tap poisson disk
- const vec2 poissonDisk0 = vec2(-0.1711046, -0.425016);
- const vec2 poissonDisk1 = vec2(-0.7829809, 0.2162201);
- const vec2 poissonDisk2 = vec2(-0.2380269, -0.8835521);
- const vec2 poissonDisk3 = vec2(0.4198045, 0.1687819);
- const vec2 poissonDisk4 = vec2(-0.684418, -0.3186957);
- const vec2 poissonDisk5 = vec2(0.6026866, -0.2587841);
- const vec2 poissonDisk6 = vec2(-0.2412762, 0.3913516);
- const vec2 poissonDisk7 = vec2(0.4720655, -0.7664126);
- const vec2 poissonDisk8 = vec2(0.9571564, 0.2680693);
- const vec2 poissonDisk9 = vec2(-0.5238616, 0.802707);
- const vec2 poissonDisk10 = vec2(0.5653144, 0.60262);
- const vec2 poissonDisk11 = 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;
-
- //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 + poissonDisk0 * texelSize, projCoord.zw));
- shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk1 * texelSize, projCoord.zw));
- shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk2 * texelSize, projCoord.zw));
- shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk3 * texelSize, projCoord.zw));
- shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk4 * texelSize, projCoord.zw));
- shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk5 * texelSize, projCoord.zw));
- shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk6 * texelSize, projCoord.zw));
- shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk7 * texelSize, projCoord.zw));
- shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk8 * texelSize, projCoord.zw));
- shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk9 * texelSize, projCoord.zw));
- shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk10 * texelSize, projCoord.zw));
- shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk11 * texelSize, projCoord.zw));
-
- shadow = shadow * 0.08333333333;//this is divided by 12
- return shadow;
-}
#ifdef DISCARD_ALPHA
#ifdef COLOR_MAP
@@ -179,9 +18,7 @@ float Shadow_DoPCFPoisson(in SHADOWMAP tex, in vec4 projCoord){
#endif
void main(){
- float shadow = 0.0;
-
-
+
#ifdef DISCARD_ALPHA
#ifdef COLOR_MAP
float alpha = texture2D(m_ColorMap,texCoord).a;
@@ -193,20 +30,24 @@ void main(){
discard;
}
#endif
+
+
+ float shadow = 0.0;
if(shadowPosition < m_Splits.x){
shadow = GETSHADOW(m_ShadowMap0, projCoord0);
}else if( shadowPosition < m_Splits.y){
- scale = 0.5;
+ shadowBorderScale = 0.5;
shadow = GETSHADOW(m_ShadowMap1, projCoord1);
}else if( shadowPosition < m_Splits.z){
- scale = 0.25;
+ shadowBorderScale = 0.25;
shadow = GETSHADOW(m_ShadowMap2, projCoord2);
}else if( shadowPosition < m_Splits.w){
- scale = 0.125;
+ shadowBorderScale = 0.125;
shadow = GETSHADOW(m_ShadowMap3, projCoord3);
}
- shadow = shadow * m_ShadowIntensity + (1.0 - m_ShadowIntensity);
+ shadow= shadow * m_ShadowIntensity + (1.0 - m_ShadowIntensity);
+
outFragColor = vec4(shadow, shadow, shadow, 1.0);
}
diff --git a/engine/src/core-data/Common/ShaderLib/PssmShadows.glsllib b/engine/src/core-data/Common/ShaderLib/PssmShadows.glsllib
new file mode 100644
index 000000000..1e53d86f3
--- /dev/null
+++ b/engine/src/core-data/Common/ShaderLib/PssmShadows.glsllib
@@ -0,0 +1,151 @@
+#ifdef HARDWARE_SHADOWS
+ #define SHADOWMAP sampler2DShadow
+ #define SHADOWCOMPARE(tex,coord) shadow2DProj(tex, coord).r
+#else
+ #define SHADOWMAP sampler2D
+ #define SHADOWCOMPARE(tex,coord) step(coord.z, texture2DProj(tex, coord).r)
+#endif
+
+#if FILTER_MODE == 0
+ #define GETSHADOW Shadow_DoShadowCompare
+ #define KERNEL 1.0
+#elif FILTER_MODE == 1
+ #ifdef HARDWARE_SHADOWS
+ #define GETSHADOW Shadow_DoShadowCompare
+ #else
+ #define GETSHADOW Shadow_DoBilinear_2x2
+ #endif
+ #define KERNEL 1.0
+#elif FILTER_MODE == 2
+ #define GETSHADOW Shadow_DoDither_2x2
+ #define KERNEL 1.0
+#elif FILTER_MODE == 3
+ #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
+
+
+uniform SHADOWMAP m_ShadowMap0;
+uniform SHADOWMAP m_ShadowMap1;
+uniform SHADOWMAP m_ShadowMap2;
+uniform SHADOWMAP m_ShadowMap3;
+
+uniform vec4 m_Splits;
+
+uniform float m_ShadowIntensity;
+
+const vec2 pixSize2 = vec2(1.0 / SHADOWMAP_SIZE);
+float shadowBorderScale = 1.0;
+
+float Shadow_DoShadowCompareOffset(in SHADOWMAP tex, in vec4 projCoord, in vec2 offset){
+ vec4 coord = vec4(projCoord.xy + offset.xy * pixSize2 * shadowBorderScale, projCoord.zw);
+ return SHADOWCOMPARE(tex, coord);
+}
+
+float Shadow_DoShadowCompare(in SHADOWMAP tex, vec4 projCoord){
+ return SHADOWCOMPARE(tex, projCoord);
+}
+
+float Shadow_BorderCheck(in vec2 coord){
+ // Fastest, "hack" method (uses 4-5 instructions)
+ vec4 t = vec4(coord.xy, 0.0, 1.0);
+ t = step(t.wwxy, t.xyzz);
+ return dot(t,t);
+}
+
+float Shadow_DoDither_2x2(in SHADOWMAP tex, in vec4 projCoord){
+ float border = Shadow_BorderCheck(projCoord.xy);
+ if (border > 0.0)
+ return 1.0;
+
+
+ float shadow = 0.0;
+ vec2 o = mod(floor(gl_FragCoord.xy), 2.0);
+ shadow += Shadow_DoShadowCompareOffset(tex,projCoord,vec2(-1.5, 1.5) + o);
+ shadow += Shadow_DoShadowCompareOffset(tex,projCoord,vec2( 0.5, 1.5) + o);
+ shadow += Shadow_DoShadowCompareOffset(tex,projCoord,vec2(-1.5, -0.5) + o);
+ shadow += Shadow_DoShadowCompareOffset(tex,projCoord,vec2( 0.5, -0.5) + o);
+ shadow *= 0.25 ;
+ return shadow;
+}
+
+float Shadow_DoBilinear_2x2(in SHADOWMAP tex, in vec4 projCoord){
+ float border = Shadow_BorderCheck(projCoord.xy);
+ if (border > 0.0)
+ return 1.0;
+ vec4 gather = vec4(0.0);
+ gather.x = Shadow_DoShadowCompareOffset(tex, projCoord, vec2(0.0, 0.0));
+ gather.y = Shadow_DoShadowCompareOffset(tex, projCoord, vec2(1.0, 0.0));
+ 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 * 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 shadow = 0.0;
+ float border = Shadow_BorderCheck(projCoord.xy);
+ if (border > 0.0)
+ return 1.0;
+ float bound = KERNEL * 0.5 - 0.5;
+ bound *= PCFEDGE;
+ for (float y = -bound; y <= bound; y += PCFEDGE){
+ for (float x = -bound; x <= bound; x += PCFEDGE){
+ shadow += clamp(Shadow_DoShadowCompareOffset(tex,projCoord,vec2(x,y)) +
+ border,
+ 0.0, 1.0);
+ }
+ }
+
+ shadow = shadow / (KERNEL * KERNEL);
+ return shadow;
+}
+
+
+//12 tap poisson disk
+ const vec2 poissonDisk0 = vec2(-0.1711046, -0.425016);
+ const vec2 poissonDisk1 = vec2(-0.7829809, 0.2162201);
+ const vec2 poissonDisk2 = vec2(-0.2380269, -0.8835521);
+ const vec2 poissonDisk3 = vec2(0.4198045, 0.1687819);
+ const vec2 poissonDisk4 = vec2(-0.684418, -0.3186957);
+ const vec2 poissonDisk5 = vec2(0.6026866, -0.2587841);
+ const vec2 poissonDisk6 = vec2(-0.2412762, 0.3913516);
+ const vec2 poissonDisk7 = vec2(0.4720655, -0.7664126);
+ const vec2 poissonDisk8 = vec2(0.9571564, 0.2680693);
+ const vec2 poissonDisk9 = vec2(-0.5238616, 0.802707);
+ const vec2 poissonDisk10 = vec2(0.5653144, 0.60262);
+ const vec2 poissonDisk11 = 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 * shadowBorderScale);
+
+ shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk0 * texelSize);
+ shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk1 * texelSize);
+ shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk2 * texelSize);
+ shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk3 * texelSize);
+ shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk4 * texelSize);
+ shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk5 * texelSize);
+ shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk6 * texelSize);
+ shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk7 * texelSize);
+ shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk8 * texelSize);
+ shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk9 * texelSize);
+ shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk10 * texelSize);
+ shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk11 * texelSize);
+
+ shadow = shadow * 0.08333333333;//this is divided by 12
+ return shadow;
+}
+
diff --git a/engine/src/core-data/Common/ShaderLib/PssmShadows15.glsllib b/engine/src/core-data/Common/ShaderLib/PssmShadows15.glsllib
new file mode 100644
index 000000000..f52213003
--- /dev/null
+++ b/engine/src/core-data/Common/ShaderLib/PssmShadows15.glsllib
@@ -0,0 +1,164 @@
+// Because gpu_shader5 is actually where those
+// gather functions are declared to work on shadowmaps
+#extension GL_ARB_gpu_shader5 : enable
+
+#ifdef HARDWARE_SHADOWS
+ #define SHADOWMAP sampler2DShadow
+ #define SHADOWCOMPAREOFFSET(tex,coord,offset) textureProjOffset(tex, coord, offset)
+ #define SHADOWCOMPARE(tex,coord) textureProj(tex, coord)
+ #define SHADOWGATHER(tex,coord) textureGather(tex, coord.xy, coord.z)
+#else
+ #define SHADOWMAP sampler2D
+ #define SHADOWCOMPAREOFFSET(tex,coord,offset) step(coord.z, textureProjOffset(tex, coord, offset).r)
+ #define SHADOWCOMPARE(tex,coord) step(coord.z, textureProj(tex, coord).r)
+ #define SHADOWGATHER(tex,coord) step(coord.z, textureGather(tex, coord.xy))
+#endif
+
+
+#if FILTER_MODE == 0
+ #define GETSHADOW SHADOWCOMPARE
+ #define KERNEL 1
+#elif FILTER_MODE == 1
+ #ifdef HARDWARE_SHADOWS
+ #define GETSHADOW SHADOWCOMPARE
+ #else
+ #define GETSHADOW Shadow_DoBilinear_2x2
+ #endif
+ #define KERNEL 1
+#elif FILTER_MODE == 2
+ #define GETSHADOW Shadow_DoDither_2x2
+ #define KERNEL 1
+#elif FILTER_MODE == 3
+ #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
+
+
+
+uniform SHADOWMAP m_ShadowMap0;
+uniform SHADOWMAP m_ShadowMap1;
+uniform SHADOWMAP m_ShadowMap2;
+uniform SHADOWMAP m_ShadowMap3;
+
+uniform vec4 m_Splits;
+uniform float m_ShadowIntensity;
+
+const vec2 pixSize2 = vec2(1.0 / SHADOWMAP_SIZE);
+float shadowBorderScale = 1.0;
+
+float Shadow_BorderCheck(in vec2 coord){
+ // Fastest, "hack" method (uses 4-5 instructions)
+ vec4 t = vec4(coord.xy, 0.0, 1.0);
+ t = step(t.wwxy, t.xyzz);
+ return dot(t,t);
+}
+
+float Shadow_DoDither_2x2(in SHADOWMAP tex, in vec4 projCoord){
+ float border = Shadow_BorderCheck(projCoord.xy);
+ if (border > 0.0)
+ return 1.0;
+
+ vec2 pixSize = pixSize2 * shadowBorderScale;
+
+ 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));
+ shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy+pixSize*(vec2( 0.5, 1.5)+o), projCoord.zw));
+ shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy+pixSize*(vec2(-1.5, -0.5)+o), projCoord.zw));
+ shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy+pixSize*(vec2( 0.5, -0.5)+o), projCoord.zw));
+ shadow *= 0.25;
+ return shadow;
+}
+
+float Shadow_DoBilinear_2x2(in SHADOWMAP tex, in vec4 projCoord){
+ float border = Shadow_BorderCheck(projCoord.xy);
+ if (border > 0.0)
+ return 1.0;
+
+ #ifdef GL_ARB_gpu_shader5
+ vec4 coord = vec4(projCoord.xyz / projCoord.www,0.0);
+ vec4 gather = SHADOWGATHER(tex, coord);
+ #else
+ vec4 gather = vec4(0.0);
+ gather.x = SHADOWCOMPAREOFFSET(tex, projCoord, ivec2(0, 0));
+ gather.y = SHADOWCOMPAREOFFSET(tex, projCoord, ivec2(1, 0));
+ gather.z = SHADOWCOMPAREOFFSET(tex, projCoord, ivec2(0, 1));
+ gather.w = SHADOWCOMPAREOFFSET(tex, projCoord, ivec2(1, 1));
+ #endif
+
+ 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){
+
+ vec2 pixSize = pixSize2 * shadowBorderScale;
+ float shadow = 0.0;
+ float border = Shadow_BorderCheck(projCoord.xy);
+ if (border > 0.0)
+ return 1.0;
+
+ float bound = KERNEL * 0.5 - 0.5;
+ bound *= PCFEDGE;
+ for (float y = -bound; y <= bound; y += PCFEDGE){
+ for (float x = -bound; x <= bound; x += PCFEDGE){
+ vec4 coord = vec4(projCoord.xy + vec2(x,y) * pixSize, projCoord.zw);
+ shadow += SHADOWCOMPARE(tex, coord);
+ }
+ }
+
+ shadow = shadow / (KERNEL * KERNEL);
+ return shadow;
+}
+
+
+//12 tap poisson disk
+ const vec2 poissonDisk0 = vec2(-0.1711046, -0.425016);
+ const vec2 poissonDisk1 = vec2(-0.7829809, 0.2162201);
+ const vec2 poissonDisk2 = vec2(-0.2380269, -0.8835521);
+ const vec2 poissonDisk3 = vec2(0.4198045, 0.1687819);
+ const vec2 poissonDisk4 = vec2(-0.684418, -0.3186957);
+ const vec2 poissonDisk5 = vec2(0.6026866, -0.2587841);
+ const vec2 poissonDisk6 = vec2(-0.2412762, 0.3913516);
+ const vec2 poissonDisk7 = vec2(0.4720655, -0.7664126);
+ const vec2 poissonDisk8 = vec2(0.9571564, 0.2680693);
+ const vec2 poissonDisk9 = vec2(-0.5238616, 0.802707);
+ const vec2 poissonDisk10 = vec2(0.5653144, 0.60262);
+ const vec2 poissonDisk11 = 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 = pixSize2 * 4.0 * PCFEDGE * shadowBorderScale;
+
+ shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk0 * texelSize, projCoord.zw));
+ shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk1 * texelSize, projCoord.zw));
+ shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk2 * texelSize, projCoord.zw));
+ shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk3 * texelSize, projCoord.zw));
+ shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk4 * texelSize, projCoord.zw));
+ shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk5 * texelSize, projCoord.zw));
+ shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk6 * texelSize, projCoord.zw));
+ shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk7 * texelSize, projCoord.zw));
+ shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk8 * texelSize, projCoord.zw));
+ shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk9 * texelSize, projCoord.zw));
+ shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk10 * texelSize, projCoord.zw));
+ shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk11 * texelSize, projCoord.zw));
+
+ //this is divided by 12
+ return shadow * 0.08333333333;
+}
+
+
diff --git a/engine/src/core/com/jme3/shadow/PssmShadowFilter.java b/engine/src/core/com/jme3/shadow/PssmShadowFilter.java
new file mode 100644
index 000000000..342f4f2c2
--- /dev/null
+++ b/engine/src/core/com/jme3/shadow/PssmShadowFilter.java
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 2009-2010 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.shadow;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.export.InputCapsule;
+import com.jme3.export.JmeExporter;
+import com.jme3.export.JmeImporter;
+import com.jme3.export.OutputCapsule;
+import com.jme3.material.Material;
+import com.jme3.math.Matrix4f;
+import com.jme3.math.Vector3f;
+import com.jme3.math.Vector4f;
+import com.jme3.post.Filter;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+import com.jme3.renderer.queue.RenderQueue;
+import com.jme3.shadow.PssmShadowRenderer.CompareMode;
+import com.jme3.shadow.PssmShadowRenderer.FilterMode;
+import com.jme3.texture.FrameBuffer;
+import java.io.IOException;
+
+/**
+ *
+ * This Filter does basically the same as a PssmShadowRenderer except it renders
+ * the post shadow pass as a fulscreen quad pass instead of a geometry pass.
+ * It's mostly faster than PssmShadowRenderer as long as you have more than a about ten shadow recieving objects.
+ * The expense is the draw back that the shadow Recieve mode set on spatial is ignored.
+ * So basically all and only objects that render depth in the scene receive shadows.
+ * See this post for more details http://jmonkeyengine.org/groups/general-2/forum/topic/silly-question-about-shadow-rendering/#post-191599
+ *
+ * API is basically the same as the PssmShadowRenderer;
+ *
+ * @author Rémy Bouquet aka Nehon
+ */
+public class PssmShadowFilter extends Filter {
+
+ private PssmShadowRenderer pssmRenderer;
+ private ViewPort viewPort;
+
+ /**
+ * Creates a PSSM Shadow Filter
+ * More info on the technique at http://http.developer.nvidia.com/GPUGems3/gpugems3_ch10.html
+ * @param manager the application asset manager
+ * @param size the size of the rendered shadowmaps (512,1024,2048, etc...)
+ * @param nbSplits the number of shadow maps rendered (the more shadow maps the more quality, the less fps).
+ */
+ public PssmShadowFilter(AssetManager manager, int size, int nbSplits) {
+ super("Post Shadow");
+ material = new Material(manager, "Common/MatDefs/Shadow/PostShadowFilter.j3md");
+ pssmRenderer = new PssmShadowRenderer(manager, size, nbSplits, material);
+ pssmRenderer.needsfallBackMaterial = true;
+ }
+
+ @Override
+ protected Material getMaterial() {
+ return material;
+ }
+
+ @Override
+ protected boolean isRequiresDepthTexture() {
+ return true;
+ }
+
+ public Material getShadowMaterial() {
+ return material;
+ }
+ Vector4f tmpv = new Vector4f();
+
+ @Override
+ protected void preFrame(float tpf) {
+ pssmRenderer.preFrame(tpf);
+ material.setMatrix4("ViewProjectionMatrixInverse", viewPort.getCamera().getViewProjectionMatrix().invert());
+ Matrix4f m = viewPort.getCamera().getViewProjectionMatrix();
+ material.setVector4("ViewProjectionMatrixRow2", tmpv.set(m.m20, m.m21, m.m22, m.m23));
+
+ }
+
+ @Override
+ protected void postQueue(RenderQueue queue) {
+ pssmRenderer.postQueue(queue);
+ }
+
+ @Override
+ protected void postFrame(RenderManager renderManager, ViewPort viewPort, FrameBuffer prevFilterBuffer, FrameBuffer sceneBuffer) {
+ pssmRenderer.setPostShadowParams();
+ }
+
+ @Override
+ protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
+ pssmRenderer.initialize(renderManager, vp);
+ this.viewPort = vp;
+ }
+
+ /**
+ * returns the light direction used by the processor
+ * @return
+ */
+ public Vector3f getDirection() {
+ return pssmRenderer.getDirection();
+ }
+
+ /**
+ * Sets the light direction to use to compute shadows
+ * @param direction
+ */
+ public void setDirection(Vector3f direction) {
+ pssmRenderer.setDirection(direction);
+ }
+
+ /**
+ * returns the labda parameter
+ * see {@link setLambda(float lambda)}
+ * @return lambda
+ */
+ public float getLambda() {
+ return pssmRenderer.getLambda();
+ }
+
+ /*
+ * Adjust the repartition of the different shadow maps in the shadow extend
+ * usualy goes from 0.0 to 1.0
+ * a low value give a more linear repartition resulting in a constant quality in the shadow over the extends, but near shadows could look very jagged
+ * a high value give a more logarithmic repartition resulting in a high quality for near shadows, but the quality quickly decrease over the extend.
+ * the default value is set to 0.65f (theoric optimal value).
+ * @param lambda the lambda value.
+ */
+ public void setLambda(float lambda) {
+ pssmRenderer.setLambda(lambda);
+ }
+
+ /**
+ * How far the shadows are rendered in the view
+ * see {@link setShadowZExtend(float zFar)}
+ * @return shadowZExtend
+ */
+ public float getShadowZExtend() {
+ return pssmRenderer.getShadowZExtend();
+ }
+
+ /**
+ * Set the distance from the eye where the shadows will be rendered
+ * default value is dynamicaly computed to the shadow casters/receivers union bound zFar, capped to view frustum far value.
+ * @param zFar the zFar values that override the computed one
+ */
+ public void setShadowZExtend(float zFar) {
+ pssmRenderer.setShadowZExtend(zFar);
+ }
+
+ /**
+ * returns the shdaow intensity
+ * see {@link setShadowIntensity(float shadowIntensity)}
+ * @return shadowIntensity
+ */
+ public float getShadowIntensity() {
+ return pssmRenderer.getShadowIntensity();
+ }
+
+ /**
+ * Set the shadowIntensity, the value should be between 0 and 1,
+ * a 0 value gives a bright and invisilble shadow,
+ * a 1 value gives a pitch black shadow,
+ * default is 0.7
+ * @param shadowIntensity the darkness of the shadow
+ */
+ final public void setShadowIntensity(float shadowIntensity) {
+ pssmRenderer.setShadowIntensity(shadowIntensity);
+ }
+
+ /**
+ * returns the edges thickness
+ * see {@link setEdgesThickness(int edgesThickness)}
+ * @return edgesThickness
+ */
+ public int getEdgesThickness() {
+ return pssmRenderer.getEdgesThickness();
+ }
+
+ /**
+ * Sets the shadow edges thickness. default is 1, setting it to lower values can help to reduce the jagged effect of the shadow edges
+ * @param edgesThickness
+ */
+ public void setEdgesThickness(int edgesThickness) {
+ pssmRenderer.setEdgesThickness(edgesThickness);
+ }
+
+ /**
+ * returns true if the PssmRenderer flushed the shadow queues
+ * @return flushQueues
+ */
+ public boolean isFlushQueues() {
+ return pssmRenderer.isFlushQueues();
+ }
+
+ /**
+ * Set this to false if you want to use several PssmRederers to have multiple shadows cast by multiple light sources.
+ * Make sure the last PssmRenderer in the stack DO flush the queues, but not the others
+ * @param flushQueues
+ */
+ public void setFlushQueues(boolean flushQueues) {
+ pssmRenderer.setFlushQueues(flushQueues);
+ }
+
+ /**
+ * sets the shadow compare mode see {@link CompareMode} for more info
+ * @param compareMode
+ */
+ final public void setCompareMode(CompareMode compareMode) {
+ pssmRenderer.setCompareMode(compareMode);
+ }
+
+ /**
+ * Sets the filtering mode for shadow edges see {@link FilterMode} for more info
+ * @param filterMode
+ */
+ final public void setFilterMode(FilterMode filterMode) {
+ pssmRenderer.setFilterMode(filterMode);
+ }
+
+ @Override
+ public void write(JmeExporter ex) throws IOException {
+ super.write(ex);
+ OutputCapsule oc = ex.getCapsule(this);
+
+ }
+
+ @Override
+ public void read(JmeImporter im) throws IOException {
+ super.read(im);
+ InputCapsule ic = im.getCapsule(this);
+
+ }
+}
diff --git a/engine/src/core/com/jme3/shadow/PssmShadowRenderer.java b/engine/src/core/com/jme3/shadow/PssmShadowRenderer.java
index 2749e36f9..1576c937d 100644
--- a/engine/src/core/com/jme3/shadow/PssmShadowRenderer.java
+++ b/engine/src/core/com/jme3/shadow/PssmShadowRenderer.java
@@ -31,7 +31,6 @@ 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;
@@ -48,7 +47,6 @@ import com.jme3.renderer.queue.RenderQueue.ShadowMode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Spatial;
import com.jme3.scene.debug.WireFrustum;
-import com.jme3.shader.VarType;
import com.jme3.texture.FrameBuffer;
import com.jme3.texture.Image.Format;
import com.jme3.texture.Texture.MagFilter;
@@ -56,6 +54,8 @@ import com.jme3.texture.Texture.MinFilter;
import com.jme3.texture.Texture.ShadowCompareMode;
import com.jme3.texture.Texture2D;
import com.jme3.ui.Picture;
+import java.util.ArrayList;
+import java.util.List;
/**
* PssmShadow renderer use Parrallel Split Shadow Mapping technique (pssm)
@@ -99,13 +99,12 @@ public class PssmShadowRenderer implements SceneProcessor {
* 8x8 percentage-closer filtering is used. Shadows will be smoother
* at the cost of performance
*/
- PCFPOISSON,
+ PCFPOISSON,
/**
* 8x8 percentage-closer filtering is used. Shadows will be smoother
* at the cost of performance
*/
PCF8
-
}
/**
@@ -151,9 +150,16 @@ public class PssmShadowRenderer implements SceneProcessor {
private Vector3f[] points = new Vector3f[8];
private boolean flushQueues = true;
// define if the fallback material should be used.
- private boolean needsfallBackMaterial = false;
+ protected boolean needsfallBackMaterial = false;
//Name of the post material technique
private String postTechniqueName = "PostShadow";
+ //flags to know when to change params in the materials
+ private boolean applyHWShadows = true;
+ private boolean applyFilterMode = true;
+ private boolean applyPCFEdge = true;
+ private boolean applyShadowIntensity = true;
+ //a list of material of the post shadow queue geometries.
+ private List matCache = new ArrayList();
/**
* Create a PSSM Shadow Renderer
@@ -165,7 +171,6 @@ public class PssmShadowRenderer implements SceneProcessor {
*/
public PssmShadowRenderer(AssetManager manager, int size, int nbSplits) {
this(manager, size, nbSplits, new Material(manager, "Common/MatDefs/Shadow/PostShadowPSSM.j3md"));
-
}
/**
@@ -174,10 +179,12 @@ public class PssmShadowRenderer implements SceneProcessor {
* @param manager the application asset manager
* @param size the size of the rendered shadowmaps (512,1024,2048, etc...)
* @param nbSplits the number of shadow maps rendered (the more shadow maps the more quality, the less fps).
- * @param postShadowMat the material used for post shadows if you need to override it *
+ * @param filterPass set this to true if you want the post shadow pass to be done in a Filter un screen space.
+ * @param postShadowMat the material used for post shadows if you need to override it
*/
- //TODO remove the postShadowMat when we have shader injection....or remove this todo if we are in 2020.
- public PssmShadowRenderer(AssetManager manager, int size, int nbSplits, Material postShadowMat) {
+ protected PssmShadowRenderer(AssetManager manager, int size, int nbSplits, Material postShadowMat) {
+
+ this.postshadowMat = postShadowMat;
assetManager = manager;
nbSplits = Math.max(Math.min(nbSplits, 4), 1);
this.nbSplits = nbSplits;
@@ -194,9 +201,8 @@ public class PssmShadowRenderer implements SceneProcessor {
dummyTex = new Texture2D(size, size, Format.RGBA8);
preshadowMat = new Material(manager, "Common/MatDefs/Shadow/PreShadow.j3md");
- this.postshadowMat = postShadowMat;
- postshadowMat.setFloat("ShadowMapSize", size);
-
+ postshadowMat.setFloat("ShadowMapSize", size);
+
for (int i = 0; i < nbSplits; i++) {
lightViewProjectionsMatrices[i] = new Matrix4f();
shadowFB[i] = new FrameBuffer(size, size, 1);
@@ -254,6 +260,7 @@ public class PssmShadowRenderer implements SceneProcessor {
}
}
}
+ applyFilterMode = true;
}
/**
@@ -287,6 +294,7 @@ public class PssmShadowRenderer implements SceneProcessor {
}
}
postshadowMat.setBoolean("HardwareShadows", compareMode == CompareMode.Hardware);
+ applyHWShadows = true;
}
//debug function that create a displayable frustrum
@@ -429,12 +437,12 @@ public class PssmShadowRenderer implements SceneProcessor {
}
//debug only : displays depth shadow maps
- private void displayShadowMap(Renderer r) {
+ protected void displayShadowMap(Renderer r) {
Camera cam = viewPort.getCamera();
renderManager.setCamera(cam, true);
int h = cam.getHeight();
for (int i = 0; i < dispPic.length; i++) {
- dispPic[i].setPosition((128 * i) +(150 + 64 * (i + 1) ), h / 20f);
+ dispPic[i].setPosition((128 * i) + (150 + 64 * (i + 1)), h / 20f);
dispPic[i].setWidth(128);
dispPic[i].setHeight(128);
dispPic[i].updateGeometricState();
@@ -451,10 +459,15 @@ public class PssmShadowRenderer implements SceneProcessor {
}
public void postFrame(FrameBuffer out) {
- Camera cam = viewPort.getCamera();
+
+ if (debug) {
+ displayShadowMap(renderManager.getRenderer());
+ }
if (!noOccluders) {
//setting params to recieving geometry list
setMatParams();
+
+ Camera cam = viewPort.getCamera();
//some materials in the scene does not have a post shadow technique so we're using the fall back material
if (needsfallBackMaterial) {
renderManager.setForcedMaterial(postshadowMat);
@@ -472,50 +485,79 @@ public class PssmShadowRenderer implements SceneProcessor {
renderManager.setCamera(cam, false);
}
- if (debug) {
- displayShadowMap(renderManager.getRenderer());
- }
+
}
private void setMatParams() {
GeometryList l = viewPort.getQueue().getShadowQueueContent(ShadowMode.Receive);
- //iteratin throught all the geometries of the list to set the material params
+ //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 setting the params.
+ //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
+ for (Material mat : matCache) {
+ if (mat.getParam("Splits") == null) {
mat.setColor("Splits", splits);
- postshadowMat.setColor("Splits", splits);
+ }
+ if (mat.getParam("ShadowMapSize") == null) {
+ mat.setFloat("ShadowMapSize", shadowMapSize);
+ }
+ for (int j = 0; j < nbSplits; j++) {
+ mat.setMatrix4("LightViewProjectionMatrix" + j, lightViewProjectionsMatrices[j]);
+ }
+ if (mat.getParam("ShadowMap0") == null) {
for (int j = 0; j < nbSplits; j++) {
- mat.setMatrix4("LightViewProjectionMatrix" + j, lightViewProjectionsMatrices[j]);
mat.setTexture("ShadowMap" + j, shadowMaps[j]);
}
+ }
+ if (applyHWShadows || mat.getParam("HardwareShadows") == null) {
mat.setBoolean("HardwareShadows", compareMode == CompareMode.Hardware);
+ applyHWShadows = false;
+ }
+ if (applyFilterMode || mat.getParam("FilterMode") == null) {
mat.setInt("FilterMode", filterMode.ordinal());
+ applyFilterMode = false;
+ }
+ if (mat.getParam("PCFEdge") == null || applyPCFEdge) {
mat.setFloat("PCFEdge", edgesThickness);
+ applyPCFEdge = false;
+ }
+
+ if (mat.getParam("ShadowIntensity") == null || applyShadowIntensity) {
mat.setFloat("ShadowIntensity", shadowIntensity);
- if(mat.getParam("ShadowMapSize") == null){
- mat.setFloat("ShadowMapSize", shadowMapSize);
- }
- } else {
- needsfallBackMaterial = true;
+ applyShadowIntensity = false;
}
- }
+ }
//At least one material of the receiving geoms does not support the post shadow techniques
//so we fall back to the forced material solution (transparent shadows won't be supported for these objects)
if (needsfallBackMaterial) {
- postshadowMat.setColor("Splits", splits);
- for (int j = 0; j < nbSplits; j++) {
- postshadowMat.setMatrix4("LightViewProjectionMatrix" + j, lightViewProjectionsMatrices[j]);
- }
+ setPostShadowParams();
}
}
+ protected void setPostShadowParams() {
+ postshadowMat.setColor("Splits", splits);
+ for (int j = 0; j < nbSplits; j++) {
+ postshadowMat.setMatrix4("LightViewProjectionMatrix" + j, lightViewProjectionsMatrices[j]);
+ }
+ }
+
public void preFrame(float tpf) {
}
@@ -583,6 +625,7 @@ public class PssmShadowRenderer implements SceneProcessor {
final public void setShadowIntensity(float shadowIntensity) {
this.shadowIntensity = shadowIntensity;
postshadowMat.setFloat("ShadowIntensity", shadowIntensity);
+ applyShadowIntensity = true;
}
/**
@@ -602,6 +645,7 @@ public class PssmShadowRenderer implements SceneProcessor {
this.edgesThickness = Math.max(1, Math.min(edgesThickness, 10));
this.edgesThickness *= 0.1f;
postshadowMat.setFloat("PCFEdge", edgesThickness);
+ applyPCFEdge = true;
}
/**
diff --git a/engine/src/test/jme3test/light/TestPssmShadow.java b/engine/src/test/jme3test/light/TestPssmShadow.java
index 005675627..08e58b7af 100644
--- a/engine/src/test/jme3test/light/TestPssmShadow.java
+++ b/engine/src/test/jme3test/light/TestPssmShadow.java
@@ -44,6 +44,8 @@ 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.filters.FXAAFilter;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
@@ -53,6 +55,7 @@ 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.PssmShadowFilter;
import com.jme3.shadow.PssmShadowRenderer;
import com.jme3.shadow.PssmShadowRenderer.CompareMode;
import com.jme3.shadow.PssmShadowRenderer.FilterMode;
@@ -65,13 +68,12 @@ public class TestPssmShadow extends SimpleApplication implements ActionListener
private Spatial[] obj;
private Material[] mat;
- private boolean renderShadows = true;
private boolean hardwareShadows = false;
private PssmShadowRenderer pssmRenderer;
+ private PssmShadowFilter pssmFilter;
private Geometry ground;
- private Material matGroundU;
- private Material matGroundL;
-
+ private Material matGroundU;
+ private Material matGroundL;
public static void main(String[] args) {
TestPssmShadow app = new TestPssmShadow();
@@ -109,15 +111,15 @@ public class TestPssmShadow extends SimpleApplication implements ActionListener
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);
@@ -146,16 +148,35 @@ public class TestPssmShadow extends SimpleApplication implements ActionListener
loadScene();
pssmRenderer = new PssmShadowRenderer(assetManager, 1024, 3);
+ // pssmRenderer.setDirection(new Vector3f(-1, -1, -1).normalizeLocal());
pssmRenderer.setDirection(new Vector3f(0.5973172f, -0.16583486f, 0.7846725f).normalizeLocal());
pssmRenderer.setLambda(0.55f);
pssmRenderer.setShadowIntensity(0.6f);
pssmRenderer.setCompareMode(CompareMode.Software);
pssmRenderer.setFilterMode(FilterMode.Dither);
- pssmRenderer.displayDebug();
+ // pssmRenderer.displayDebug();
viewPort.addProcessor(pssmRenderer);
+
+
+
+ pssmFilter = new PssmShadowFilter(assetManager, 1024, 3);
+ //pssmFilter.setDirection(new Vector3f(-1, -1, -1).normalizeLocal());
+ pssmRenderer.setDirection(new Vector3f(0.5973172f, -0.16583486f, 0.7846725f).normalizeLocal());
+ pssmFilter.setLambda(0.55f);
+ pssmFilter.setShadowIntensity(0.6f);
+ pssmFilter.setCompareMode(CompareMode.Software);
+ pssmFilter.setFilterMode(FilterMode.Dither);
+ pssmFilter.setEnabled(false);
+ FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
+ // fpp.setNumSamples(4);
+ fpp.addFilter(pssmFilter);
+
+ viewPort.addProcessor(fpp);
+
+
initInputs();
}
- BitmapText infoText;
+ BitmapText infoText;
private void initInputs() {
/** Write text on the screen (HUD) */
@@ -174,7 +195,7 @@ public class TestPssmShadow extends SimpleApplication implements ActionListener
inputManager.addMapping("lambdaDown", new KeyTrigger(KeyInput.KEY_J));
inputManager.addMapping("toggleHW", new KeyTrigger(KeyInput.KEY_RETURN));
inputManager.addMapping("switchGroundMat", new KeyTrigger(KeyInput.KEY_M));
- inputManager.addListener(this, "lambdaUp", "lambdaDown", "toggleHW", "toggle", "ShadowUp", "ShadowDown", "ThicknessUp", "ThicknessDown","changeFiltering","switchGroundMat");
+ inputManager.addListener(this, "lambdaUp", "lambdaDown", "toggleHW", "toggle", "ShadowUp", "ShadowDown", "ThicknessUp", "ThicknessDown", "changeFiltering", "switchGroundMat");
}
private void print(String str) {
@@ -212,60 +233,83 @@ public class TestPssmShadow extends SimpleApplication implements ActionListener
}
};
int filteringIndex = 2;
+ int renderModeIndex = 0;
public void onAction(String name, boolean keyPressed, float tpf) {
if (name.equals("toggle") && keyPressed) {
- if (renderShadows) {
- renderShadows = false;
- viewPort.removeProcessor(pssmRenderer);
- } else {
- renderShadows = true;
- viewPort.addProcessor(pssmRenderer);
+ renderModeIndex += 1;
+ renderModeIndex %= 3;
+
+ switch (renderModeIndex) {
+ case 0:
+ viewPort.addProcessor(pssmRenderer);
+ break;
+ case 1:
+ viewPort.removeProcessor(pssmRenderer);
+ pssmFilter.setEnabled(true);
+ break;
+ case 2:
+ pssmFilter.setEnabled(false);
+ break;
}
+
+
+
} else if (name.equals("toggleHW") && keyPressed) {
hardwareShadows = !hardwareShadows;
pssmRenderer.setCompareMode(hardwareShadows ? CompareMode.Hardware : CompareMode.Software);
+ pssmFilter.setCompareMode(hardwareShadows ? CompareMode.Hardware : CompareMode.Software);
System.out.println("HW Shadows: " + hardwareShadows);
}
+//
+// renderShadows = true;
+// viewPort.addProcessor(pssmRenderer);
if (name.equals("changeFiltering") && keyPressed) {
filteringIndex = (filteringIndex + 1) % FilterMode.values().length;
FilterMode m = FilterMode.values()[filteringIndex];
pssmRenderer.setFilterMode(m);
+ pssmFilter.setFilterMode(m);
print("Filter mode : " + m.toString());
}
if (name.equals("lambdaUp") && keyPressed) {
pssmRenderer.setLambda(pssmRenderer.getLambda() + 0.01f);
+ pssmFilter.setLambda(pssmRenderer.getLambda() + 0.01f);
System.out.println("Lambda : " + pssmRenderer.getLambda());
} else if (name.equals("lambdaDown") && keyPressed) {
pssmRenderer.setLambda(pssmRenderer.getLambda() - 0.01f);
+ pssmFilter.setLambda(pssmRenderer.getLambda() - 0.01f);
System.out.println("Lambda : " + pssmRenderer.getLambda());
}
if (name.equals("ShadowUp") && keyPressed) {
pssmRenderer.setShadowIntensity(pssmRenderer.getShadowIntensity() + 0.1f);
+ pssmFilter.setShadowIntensity(pssmRenderer.getShadowIntensity() + 0.1f);
System.out.println("Shadow intensity : " + pssmRenderer.getShadowIntensity());
}
if (name.equals("ShadowDown") && keyPressed) {
pssmRenderer.setShadowIntensity(pssmRenderer.getShadowIntensity() - 0.1f);
+ pssmFilter.setShadowIntensity(pssmRenderer.getShadowIntensity() - 0.1f);
System.out.println("Shadow intensity : " + pssmRenderer.getShadowIntensity());
}
if (name.equals("ThicknessUp") && keyPressed) {
pssmRenderer.setEdgesThickness(pssmRenderer.getEdgesThickness() + 1);
+ pssmFilter.setEdgesThickness(pssmRenderer.getEdgesThickness() + 1);
System.out.println("Shadow thickness : " + pssmRenderer.getEdgesThickness());
}
if (name.equals("ThicknessDown") && keyPressed) {
pssmRenderer.setEdgesThickness(pssmRenderer.getEdgesThickness() - 1);
+ pssmFilter.setEdgesThickness(pssmRenderer.getEdgesThickness() - 1);
System.out.println("Shadow thickness : " + pssmRenderer.getEdgesThickness());
}
if (name.equals("switchGroundMat") && keyPressed) {
- if(ground.getMaterial() == matGroundL){
+ if (ground.getMaterial() == matGroundL) {
ground.setMaterial(matGroundU);
- }else{
+ } else {
ground.setMaterial(matGroundL);
- }
+ }
}
-
+
}
}
diff --git a/engine/src/test/jme3test/light/TestShadowsPerf.java b/engine/src/test/jme3test/light/TestShadowsPerf.java
new file mode 100644
index 000000000..503bc2127
--- /dev/null
+++ b/engine/src/test/jme3test/light/TestShadowsPerf.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2009-2010 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jme3test.light;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.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.light.PointLight;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector2f;
+import com.jme3.math.Vector3f;
+import com.jme3.renderer.queue.RenderQueue.ShadowMode;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Spatial;
+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 com.jme3.util.TangentBinormalGenerator;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class TestShadowsPerf extends SimpleApplication {
+
+ float angle;
+ PointLight pl;
+ Spatial lightMdl;
+
+ public static void main(String[] args) {
+ TestShadowsPerf app = new TestShadowsPerf();
+ app.start();
+ }
+ Geometry sphere;
+ Material mat;
+
+ @Override
+ public void simpleInitApp() {
+ Logger.getLogger("com.jme3").setLevel(Level.SEVERE);
+ flyCam.setMoveSpeed(50);
+ flyCam.setEnabled(false);
+ viewPort.setBackgroundColor(ColorRGBA.DarkGray);
+ cam.setLocation(new Vector3f(-53.952988f, 27.15874f, -32.875023f));
+ cam.setRotation(new Quaternion(0.1564309f, 0.6910534f, -0.15713608f, 0.6879555f));
+
+// cam.setLocation(new Vector3f(53.64627f, 130.56f, -11.247704f));
+// cam.setRotation(new Quaternion(-6.5737107E-4f, 0.76819664f, -0.64021313f, -7.886125E-4f));
+////
+ cam.setFrustumFar(500);
+
+ mat = assetManager.loadMaterial("Textures/Terrain/Pond/Pond.j3m");
+
+ Box b = new Box(Vector3f.ZERO, 800, 1, 700);
+ b.scaleTextureCoordinates(new Vector2f(50, 50));
+ Geometry ground = new Geometry("ground", b);
+ ground.setMaterial(mat);
+ rootNode.attachChild(ground);
+ ground.setShadowMode(ShadowMode.Receive);
+
+ Sphere sphMesh = new Sphere(32, 32, 1);
+ sphMesh.setTextureMode(Sphere.TextureMode.Projected);
+ sphMesh.updateGeometry(32, 32, 1, false, false);
+ TangentBinormalGenerator.generate(sphMesh);
+
+ sphere = new Geometry("Rock Ball", sphMesh);
+ sphere.setLocalTranslation(0, 5, 0);
+ sphere.setMaterial(mat);
+ sphere.setShadowMode(ShadowMode.CastAndReceive);
+ rootNode.attachChild(sphere);
+
+
+
+
+ DirectionalLight dl = new DirectionalLight();
+ dl.setDirection(new Vector3f(0, -1, 0).normalizeLocal());
+ dl.setColor(ColorRGBA.White);
+ rootNode.addLight(dl);
+
+ AmbientLight al = new AmbientLight();
+ al.setColor(ColorRGBA.White.mult(0.7f));
+ rootNode.addLight(al);
+ //rootNode.setShadowMode(ShadowMode.CastAndReceive);
+
+ createballs();
+
+ final PssmShadowRenderer pssmRenderer = new PssmShadowRenderer(assetManager, 1024, 4);
+ viewPort.addProcessor(pssmRenderer);
+//
+// final PssmShadowFilter pssmRenderer = new PssmShadowFilter(assetManager, 1024, 4);
+// FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
+// fpp.addFilter(pssmRenderer);
+// viewPort.addProcessor(fpp);
+
+ pssmRenderer.setDirection(dl.getDirection());
+ pssmRenderer.setLambda(0.55f);
+ pssmRenderer.setShadowIntensity(0.55f);
+ pssmRenderer.setCompareMode(CompareMode.Software);
+ pssmRenderer.setFilterMode(FilterMode.PCF4);
+ //pssmRenderer.displayDebug();
+
+ inputManager.addListener(new ActionListener() {
+
+ public void onAction(String name, boolean isPressed, float tpf) {
+ if (name.equals("display") && isPressed) {
+ //pssmRenderer.debugFrustrums();
+ System.out.println("tetetetet");
+ }
+ if (name.equals("add") && isPressed) {
+ createballs();
+ }
+ }
+ }, "display", "add");
+ inputManager.addMapping("display", new KeyTrigger(KeyInput.KEY_SPACE));
+ inputManager.addMapping("add", new KeyTrigger(KeyInput.KEY_RETURN));
+ }
+ int val = 0;
+
+ private void createballs() {
+ System.out.println((frames / time) + ";" + val);
+
+
+ for (int i = val; i < val + 200; i++) {
+
+ Geometry s = sphere.clone().clone(false);
+ s.setMaterial(mat);
+ s.setLocalTranslation(i - 30, 5, (((i) * 2) % 40) - 50);
+ s.setShadowMode(ShadowMode.CastAndReceive);
+ rootNode.attachChild(s);
+ }
+ if (val == 300) {
+ //stop();
+ }
+ val += 1;
+ time = 0;
+ frames = 0;
+ }
+ float time;
+ float frames = 0;
+
+ @Override
+ public void simpleUpdate(float tpf) {
+ time += tpf;
+ frames++;
+ if (time > 1) {
+ //createballs();
+ }
+ }
+}