- Basic and PSSM shadow renderer are now deprecated - There is now one processor and its filter conterpart for each light type - created an abstract shadow processor that hold the common shadowing code. It's totally independent of the shadow technique used. - extracted the CompareMode and FilterMode enum to their own files. - renamed FilterMode enum to EdgeFilteringMode - refactored the shader code, to avoid duplicate code. all shadow related code is now gathered into Shadows.glsllib and Shadows15.glsllib. - added spot light Shadows - removed the ShadowCamera class as it was not used. - removed "pssm" in the naming of classes, shader and shader libs since it's not relevant anymore git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9971 75d07b2b-3a1a-0410-a2c5-0572b91ccdca3.0
parent
304ecb4bf7
commit
0dadaa80f5
@ -0,0 +1,12 @@ |
|||||||
|
#import "Common/ShaderLib/BasicShadow.glsllib" |
||||||
|
|
||||||
|
uniform SHADOWMAP m_ShadowMap; |
||||||
|
varying vec4 projCoord; |
||||||
|
|
||||||
|
void main() { |
||||||
|
vec4 coord = projCoord; |
||||||
|
coord.xyz /= coord.w; |
||||||
|
float shad = Shadow_GetShadow(m_ShadowMap, coord) * 0.7 + 0.3; |
||||||
|
gl_FragColor = vec4(shad,shad,shad,1.0); |
||||||
|
} |
||||||
|
|
@ -0,0 +1,28 @@ |
|||||||
|
MaterialDef Basic Post Shadow { |
||||||
|
|
||||||
|
MaterialParameters { |
||||||
|
Texture2D ShadowMap |
||||||
|
Matrix4 LightViewProjectionMatrix |
||||||
|
} |
||||||
|
|
||||||
|
Technique { |
||||||
|
VertexShader GLSL100: Common/MatDefs/Shadow/BasicPostShadow.vert |
||||||
|
FragmentShader GLSL100: Common/MatDefs/Shadow/BasicPostShadow.frag |
||||||
|
|
||||||
|
WorldParameters { |
||||||
|
WorldViewProjectionMatrix |
||||||
|
WorldMatrix |
||||||
|
} |
||||||
|
|
||||||
|
Defines { |
||||||
|
NO_SHADOW2DPROJ |
||||||
|
} |
||||||
|
|
||||||
|
RenderState { |
||||||
|
Blend Modulate |
||||||
|
DepthWrite Off |
||||||
|
PolyOffset -0.1 0 |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,31 @@ |
|||||||
|
uniform mat4 m_LightViewProjectionMatrix; |
||||||
|
uniform mat4 g_WorldViewProjectionMatrix; |
||||||
|
uniform mat4 g_WorldMatrix; |
||||||
|
|
||||||
|
varying vec4 projCoord; |
||||||
|
|
||||||
|
attribute vec3 inPosition; |
||||||
|
|
||||||
|
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); |
||||||
|
|
||||||
|
void main(){ |
||||||
|
gl_Position = g_WorldViewProjectionMatrix * vec4(inPosition, 1.0); |
||||||
|
|
||||||
|
// get the vertex in world space |
||||||
|
vec4 worldPos = g_WorldMatrix * vec4(inPosition, 1.0); |
||||||
|
|
||||||
|
// convert vertex to light viewProj space |
||||||
|
//projCoord = biasMat * (m_LightViewProjectionMatrix * worldPos); |
||||||
|
vec4 coord = m_LightViewProjectionMatrix * worldPos; |
||||||
|
projCoord = biasMat * coord; |
||||||
|
//projCoord.z /= gl_DepthRange.far; |
||||||
|
//projCoord = (m_LightViewProjectionMatrix * worldPos); |
||||||
|
//projCoord /= projCoord.w; |
||||||
|
//projCoord.xy = projCoord.xy * vec2(0.5, -0.5) + vec2(0.5); |
||||||
|
|
||||||
|
// bias from [-1, 1] to [0, 1] for sampling shadow map |
||||||
|
//projCoord = (projCoord.xyzw * vec4(0.5)) + vec4(0.5); |
||||||
|
} |
@ -1,12 +1,72 @@ |
|||||||
#import "Common/ShaderLib/Shadow.glsllib" |
#import "Common/ShaderLib/Shadows.glsllib" |
||||||
|
|
||||||
uniform SHADOWMAP m_ShadowMap; |
#ifdef PSSM |
||||||
varying vec4 projCoord; |
varying float shadowPosition; |
||||||
|
#endif |
||||||
void main() { |
|
||||||
vec4 coord = projCoord; |
varying vec4 projCoord0; |
||||||
coord.xyz /= coord.w; |
varying vec4 projCoord1; |
||||||
float shad = Shadow_GetShadow(m_ShadowMap, coord) * 0.7 + 0.3; |
varying vec4 projCoord2; |
||||||
gl_FragColor = vec4(shad,shad,shad,1.0); |
varying vec4 projCoord3; |
||||||
} |
|
||||||
|
#ifdef POINTLIGHT |
||||||
|
varying vec4 projCoord4; |
||||||
|
varying vec4 projCoord5; |
||||||
|
uniform vec3 m_LightPos; |
||||||
|
varying vec4 worldPos; |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifdef DISCARD_ALPHA |
||||||
|
#ifdef COLOR_MAP |
||||||
|
uniform sampler2D m_ColorMap; |
||||||
|
#else |
||||||
|
uniform sampler2D m_DiffuseMap; |
||||||
|
#endif |
||||||
|
uniform float m_AlphaDiscardThreshold; |
||||||
|
varying vec2 texCoord; |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifdef FADE |
||||||
|
uniform vec2 m_FadeInfo; |
||||||
|
#endif |
||||||
|
|
||||||
|
void main(){ |
||||||
|
|
||||||
|
#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 |
||||||
|
|
||||||
|
float shadow = 1.0; |
||||||
|
|
||||||
|
#ifdef POINTLIGHT |
||||||
|
shadow = getPointLightShadows(worldPos, m_LightPos, |
||||||
|
m_ShadowMap0,m_ShadowMap1,m_ShadowMap2,m_ShadowMap3,m_ShadowMap4,m_ShadowMap5, |
||||||
|
projCoord0, projCoord1, projCoord2, projCoord3, projCoord4, projCoord5); |
||||||
|
#else |
||||||
|
#ifdef PSSM |
||||||
|
shadow = getDirectionalLightShadows(m_Splits, shadowPosition, |
||||||
|
m_ShadowMap0,m_ShadowMap1,m_ShadowMap2,m_ShadowMap3, |
||||||
|
projCoord0, projCoord1, projCoord2, projCoord3); |
||||||
|
#else |
||||||
|
//spotlight |
||||||
|
shadow = getSpotLightShadows(m_ShadowMap0,projCoord0); |
||||||
|
#endif |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifdef FADE |
||||||
|
shadow = max(0.0,mix(shadow,1.0,(shadowPosition - m_FadeInfo.x) * m_FadeInfo.y)); |
||||||
|
#endif |
||||||
|
shadow = shadow * m_ShadowIntensity + (1.0 - m_ShadowIntensity); |
||||||
|
|
||||||
|
gl_FragColor = vec4(shadow, shadow, shadow, 1.0); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
@ -1,31 +1,72 @@ |
|||||||
uniform mat4 m_LightViewProjectionMatrix; |
uniform mat4 m_LightViewProjectionMatrix0; |
||||||
|
uniform mat4 m_LightViewProjectionMatrix1; |
||||||
|
uniform mat4 m_LightViewProjectionMatrix2; |
||||||
|
uniform mat4 m_LightViewProjectionMatrix3; |
||||||
|
|
||||||
uniform mat4 g_WorldViewProjectionMatrix; |
uniform mat4 g_WorldViewProjectionMatrix; |
||||||
uniform mat4 g_WorldMatrix; |
uniform mat4 g_WorldMatrix; |
||||||
|
uniform mat4 g_ViewMatrix; |
||||||
|
uniform vec3 m_LightPos; |
||||||
|
|
||||||
|
varying vec4 projCoord0; |
||||||
|
varying vec4 projCoord1; |
||||||
|
varying vec4 projCoord2; |
||||||
|
varying vec4 projCoord3; |
||||||
|
|
||||||
|
#ifdef POINTLIGHT |
||||||
|
uniform mat4 m_LightViewProjectionMatrix4; |
||||||
|
uniform mat4 m_LightViewProjectionMatrix5; |
||||||
|
varying vec4 projCoord4; |
||||||
|
varying vec4 projCoord5; |
||||||
|
varying vec4 worldPos; |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifdef PSSM |
||||||
|
varying float shadowPosition; |
||||||
|
#endif |
||||||
|
varying vec3 lightVec; |
||||||
|
|
||||||
varying vec4 projCoord; |
varying vec2 texCoord; |
||||||
|
|
||||||
attribute vec3 inPosition; |
attribute vec3 inPosition; |
||||||
|
|
||||||
|
#ifdef DISCARD_ALPHA |
||||||
|
attribute vec2 inTexCoord; |
||||||
|
#endif |
||||||
|
|
||||||
const mat4 biasMat = mat4(0.5, 0.0, 0.0, 0.0, |
const mat4 biasMat = mat4(0.5, 0.0, 0.0, 0.0, |
||||||
0.0, 0.5, 0.0, 0.0, |
0.0, 0.5, 0.0, 0.0, |
||||||
0.0, 0.0, 0.5, 0.0, |
0.0, 0.0, 0.5, 0.0, |
||||||
0.5, 0.5, 0.5, 1.0); |
0.5, 0.5, 0.5, 1.0); |
||||||
|
|
||||||
|
|
||||||
void main(){ |
void main(){ |
||||||
gl_Position = g_WorldViewProjectionMatrix * vec4(inPosition, 1.0); |
gl_Position = g_WorldViewProjectionMatrix * vec4(inPosition, 1.0); |
||||||
|
|
||||||
|
#ifndef POINTLIGHT |
||||||
|
#ifdef PSSM |
||||||
|
shadowPosition = gl_Position.z; |
||||||
|
#endif |
||||||
|
vec4 worldPos=vec4(0.0); |
||||||
|
#endif |
||||||
// get the vertex in world space |
// get the vertex in world space |
||||||
vec4 worldPos = g_WorldMatrix * vec4(inPosition, 1.0); |
worldPos = g_WorldMatrix * vec4(inPosition, 1.0); |
||||||
|
|
||||||
// convert vertex to light viewProj space |
#ifdef DISCARD_ALPHA |
||||||
//projCoord = biasMat * (m_LightViewProjectionMatrix * worldPos); |
texCoord = inTexCoord; |
||||||
vec4 coord = m_LightViewProjectionMatrix * worldPos; |
#endif |
||||||
projCoord = biasMat * coord; |
// populate the light view matrices array and convert vertex to light viewProj space |
||||||
//projCoord.z /= gl_DepthRange.far; |
projCoord0 = biasMat * m_LightViewProjectionMatrix0 * worldPos; |
||||||
//projCoord = (m_LightViewProjectionMatrix * worldPos); |
projCoord1 = biasMat * m_LightViewProjectionMatrix1 * worldPos; |
||||||
//projCoord /= projCoord.w; |
projCoord2 = biasMat * m_LightViewProjectionMatrix2 * worldPos; |
||||||
//projCoord.xy = projCoord.xy * vec2(0.5, -0.5) + vec2(0.5); |
projCoord3 = biasMat * m_LightViewProjectionMatrix3 * worldPos; |
||||||
|
#ifdef POINTLIGHT |
||||||
// bias from [-1, 1] to [0, 1] for sampling shadow map |
projCoord4 = biasMat * m_LightViewProjectionMatrix4 * worldPos; |
||||||
//projCoord = (projCoord.xyzw * vec4(0.5)) + vec4(0.5); |
projCoord5 = biasMat * m_LightViewProjectionMatrix5 * worldPos; |
||||||
|
#else |
||||||
|
|
||||||
|
vec4 vLightPos = g_ViewMatrix * vec4(m_LightPos,1.0); |
||||||
|
vec4 vPos = g_ViewMatrix * worldPos; |
||||||
|
lightVec = vLightPos.xyz - vPos.xyz; |
||||||
|
#endif |
||||||
} |
} |
@ -0,0 +1,72 @@ |
|||||||
|
#import "Common/ShaderLib/Shadows15.glsllib" |
||||||
|
|
||||||
|
out vec4 outFragColor; |
||||||
|
|
||||||
|
#ifdef PSSM |
||||||
|
in float shadowPosition; |
||||||
|
#endif |
||||||
|
|
||||||
|
in vec4 projCoord0; |
||||||
|
in vec4 projCoord1; |
||||||
|
in vec4 projCoord2; |
||||||
|
in vec4 projCoord3; |
||||||
|
|
||||||
|
#ifdef POINTLIGHT |
||||||
|
in vec4 projCoord4; |
||||||
|
in vec4 projCoord5; |
||||||
|
in vec4 worldPos; |
||||||
|
uniform vec3 m_LightPos; |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifdef DISCARD_ALPHA |
||||||
|
#ifdef COLOR_MAP |
||||||
|
uniform sampler2D m_ColorMap; |
||||||
|
#else |
||||||
|
uniform sampler2D m_DiffuseMap; |
||||||
|
#endif |
||||||
|
uniform float m_AlphaDiscardThreshold; |
||||||
|
varying vec2 texCoord; |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifdef FADE |
||||||
|
uniform vec2 m_FadeInfo; |
||||||
|
#endif |
||||||
|
|
||||||
|
void main(){ |
||||||
|
|
||||||
|
#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 |
||||||
|
|
||||||
|
float shadow = 1.0; |
||||||
|
#ifdef POINTLIGHT |
||||||
|
shadow = getPointLightShadows(worldPos, m_LightPos, |
||||||
|
m_ShadowMap0,m_ShadowMap1,m_ShadowMap2,m_ShadowMap3,m_ShadowMap4,m_ShadowMap5, |
||||||
|
projCoord0, projCoord1, projCoord2, projCoord3, projCoord4, projCoord5); |
||||||
|
#else |
||||||
|
#ifdef PSSM |
||||||
|
shadow = getDirectionalLightShadows(m_Splits, shadowPosition, |
||||||
|
m_ShadowMap0,m_ShadowMap1,m_ShadowMap2,m_ShadowMap3, |
||||||
|
projCoord0, projCoord1, projCoord2, projCoord3); |
||||||
|
#else |
||||||
|
//spotlight |
||||||
|
shadow = getSpotLightShadows(m_ShadowMap0,projCoord0); |
||||||
|
#endif |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifdef FADE |
||||||
|
shadow = max(0.0,mix(shadow,1.0,(shadowPosition - m_FadeInfo.x) * m_FadeInfo.y)); |
||||||
|
#endif |
||||||
|
|
||||||
|
shadow = shadow * m_ShadowIntensity + (1.0 - m_ShadowIntensity); |
||||||
|
outFragColor = vec4(shadow, shadow, shadow, 1.0); |
||||||
|
} |
||||||
|
|
@ -1,96 +0,0 @@ |
|||||||
#import "Common/ShaderLib/PssmShadows.glsllib" |
|
||||||
|
|
||||||
#ifdef PSSM |
|
||||||
varying float shadowPosition; |
|
||||||
#endif |
|
||||||
|
|
||||||
varying vec4 projCoord0; |
|
||||||
varying vec4 projCoord1; |
|
||||||
varying vec4 projCoord2; |
|
||||||
varying vec4 projCoord3; |
|
||||||
|
|
||||||
#ifdef POINTLIGHT |
|
||||||
varying vec4 projCoord4; |
|
||||||
varying vec4 projCoord5; |
|
||||||
uniform vec3 m_LightPos; |
|
||||||
varying vec4 worldPos; |
|
||||||
#endif |
|
||||||
|
|
||||||
#ifdef DISCARD_ALPHA |
|
||||||
#ifdef COLOR_MAP |
|
||||||
uniform sampler2D m_ColorMap; |
|
||||||
#else |
|
||||||
uniform sampler2D m_DiffuseMap; |
|
||||||
#endif |
|
||||||
uniform float m_AlphaDiscardThreshold; |
|
||||||
varying vec2 texCoord; |
|
||||||
#endif |
|
||||||
|
|
||||||
#ifdef FADE |
|
||||||
uniform vec2 m_FadeInfo; |
|
||||||
#endif |
|
||||||
|
|
||||||
void main(){ |
|
||||||
|
|
||||||
#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 |
|
||||||
|
|
||||||
float shadow = 1.0; |
|
||||||
#ifdef PSSM |
|
||||||
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); |
|
||||||
} |
|
||||||
#endif |
|
||||||
|
|
||||||
#ifdef POINTLIGHT |
|
||||||
vec3 vect = worldPos.xyz - m_LightPos; |
|
||||||
vec3 absv= abs(vect); |
|
||||||
float maxComp = max(absv.x,max(absv.y,absv.z)); |
|
||||||
if(maxComp == absv.y){ |
|
||||||
if(vect.y < 0.0){ |
|
||||||
shadow = GETSHADOW(m_ShadowMap0, projCoord0); |
|
||||||
}else{ |
|
||||||
shadow = GETSHADOW(m_ShadowMap1, projCoord1); |
|
||||||
} |
|
||||||
}else if(maxComp == absv.z){ |
|
||||||
if(vect.z < 0.0){ |
|
||||||
shadow = GETSHADOW(m_ShadowMap2, projCoord2); |
|
||||||
}else{ |
|
||||||
shadow = GETSHADOW(m_ShadowMap3, projCoord3); |
|
||||||
} |
|
||||||
}else if(maxComp == absv.x){ |
|
||||||
if(vect.x < 0.0){ |
|
||||||
shadow = GETSHADOW(m_ShadowMap4, projCoord4); |
|
||||||
}else{ |
|
||||||
shadow = GETSHADOW(m_ShadowMap5, projCoord5); |
|
||||||
} |
|
||||||
} |
|
||||||
#endif |
|
||||||
|
|
||||||
#ifdef FADE |
|
||||||
shadow = max(0.0,mix(shadow,1.0,(shadowPosition - m_FadeInfo.x) * m_FadeInfo.y)); |
|
||||||
#endif |
|
||||||
shadow = shadow * m_ShadowIntensity + (1.0 - m_ShadowIntensity); |
|
||||||
|
|
||||||
gl_FragColor = vec4(shadow, shadow, shadow, 1.0); |
|
||||||
|
|
||||||
} |
|
||||||
|
|
@ -1,85 +0,0 @@ |
|||||||
MaterialDef Post Shadow { |
|
||||||
|
|
||||||
MaterialParameters { |
|
||||||
Int FilterMode |
|
||||||
Boolean HardwareShadows |
|
||||||
|
|
||||||
Texture2D ShadowMap0 |
|
||||||
Texture2D ShadowMap1 |
|
||||||
Texture2D ShadowMap2 |
|
||||||
Texture2D ShadowMap3 |
|
||||||
//pointLights |
|
||||||
Texture2D ShadowMap4 |
|
||||||
Texture2D ShadowMap5 |
|
||||||
|
|
||||||
Float ShadowIntensity |
|
||||||
Vector4 Splits |
|
||||||
Vector2 FadeInfo |
|
||||||
|
|
||||||
Matrix4 LightViewProjectionMatrix0 |
|
||||||
Matrix4 LightViewProjectionMatrix1 |
|
||||||
Matrix4 LightViewProjectionMatrix2 |
|
||||||
Matrix4 LightViewProjectionMatrix3 |
|
||||||
//pointLight |
|
||||||
Matrix4 LightViewProjectionMatrix4 |
|
||||||
Matrix4 LightViewProjectionMatrix5 |
|
||||||
Vector3 LightPos |
|
||||||
|
|
||||||
Float PCFEdge |
|
||||||
|
|
||||||
Float ShadowMapSize |
|
||||||
} |
|
||||||
|
|
||||||
Technique { |
|
||||||
VertexShader GLSL150: Common/MatDefs/Shadow/PostShadowPSSM.vert |
|
||||||
FragmentShader GLSL150: Common/MatDefs/Shadow/PostShadowPSSM15.frag |
|
||||||
|
|
||||||
WorldParameters { |
|
||||||
WorldViewProjectionMatrix |
|
||||||
WorldMatrix |
|
||||||
} |
|
||||||
|
|
||||||
Defines { |
|
||||||
HARDWARE_SHADOWS : HardwareShadows |
|
||||||
FILTER_MODE : FilterMode |
|
||||||
PCFEDGE : PCFEdge |
|
||||||
SHADOWMAP_SIZE : ShadowMapSize |
|
||||||
FADE : FadeInfo |
|
||||||
PSSM : Splits |
|
||||||
POINTLIGHT : LightViewProjectionMatrix5 |
|
||||||
} |
|
||||||
|
|
||||||
RenderState { |
|
||||||
Blend Modulate |
|
||||||
DepthWrite Off |
|
||||||
PolyOffset -0.1 0 |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
Technique { |
|
||||||
VertexShader GLSL100: Common/MatDefs/Shadow/PostShadowPSSM.vert |
|
||||||
FragmentShader GLSL100: Common/MatDefs/Shadow/PostShadowPSSM.frag |
|
||||||
|
|
||||||
WorldParameters { |
|
||||||
WorldViewProjectionMatrix |
|
||||||
WorldMatrix |
|
||||||
} |
|
||||||
|
|
||||||
Defines { |
|
||||||
HARDWARE_SHADOWS : HardwareShadows |
|
||||||
FILTER_MODE : FilterMode |
|
||||||
PCFEDGE : PCFEdge |
|
||||||
SHADOWMAP_SIZE : ShadowMapSize |
|
||||||
FADE : FadeInfo |
|
||||||
PSSM : Splits |
|
||||||
POINTLIGHT : LightViewProjectionMatrix5 |
|
||||||
} |
|
||||||
|
|
||||||
RenderState { |
|
||||||
Blend Modulate |
|
||||||
DepthWrite Off |
|
||||||
PolyOffset -0.1 0 |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,62 +0,0 @@ |
|||||||
uniform mat4 m_LightViewProjectionMatrix0; |
|
||||||
uniform mat4 m_LightViewProjectionMatrix1; |
|
||||||
uniform mat4 m_LightViewProjectionMatrix2; |
|
||||||
uniform mat4 m_LightViewProjectionMatrix3; |
|
||||||
|
|
||||||
uniform mat4 g_WorldViewProjectionMatrix; |
|
||||||
uniform mat4 g_WorldMatrix; |
|
||||||
|
|
||||||
varying vec4 projCoord0; |
|
||||||
varying vec4 projCoord1; |
|
||||||
varying vec4 projCoord2; |
|
||||||
varying vec4 projCoord3; |
|
||||||
|
|
||||||
#ifdef POINTLIGHT |
|
||||||
uniform mat4 m_LightViewProjectionMatrix4; |
|
||||||
uniform mat4 m_LightViewProjectionMatrix5; |
|
||||||
varying vec4 projCoord4; |
|
||||||
varying vec4 projCoord5; |
|
||||||
varying vec4 worldPos; |
|
||||||
#endif |
|
||||||
|
|
||||||
#ifdef PSSM |
|
||||||
varying float shadowPosition; |
|
||||||
#endif |
|
||||||
|
|
||||||
varying vec2 texCoord; |
|
||||||
|
|
||||||
attribute vec3 inPosition; |
|
||||||
|
|
||||||
#ifdef DISCARD_ALPHA |
|
||||||
attribute vec2 inTexCoord; |
|
||||||
#endif |
|
||||||
|
|
||||||
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); |
|
||||||
|
|
||||||
|
|
||||||
void main(){ |
|
||||||
gl_Position = g_WorldViewProjectionMatrix * vec4(inPosition, 1.0); |
|
||||||
|
|
||||||
#ifdef PSSM |
|
||||||
shadowPosition = gl_Position.z; |
|
||||||
vec4 worldPos=vec4(0.0); |
|
||||||
#endif |
|
||||||
// get the vertex in world space |
|
||||||
worldPos = g_WorldMatrix * vec4(inPosition, 1.0); |
|
||||||
|
|
||||||
#ifdef DISCARD_ALPHA |
|
||||||
texCoord = inTexCoord; |
|
||||||
#endif |
|
||||||
// populate the light view matrices array and convert vertex to light viewProj space |
|
||||||
projCoord0 = biasMat * m_LightViewProjectionMatrix0 * worldPos; |
|
||||||
projCoord1 = biasMat * m_LightViewProjectionMatrix1 * worldPos; |
|
||||||
projCoord2 = biasMat * m_LightViewProjectionMatrix2 * worldPos; |
|
||||||
projCoord3 = biasMat * m_LightViewProjectionMatrix3 * worldPos; |
|
||||||
#ifdef POINTLIGHT |
|
||||||
projCoord4 = biasMat * m_LightViewProjectionMatrix4 * worldPos; |
|
||||||
projCoord5 = biasMat * m_LightViewProjectionMatrix5 * worldPos; |
|
||||||
#endif |
|
||||||
} |
|
@ -1,105 +0,0 @@ |
|||||||
#import "Common/ShaderLib/PssmShadows15.glsllib" |
|
||||||
|
|
||||||
out vec4 outFragColor; |
|
||||||
|
|
||||||
#ifdef PSSM |
|
||||||
in float shadowPosition; |
|
||||||
#endif |
|
||||||
|
|
||||||
in vec4 projCoord0; |
|
||||||
in vec4 projCoord1; |
|
||||||
in vec4 projCoord2; |
|
||||||
in vec4 projCoord3; |
|
||||||
|
|
||||||
#ifdef POINTLIGHT |
|
||||||
in vec4 projCoord4; |
|
||||||
in vec4 projCoord5; |
|
||||||
uniform vec3 m_LightPos; |
|
||||||
in vec4 worldPos; |
|
||||||
#endif |
|
||||||
|
|
||||||
#ifdef DISCARD_ALPHA |
|
||||||
#ifdef COLOR_MAP |
|
||||||
uniform sampler2D m_ColorMap; |
|
||||||
#else |
|
||||||
uniform sampler2D m_DiffuseMap; |
|
||||||
#endif |
|
||||||
uniform float m_AlphaDiscardThreshold; |
|
||||||
varying vec2 texCoord; |
|
||||||
#endif |
|
||||||
|
|
||||||
#ifdef FADE |
|
||||||
uniform vec2 m_FadeInfo; |
|
||||||
#endif |
|
||||||
|
|
||||||
void main(){ |
|
||||||
|
|
||||||
#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 |
|
||||||
|
|
||||||
float shadow = 1.0; |
|
||||||
#ifdef PSSM |
|
||||||
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); |
|
||||||
} |
|
||||||
#endif |
|
||||||
|
|
||||||
|
|
||||||
#ifdef POINTLIGHT |
|
||||||
vec3 vect = worldPos.xyz - m_LightPos; |
|
||||||
vec3 absv= abs(vect); |
|
||||||
float maxComp = max(absv.x,max(absv.y,absv.z)); |
|
||||||
if(maxComp == absv.y){ |
|
||||||
if(vect.y < 0.0){ |
|
||||||
shadow = GETSHADOW(m_ShadowMap0, projCoord0); |
|
||||||
outFragColor = vec4(projCoord0.z); |
|
||||||
}else{ |
|
||||||
shadow = GETSHADOW(m_ShadowMap1, projCoord1); |
|
||||||
outFragColor = vec4(projCoord1.z); |
|
||||||
} |
|
||||||
}else if(maxComp == absv.z){ |
|
||||||
if(vect.z < 0.0){ |
|
||||||
shadow = GETSHADOW(m_ShadowMap2, projCoord2); |
|
||||||
outFragColor =vec4(projCoord2.z); |
|
||||||
}else{ |
|
||||||
shadow = GETSHADOW(m_ShadowMap3, projCoord3); |
|
||||||
outFragColor = vec4(projCoord3.z); |
|
||||||
} |
|
||||||
}else if(maxComp == absv.x){ |
|
||||||
if(vect.x < 0.0){ |
|
||||||
shadow = GETSHADOW(m_ShadowMap4, projCoord4); |
|
||||||
outFragColor = vec4(projCoord4.z); |
|
||||||
}else{ |
|
||||||
shadow = GETSHADOW(m_ShadowMap5, projCoord5); |
|
||||||
outFragColor = vec4(projCoord5.z); |
|
||||||
} |
|
||||||
} |
|
||||||
#endif |
|
||||||
|
|
||||||
#ifdef FADE |
|
||||||
shadow = max(0.0,mix(shadow,1.0,(shadowPosition - m_FadeInfo.x) * m_FadeInfo.y)); |
|
||||||
#endif |
|
||||||
|
|
||||||
shadow = shadow * m_ShadowIntensity + (1.0 - m_ShadowIntensity); |
|
||||||
outFragColor = vec4(shadow, shadow, shadow, 1.0); |
|
||||||
|
|
||||||
} |
|
||||||
|
|
@ -0,0 +1,233 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2012 jMonkeyEngine |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions are |
||||||
|
* met: |
||||||
|
* |
||||||
|
* * Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* * Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||||
|
* may be used to endorse or promote products derived from this software |
||||||
|
* without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
package 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.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.texture.FrameBuffer; |
||||||
|
import java.io.IOException; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* Generic abstract filter that holds common implementations for the different |
||||||
|
* shadow filtesr |
||||||
|
* |
||||||
|
* @author Rémy Bouquet aka Nehon |
||||||
|
*/ |
||||||
|
public abstract class AbstractShadowFilter<T extends AbstractShadowRenderer> extends Filter { |
||||||
|
|
||||||
|
protected T shadowRenderer; |
||||||
|
protected ViewPort viewPort; |
||||||
|
|
||||||
|
/** |
||||||
|
* Abstract class constructor |
||||||
|
* |
||||||
|
* @param manager the application asset manager |
||||||
|
* @param shadowMapSize the size of the rendered shadowmaps (512,1024,2048, |
||||||
|
* etc...) |
||||||
|
* @param nbShadowMaps the number of shadow maps rendered (the more shadow |
||||||
|
* maps the more quality, the less fps). |
||||||
|
* @param shadowRenderer the shadowRenderer to use for this Filter |
||||||
|
*/ |
||||||
|
@SuppressWarnings("all") |
||||||
|
protected AbstractShadowFilter(AssetManager manager, int shadowMapSize, T shadowRenderer) { |
||||||
|
super("Post Shadow"); |
||||||
|
material = new Material(manager, "Common/MatDefs/Shadow/PostShadowFilter.j3md"); |
||||||
|
this.shadowRenderer = shadowRenderer; |
||||||
|
this.shadowRenderer.setPostShadowMaterial(material); |
||||||
|
} |
||||||
|
|
||||||
|
@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) { |
||||||
|
shadowRenderer.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) { |
||||||
|
shadowRenderer.postQueue(queue); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void postFrame(RenderManager renderManager, ViewPort viewPort, FrameBuffer prevFilterBuffer, FrameBuffer sceneBuffer) { |
||||||
|
shadowRenderer.setPostShadowParams(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) { |
||||||
|
shadowRenderer.needsfallBackMaterial = true; |
||||||
|
shadowRenderer.initialize(renderManager, vp); |
||||||
|
this.viewPort = vp; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* returns the shdaow intensity |
||||||
|
* |
||||||
|
* @see #setShadowIntensity(float shadowIntensity) |
||||||
|
* @return shadowIntensity |
||||||
|
*/ |
||||||
|
public float getShadowIntensity() { |
||||||
|
return shadowRenderer.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) { |
||||||
|
shadowRenderer.setShadowIntensity(shadowIntensity); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* returns the edges thickness <br> |
||||||
|
* |
||||||
|
* @see #setEdgesThickness(int edgesThickness) |
||||||
|
* @return edgesThickness |
||||||
|
*/ |
||||||
|
public int getEdgesThickness() { |
||||||
|
return shadowRenderer.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) { |
||||||
|
shadowRenderer.setEdgesThickness(edgesThickness); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* returns true if the PssmRenderer flushed the shadow queues |
||||||
|
* |
||||||
|
* @return flushQueues |
||||||
|
*/ |
||||||
|
public boolean isFlushQueues() { |
||||||
|
return shadowRenderer.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) { |
||||||
|
shadowRenderer.setFlushQueues(flushQueues); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* sets the shadow compare mode see {@link CompareMode} for more info |
||||||
|
* |
||||||
|
* @param compareMode |
||||||
|
*/ |
||||||
|
final public void setShadowCompareMode(CompareMode compareMode) { |
||||||
|
shadowRenderer.setShadowCompareMode(compareMode); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* returns the shadow compare mode |
||||||
|
* |
||||||
|
* @see CompareMode |
||||||
|
* @return the shadowCompareMode |
||||||
|
*/ |
||||||
|
public CompareMode getShadowCompareMode() { |
||||||
|
return shadowRenderer.getShadowCompareMode(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the filtering mode for shadow edges see {@link EdgeFilteringMode} |
||||||
|
* for more info |
||||||
|
* |
||||||
|
* @param filterMode |
||||||
|
*/ |
||||||
|
final public void setEdgeFilteringMode(EdgeFilteringMode filterMode) { |
||||||
|
shadowRenderer.setEdgeFilteringMode(filterMode); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* returns the the edge filtering mode |
||||||
|
* |
||||||
|
* @see EdgeFilteringMode |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public EdgeFilteringMode getEdgeFilteringMode() { |
||||||
|
return shadowRenderer.getEdgeFilteringMode(); |
||||||
|
} |
||||||
|
|
||||||
|
@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); |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,563 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2012 jMonkeyEngine |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions are |
||||||
|
* met: |
||||||
|
* |
||||||
|
* * Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* * Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||||
|
* may be used to endorse or promote products derived from this software |
||||||
|
* without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
package com.jme3.shadow; |
||||||
|
|
||||||
|
import com.jme3.asset.AssetManager; |
||||||
|
import com.jme3.material.Material; |
||||||
|
import com.jme3.math.ColorRGBA; |
||||||
|
import com.jme3.math.Matrix4f; |
||||||
|
import com.jme3.math.Vector3f; |
||||||
|
import com.jme3.post.SceneProcessor; |
||||||
|
import com.jme3.renderer.Camera; |
||||||
|
import com.jme3.renderer.Caps; |
||||||
|
import com.jme3.renderer.RenderManager; |
||||||
|
import com.jme3.renderer.Renderer; |
||||||
|
import com.jme3.renderer.ViewPort; |
||||||
|
import com.jme3.renderer.queue.GeometryList; |
||||||
|
import com.jme3.renderer.queue.RenderQueue; |
||||||
|
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.shadow.PssmShadowRenderer.FilterMode; |
||||||
|
import com.jme3.texture.FrameBuffer; |
||||||
|
import com.jme3.texture.Image.Format; |
||||||
|
import com.jme3.texture.Texture.MagFilter; |
||||||
|
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; |
||||||
|
|
||||||
|
/** |
||||||
|
* abstract shadow renderer that holds commons feature to have for a shadow renderer |
||||||
|
* @author Rémy Bouquet aka Nehon |
||||||
|
*/ |
||||||
|
public abstract class AbstractShadowRenderer implements SceneProcessor { |
||||||
|
|
||||||
|
protected int nbShadowMaps = 1; |
||||||
|
protected float shadowMapSize; |
||||||
|
protected float shadowIntensity = 0.7f; |
||||||
|
protected RenderManager renderManager; |
||||||
|
protected ViewPort viewPort; |
||||||
|
protected FrameBuffer[] shadowFB; |
||||||
|
protected Texture2D[] shadowMaps; |
||||||
|
protected Texture2D dummyTex; |
||||||
|
protected Material preshadowMat; |
||||||
|
protected Material postshadowMat; |
||||||
|
protected Matrix4f[] lightViewProjectionsMatrices; |
||||||
|
protected boolean noOccluders = false; |
||||||
|
protected AssetManager assetManager; |
||||||
|
protected boolean debug = false; |
||||||
|
protected float edgesThickness = 1.0f; |
||||||
|
protected EdgeFilteringMode edgeFilteringMode; |
||||||
|
protected CompareMode shadowCompareMode; |
||||||
|
protected Picture[] dispPic; |
||||||
|
protected boolean flushQueues = true; |
||||||
|
// define if the fallback material should be used.
|
||||||
|
protected boolean needsfallBackMaterial = false; |
||||||
|
//Name of the post material technique
|
||||||
|
protected String postTechniqueName = "PostShadow"; |
||||||
|
//flags to know when to change params in the materials
|
||||||
|
//a list of material of the post shadow queue geometries.
|
||||||
|
protected List<Material> matCache = new ArrayList<Material>(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Create an abstract shadow renderer, this is to be called in extending classes |
||||||
|
* @param assetManager the application asset manager |
||||||
|
* @param shadowMapSize the size of the rendered shadowmaps (512,1024,2048, |
||||||
|
* etc...) |
||||||
|
* @param nbShadowMaps the number of shadow maps rendered (the more shadow |
||||||
|
* maps the more quality, the less fps). |
||||||
|
*/ |
||||||
|
protected AbstractShadowRenderer(AssetManager assetManager, int shadowMapSize, int nbShadowMaps) { |
||||||
|
|
||||||
|
this.assetManager = assetManager; |
||||||
|
this.postshadowMat = new Material(assetManager, "Common/MatDefs/Shadow/PostShadow.j3md"); |
||||||
|
this.nbShadowMaps = nbShadowMaps; |
||||||
|
this.shadowMapSize = shadowMapSize; |
||||||
|
shadowFB = new FrameBuffer[nbShadowMaps]; |
||||||
|
shadowMaps = new Texture2D[nbShadowMaps]; |
||||||
|
dispPic = new Picture[nbShadowMaps]; |
||||||
|
lightViewProjectionsMatrices = new Matrix4f[nbShadowMaps]; |
||||||
|
|
||||||
|
//DO NOT COMMENT THIS (it prevent the OSX incomplete read buffer crash)
|
||||||
|
dummyTex = new Texture2D(shadowMapSize, shadowMapSize, Format.RGBA8); |
||||||
|
|
||||||
|
preshadowMat = new Material(assetManager, "Common/MatDefs/Shadow/PreShadow.j3md"); |
||||||
|
postshadowMat.setFloat("ShadowMapSize", shadowMapSize); |
||||||
|
|
||||||
|
for (int i = 0; i < nbShadowMaps; i++) { |
||||||
|
lightViewProjectionsMatrices[i] = new Matrix4f(); |
||||||
|
shadowFB[i] = new FrameBuffer(shadowMapSize, shadowMapSize, 1); |
||||||
|
shadowMaps[i] = new Texture2D(shadowMapSize, shadowMapSize, Format.Depth); |
||||||
|
|
||||||
|
shadowFB[i].setDepthTexture(shadowMaps[i]); |
||||||
|
|
||||||
|
//DO NOT COMMENT THIS (it prevent the OSX incomplete read buffer crash)
|
||||||
|
shadowFB[i].setColorTexture(dummyTex); |
||||||
|
|
||||||
|
postshadowMat.setTexture("ShadowMap" + i, shadowMaps[i]); |
||||||
|
|
||||||
|
//quads for debuging purpose
|
||||||
|
dispPic[i] = new Picture("Picture" + i); |
||||||
|
dispPic[i].setTexture(assetManager, shadowMaps[i], false); |
||||||
|
} |
||||||
|
|
||||||
|
setShadowCompareMode(CompareMode.Hardware); |
||||||
|
setEdgeFilteringMode(EdgeFilteringMode.Bilinear); |
||||||
|
setShadowIntensity(0.7f); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* set the post shadow material for this renderer |
||||||
|
* @param postShadowMat |
||||||
|
*/ |
||||||
|
protected final void setPostShadowMaterial(Material postShadowMat) { |
||||||
|
this.postshadowMat = postShadowMat; |
||||||
|
postshadowMat.setFloat("ShadowMapSize", shadowMapSize); |
||||||
|
for (int i = 0; i < nbShadowMaps; i++) { |
||||||
|
postshadowMat.setTexture("ShadowMap" + i, shadowMaps[i]); |
||||||
|
} |
||||||
|
setShadowCompareMode(shadowCompareMode); |
||||||
|
setEdgeFilteringMode(edgeFilteringMode); |
||||||
|
setShadowIntensity(shadowIntensity); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the filtering mode for shadow edges see {@link FilterMode} for more |
||||||
|
* info |
||||||
|
* |
||||||
|
* @param filterMode |
||||||
|
*/ |
||||||
|
final public void setEdgeFilteringMode(EdgeFilteringMode filterMode) { |
||||||
|
if (filterMode == null) { |
||||||
|
throw new NullPointerException(); |
||||||
|
} |
||||||
|
|
||||||
|
if (this.edgeFilteringMode == filterMode) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
this.edgeFilteringMode = filterMode; |
||||||
|
postshadowMat.setInt("FilterMode", filterMode.getMaterialParamValue()); |
||||||
|
postshadowMat.setFloat("PCFEdge", edgesThickness); |
||||||
|
if (shadowCompareMode == CompareMode.Hardware) { |
||||||
|
for (Texture2D shadowMap : shadowMaps) { |
||||||
|
if (filterMode == EdgeFilteringMode.Bilinear) { |
||||||
|
shadowMap.setMagFilter(MagFilter.Bilinear); |
||||||
|
shadowMap.setMinFilter(MinFilter.BilinearNoMipMaps); |
||||||
|
} else { |
||||||
|
shadowMap.setMagFilter(MagFilter.Nearest); |
||||||
|
shadowMap.setMinFilter(MinFilter.NearestNoMipMaps); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* returns the the edge filtering mode |
||||||
|
* |
||||||
|
* @see EdgeFilteringMode |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public EdgeFilteringMode getEdgeFilteringMode() { |
||||||
|
return edgeFilteringMode; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* sets the shadow compare mode see {@link CompareMode} for more info |
||||||
|
* |
||||||
|
* @param compareMode |
||||||
|
*/ |
||||||
|
final public void setShadowCompareMode(CompareMode compareMode) { |
||||||
|
if (compareMode == null) { |
||||||
|
throw new NullPointerException(); |
||||||
|
} |
||||||
|
|
||||||
|
if (this.shadowCompareMode == compareMode) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
this.shadowCompareMode = compareMode; |
||||||
|
for (Texture2D shadowMap : shadowMaps) { |
||||||
|
if (compareMode == CompareMode.Hardware) { |
||||||
|
shadowMap.setShadowCompareMode(ShadowCompareMode.LessOrEqual); |
||||||
|
if (edgeFilteringMode == EdgeFilteringMode.Bilinear) { |
||||||
|
shadowMap.setMagFilter(MagFilter.Bilinear); |
||||||
|
shadowMap.setMinFilter(MinFilter.BilinearNoMipMaps); |
||||||
|
} else { |
||||||
|
shadowMap.setMagFilter(MagFilter.Nearest); |
||||||
|
shadowMap.setMinFilter(MinFilter.NearestNoMipMaps); |
||||||
|
} |
||||||
|
} else { |
||||||
|
shadowMap.setShadowCompareMode(ShadowCompareMode.Off); |
||||||
|
shadowMap.setMagFilter(MagFilter.Nearest); |
||||||
|
shadowMap.setMinFilter(MinFilter.NearestNoMipMaps); |
||||||
|
} |
||||||
|
} |
||||||
|
postshadowMat.setBoolean("HardwareShadows", compareMode == CompareMode.Hardware); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* returns the shadow compare mode |
||||||
|
* |
||||||
|
* @see CompareMode |
||||||
|
* @return the shadowCompareMode |
||||||
|
*/ |
||||||
|
public CompareMode getShadowCompareMode() { |
||||||
|
return shadowCompareMode; |
||||||
|
} |
||||||
|
|
||||||
|
//debug function that create a displayable frustrum
|
||||||
|
protected Geometry createFrustum(Vector3f[] pts, int i) { |
||||||
|
WireFrustum frustum = new WireFrustum(pts); |
||||||
|
Geometry frustumMdl = new Geometry("f", frustum); |
||||||
|
frustumMdl.setCullHint(Spatial.CullHint.Never); |
||||||
|
frustumMdl.setShadowMode(ShadowMode.Off); |
||||||
|
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); |
||||||
|
mat.getAdditionalRenderState().setWireframe(true); |
||||||
|
frustumMdl.setMaterial(mat); |
||||||
|
switch (i) { |
||||||
|
case 0: |
||||||
|
frustumMdl.getMaterial().setColor("Color", ColorRGBA.Pink); |
||||||
|
break; |
||||||
|
case 1: |
||||||
|
frustumMdl.getMaterial().setColor("Color", ColorRGBA.Red); |
||||||
|
break; |
||||||
|
case 2: |
||||||
|
frustumMdl.getMaterial().setColor("Color", ColorRGBA.Green); |
||||||
|
break; |
||||||
|
case 3: |
||||||
|
frustumMdl.getMaterial().setColor("Color", ColorRGBA.Blue); |
||||||
|
break; |
||||||
|
default: |
||||||
|
frustumMdl.getMaterial().setColor("Color", ColorRGBA.White); |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
frustumMdl.updateGeometricState(); |
||||||
|
return frustumMdl; |
||||||
|
} |
||||||
|
|
||||||
|
public void initialize(RenderManager rm, ViewPort vp) { |
||||||
|
renderManager = rm; |
||||||
|
viewPort = vp; |
||||||
|
//checking for caps to chosse the appropriate post material technique
|
||||||
|
if (renderManager.getRenderer().getCaps().contains(Caps.GLSL150)) { |
||||||
|
postTechniqueName = "PostShadow15"; |
||||||
|
} else { |
||||||
|
postTechniqueName = "PostShadow"; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isInitialized() { |
||||||
|
return viewPort != null; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* This mehtod is called once per frame. |
||||||
|
* it is responsible for updating the shadow cams according to the light view. |
||||||
|
* @param viewCam the scene cam |
||||||
|
*/ |
||||||
|
protected abstract void updateShadowCams(Camera viewCam); |
||||||
|
|
||||||
|
/** |
||||||
|
* this method must return the geomtryList that contains the oclluders to be rendered in the shadow map |
||||||
|
* @param shadowMapIndex the index of the shadow map being rendered |
||||||
|
* @param sceneOccluders the occluders of the whole scene |
||||||
|
* @param sceneReceivers the recievers of the whole scene |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
protected abstract GeometryList getOccludersToRender(int shadowMapIndex, GeometryList sceneOccluders, GeometryList sceneReceivers); |
||||||
|
|
||||||
|
/** |
||||||
|
* return the shadow camera to use for rendering the shadow map according the given index |
||||||
|
* @param shadowMapIndex the index of the shadow map being rendered |
||||||
|
* @return the shadowCam |
||||||
|
*/ |
||||||
|
protected abstract Camera getShadowCam(int shadowMapIndex); |
||||||
|
|
||||||
|
/** |
||||||
|
* responsible for displaying the frustum of the shadow cam for debug purpose |
||||||
|
* @param shadowMapIndex |
||||||
|
*/ |
||||||
|
protected void doDisplayFrustumDebug(int shadowMapIndex) { |
||||||
|
} |
||||||
|
|
||||||
|
@SuppressWarnings("fallthrough") |
||||||
|
public void postQueue(RenderQueue rq) { |
||||||
|
GeometryList occluders = rq.getShadowQueueContent(ShadowMode.Cast); |
||||||
|
GeometryList receivers = rq.getShadowQueueContent(ShadowMode.Receive); |
||||||
|
if (receivers.size() == 0 || occluders.size() == 0) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
updateShadowCams(viewPort.getCamera()); |
||||||
|
|
||||||
|
Renderer r = renderManager.getRenderer(); |
||||||
|
renderManager.setForcedMaterial(preshadowMat); |
||||||
|
renderManager.setForcedTechnique("PreShadow"); |
||||||
|
|
||||||
|
for (int shadowMapIndex = 0; shadowMapIndex < nbShadowMaps; shadowMapIndex++) { |
||||||
|
|
||||||
|
if (debugfrustums) { |
||||||
|
doDisplayFrustumDebug(shadowMapIndex); |
||||||
|
} |
||||||
|
renderShadowMap(shadowMapIndex, occluders, receivers); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
debugfrustums = false; |
||||||
|
if (flushQueues) { |
||||||
|
occluders.clear(); |
||||||
|
} |
||||||
|
//restore setting for future rendering
|
||||||
|
r.setFrameBuffer(viewPort.getOutputFrameBuffer()); |
||||||
|
renderManager.setForcedMaterial(null); |
||||||
|
renderManager.setForcedTechnique(null); |
||||||
|
renderManager.setCamera(viewPort.getCamera(), false); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
protected void renderShadowMap(int shadowMapIndex, GeometryList occluders, GeometryList receivers) { |
||||||
|
GeometryList mapOccluders = getOccludersToRender(shadowMapIndex, occluders, receivers); |
||||||
|
Camera shadowCam = getShadowCam(shadowMapIndex); |
||||||
|
|
||||||
|
//saving light view projection matrix for this split
|
||||||
|
lightViewProjectionsMatrices[shadowMapIndex].set(shadowCam.getViewProjectionMatrix()); |
||||||
|
renderManager.setCamera(shadowCam, false); |
||||||
|
|
||||||
|
renderManager.getRenderer().setFrameBuffer(shadowFB[shadowMapIndex]); |
||||||
|
renderManager.getRenderer().clearBuffers(false, true, false); |
||||||
|
|
||||||
|
// render shadow casters to shadow map
|
||||||
|
viewPort.getQueue().renderShadowQueue(mapOccluders, renderManager, shadowCam, true); |
||||||
|
} |
||||||
|
boolean debugfrustums = false; |
||||||
|
|
||||||
|
public void displayFrustum() { |
||||||
|
debugfrustums = true; |
||||||
|
} |
||||||
|
|
||||||
|
//debug only : displays depth shadow maps
|
||||||
|
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].setWidth(128); |
||||||
|
dispPic[i].setHeight(128); |
||||||
|
dispPic[i].updateGeometricState(); |
||||||
|
renderManager.renderGeometry(dispPic[i]); |
||||||
|
} |
||||||
|
renderManager.setCamera(cam, false); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* For dubuging purpose Allow to "snapshot" the current frustrum to the |
||||||
|
* scene |
||||||
|
*/ |
||||||
|
public void displayDebug() { |
||||||
|
debug = true; |
||||||
|
} |
||||||
|
|
||||||
|
public void postFrame(FrameBuffer out) { |
||||||
|
|
||||||
|
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); |
||||||
|
} |
||||||
|
|
||||||
|
//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.setCamera(cam, false); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* This method is called once per frame and is responsible of setting the material |
||||||
|
* parameters than sub class may need to set on the post material |
||||||
|
* @param material the materail to use for the post shadow pass |
||||||
|
*/ |
||||||
|
protected abstract void setMaterialParameters(Material material); |
||||||
|
|
||||||
|
private void setMatParams() { |
||||||
|
|
||||||
|
GeometryList l = viewPort.getQueue().getShadowQueueContent(ShadowMode.Receive); |
||||||
|
|
||||||
|
//iteration throught all the geometries of the list to gather the materials
|
||||||
|
|
||||||
|
matCache.clear(); |
||||||
|
for (int i = 0; i < l.size(); i++) { |
||||||
|
Material mat = l.get(i).getMaterial(); |
||||||
|
//checking if the material has the post technique and adding it to the material cache
|
||||||
|
if (mat.getMaterialDef().getTechniqueDef(postTechniqueName) != null) { |
||||||
|
if (!matCache.contains(mat)) { |
||||||
|
matCache.add(mat); |
||||||
|
} |
||||||
|
} else { |
||||||
|
needsfallBackMaterial = true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
//iterating through the mat cache and setting the parameters
|
||||||
|
for (Material mat : matCache) { |
||||||
|
|
||||||
|
mat.setFloat("ShadowMapSize", shadowMapSize); |
||||||
|
|
||||||
|
for (int j = 0; j < nbShadowMaps; j++) { |
||||||
|
mat.setMatrix4("LightViewProjectionMatrix" + j, lightViewProjectionsMatrices[j]); |
||||||
|
} |
||||||
|
for (int j = 0; j < nbShadowMaps; j++) { |
||||||
|
mat.setTexture("ShadowMap" + j, shadowMaps[j]); |
||||||
|
} |
||||||
|
mat.setBoolean("HardwareShadows", shadowCompareMode == CompareMode.Hardware); |
||||||
|
mat.setInt("FilterMode", edgeFilteringMode.getMaterialParamValue()); |
||||||
|
mat.setFloat("PCFEdge", edgesThickness); |
||||||
|
mat.setFloat("ShadowIntensity", shadowIntensity); |
||||||
|
|
||||||
|
setMaterialParameters(mat); |
||||||
|
} |
||||||
|
|
||||||
|
//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) { |
||||||
|
setPostShadowParams(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* for internal use only |
||||||
|
*/ |
||||||
|
protected void setPostShadowParams() { |
||||||
|
setMaterialParameters(postshadowMat); |
||||||
|
for (int j = 0; j < nbShadowMaps; j++) { |
||||||
|
postshadowMat.setMatrix4("LightViewProjectionMatrix" + j, lightViewProjectionsMatrices[j]); |
||||||
|
postshadowMat.setTexture("ShadowMap" + j, shadowMaps[j]); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void preFrame(float tpf) { |
||||||
|
} |
||||||
|
|
||||||
|
public void cleanup() { |
||||||
|
} |
||||||
|
|
||||||
|
public void reshape(ViewPort vp, int w, int h) { |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* returns the shdaow intensity |
||||||
|
* |
||||||
|
* @see #setShadowIntensity(float shadowIntensity) |
||||||
|
* @return shadowIntensity |
||||||
|
*/ |
||||||
|
public float getShadowIntensity() { |
||||||
|
return shadowIntensity; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 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) { |
||||||
|
this.shadowIntensity = shadowIntensity; |
||||||
|
postshadowMat.setFloat("ShadowIntensity", shadowIntensity); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* returns the edges thickness |
||||||
|
* |
||||||
|
* @see #setEdgesThickness(int edgesThickness) |
||||||
|
* @return edgesThickness |
||||||
|
*/ |
||||||
|
public int getEdgesThickness() { |
||||||
|
return (int) (edgesThickness * 10); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 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) { |
||||||
|
this.edgesThickness = Math.max(1, Math.min(edgesThickness, 10)); |
||||||
|
this.edgesThickness *= 0.1f; |
||||||
|
postshadowMat.setFloat("PCFEdge", edgesThickness); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* returns true if the PssmRenderer flushed the shadow queues |
||||||
|
* |
||||||
|
* @return flushQueues |
||||||
|
*/ |
||||||
|
public boolean isFlushQueues() { |
||||||
|
return flushQueues; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 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) { |
||||||
|
this.flushQueues = flushQueues; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,48 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2012 jMonkeyEngine |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions are |
||||||
|
* met: |
||||||
|
* |
||||||
|
* * Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* * Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||||
|
* may be used to endorse or promote products derived from this software |
||||||
|
* without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
package com.jme3.shadow; |
||||||
|
|
||||||
|
/** |
||||||
|
* Specifies the shadow comparison mode |
||||||
|
*/ |
||||||
|
public enum CompareMode { |
||||||
|
|
||||||
|
/** |
||||||
|
* Shadow depth comparisons are done by using shader code |
||||||
|
*/ |
||||||
|
Software, |
||||||
|
/** |
||||||
|
* Shadow depth comparisons are done by using the GPU's dedicated shadowing |
||||||
|
* pipeline. |
||||||
|
*/ |
||||||
|
Hardware; |
||||||
|
} |
@ -0,0 +1,174 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2012 jMonkeyEngine |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions are |
||||||
|
* met: |
||||||
|
* |
||||||
|
* * Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* * Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||||
|
* may be used to endorse or promote products derived from this software |
||||||
|
* without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
package 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.light.DirectionalLight; |
||||||
|
import com.jme3.material.Material; |
||||||
|
import java.io.IOException; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* This Filter does basically the same as a DirectionalLightShadowRenderer |
||||||
|
* 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 DirectionalLightShadowFilter extends AbstractShadowFilter<DirectionalLightShadowRenderer> { |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a DirectionalLightShadowFilter Shadow Filter More info on the |
||||||
|
* technique at <a |
||||||
|
* href="http://http.developer.nvidia.com/GPUGems3/gpugems3_ch10.html">http://http.developer.nvidia.com/GPUGems3/gpugems3_ch10.html</a>
|
||||||
|
* |
||||||
|
* @param assetManager the application asset manager |
||||||
|
* @param shadowMapSize 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 DirectionalLightShadowFilter(AssetManager assetManager, int shadowMapSize, int nbSplits) { |
||||||
|
super(assetManager, shadowMapSize, new DirectionalLightShadowRenderer(assetManager, shadowMapSize, nbSplits)); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* return the light used to cast shadows |
||||||
|
* |
||||||
|
* @return the DirectionalLight |
||||||
|
*/ |
||||||
|
public DirectionalLight getLight() { |
||||||
|
return shadowRenderer.getLight(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the light to use to cast shadows |
||||||
|
* |
||||||
|
* @param light a DirectionalLight |
||||||
|
*/ |
||||||
|
public void setLight(DirectionalLight light) { |
||||||
|
shadowRenderer.setLight(light); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* returns the labda parameter |
||||||
|
* |
||||||
|
* @see #setLambda(float lambda) |
||||||
|
* @return lambda |
||||||
|
*/ |
||||||
|
public float getLambda() { |
||||||
|
return shadowRenderer.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) { |
||||||
|
shadowRenderer.setLambda(lambda); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* How far the shadows are rendered in the view |
||||||
|
* |
||||||
|
* @see setShadowZExtend(float zFar) |
||||||
|
* @return shadowZExtend |
||||||
|
*/ |
||||||
|
public float getShadowZExtend() { |
||||||
|
return shadowRenderer.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) { |
||||||
|
shadowRenderer.setShadowZExtend(zFar); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Define the length over which the shadow will fade out when using a |
||||||
|
* shadowZextend |
||||||
|
* |
||||||
|
* @param length the fade length in world units |
||||||
|
*/ |
||||||
|
public void setShadowZFadeLength(float length) { |
||||||
|
shadowRenderer.setShadowZFadeLength(length); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* get the length over which the shadow will fade out when using a |
||||||
|
* shadowZextend |
||||||
|
* |
||||||
|
* @return the fade length in world units |
||||||
|
*/ |
||||||
|
public float getShadowZFadeLength() { |
||||||
|
return shadowRenderer.getShadowZFadeLength(); |
||||||
|
} |
||||||
|
|
||||||
|
@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); |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,257 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2012 jMonkeyEngine |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions are |
||||||
|
* met: |
||||||
|
* |
||||||
|
* * Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* * Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||||
|
* may be used to endorse or promote products derived from this software |
||||||
|
* without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
package com.jme3.shadow; |
||||||
|
|
||||||
|
import com.jme3.asset.AssetManager; |
||||||
|
import com.jme3.light.DirectionalLight; |
||||||
|
import com.jme3.material.Material; |
||||||
|
import com.jme3.math.ColorRGBA; |
||||||
|
import com.jme3.math.Vector2f; |
||||||
|
import com.jme3.math.Vector3f; |
||||||
|
import com.jme3.renderer.Camera; |
||||||
|
import com.jme3.renderer.queue.GeometryList; |
||||||
|
import com.jme3.renderer.queue.OpaqueComparator; |
||||||
|
import com.jme3.scene.Node; |
||||||
|
|
||||||
|
/** |
||||||
|
* DirectionalLightShadowRenderer renderer use Parrallel Split Shadow Mapping |
||||||
|
* technique (pssm)<br> It splits the view frustum in several parts and compute |
||||||
|
* a shadow map for each one.<br> splits are distributed so that the closer they |
||||||
|
* are from the camera, the smaller they are to maximize the resolution used of |
||||||
|
* the shadow map.<br> This result in a better quality shadow than standard |
||||||
|
* shadow mapping.<br> for more informations on this read this <a |
||||||
|
* href="http://http.developer.nvidia.com/GPUGems3/gpugems3_ch10.html">http://http.developer.nvidia.com/GPUGems3/gpugems3_ch10.html</a><br>
|
||||||
|
* <p/> |
||||||
|
* @author Rémy Bouquet aka Nehon |
||||||
|
*/ |
||||||
|
public class DirectionalLightShadowRenderer extends AbstractShadowRenderer { |
||||||
|
|
||||||
|
protected float lambda = 0.65f; |
||||||
|
protected float zFarOverride = 0; |
||||||
|
protected Camera shadowCam; |
||||||
|
protected ColorRGBA splits; |
||||||
|
protected GeometryList splitOccluders = new GeometryList(new OpaqueComparator()); |
||||||
|
protected float[] splitsArray; |
||||||
|
protected DirectionalLight light; |
||||||
|
protected Vector3f[] points = new Vector3f[8]; |
||||||
|
//Holding the info for fading shadows in the far distance
|
||||||
|
protected Vector2f fadeInfo; |
||||||
|
protected float fadeLength; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Create a DirectionalLightShadowRenderer More info on the technique at <a |
||||||
|
* href="http://http.developer.nvidia.com/GPUGems3/gpugems3_ch10.html">http://http.developer.nvidia.com/GPUGems3/gpugems3_ch10.html</a>
|
||||||
|
* |
||||||
|
* @param assetManager the application asset manager |
||||||
|
* @param shadowMapSize 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 DirectionalLightShadowRenderer(AssetManager assetManager, int shadowMapSize, int nbSplits) { |
||||||
|
super(assetManager, shadowMapSize, nbSplits); |
||||||
|
|
||||||
|
nbShadowMaps = Math.max(Math.min(nbSplits, 4), 1); |
||||||
|
splits = new ColorRGBA(); |
||||||
|
splitsArray = new float[nbSplits + 1]; |
||||||
|
shadowCam = new Camera(shadowMapSize, shadowMapSize); |
||||||
|
shadowCam.setParallelProjection(true); |
||||||
|
|
||||||
|
for (int i = 0; i < points.length; i++) { |
||||||
|
points[i] = new Vector3f(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* return the light used to cast shadows |
||||||
|
* |
||||||
|
* @return the DirectionalLight |
||||||
|
*/ |
||||||
|
public DirectionalLight getLight() { |
||||||
|
return light; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the light to use to cast shadows |
||||||
|
* |
||||||
|
* @param light a DirectionalLight |
||||||
|
*/ |
||||||
|
public void setLight(DirectionalLight light) { |
||||||
|
this.light = light; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void updateShadowCams(Camera viewCam) { |
||||||
|
|
||||||
|
float zFar = zFarOverride; |
||||||
|
if (zFar == 0) { |
||||||
|
zFar = viewCam.getFrustumFar(); |
||||||
|
} |
||||||
|
|
||||||
|
//We prevent computing the frustum points and splits with zeroed or negative near clip value
|
||||||
|
float frustumNear = Math.max(viewCam.getFrustumNear(), 0.001f); |
||||||
|
ShadowUtil.updateFrustumPoints(viewCam, frustumNear, zFar, 1.0f, points); |
||||||
|
|
||||||
|
//shadowCam.setDirection(direction);
|
||||||
|
shadowCam.getRotation().lookAt(light.getDirection(), shadowCam.getUp()); |
||||||
|
shadowCam.update(); |
||||||
|
shadowCam.updateViewProjection(); |
||||||
|
|
||||||
|
PssmShadowUtil.updateFrustumSplits(splitsArray, frustumNear, zFar, lambda); |
||||||
|
|
||||||
|
|
||||||
|
switch (splitsArray.length) { |
||||||
|
case 5: |
||||||
|
splits.a = splitsArray[4]; |
||||||
|
case 4: |
||||||
|
splits.b = splitsArray[3]; |
||||||
|
case 3: |
||||||
|
splits.g = splitsArray[2]; |
||||||
|
case 2: |
||||||
|
case 1: |
||||||
|
splits.r = splitsArray[1]; |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected GeometryList getOccludersToRender(int shadowMapIndex, GeometryList sceneOccluders, GeometryList sceneReceivers) { |
||||||
|
|
||||||
|
// update frustum points based on current camera and split
|
||||||
|
ShadowUtil.updateFrustumPoints(viewPort.getCamera(), splitsArray[shadowMapIndex], splitsArray[shadowMapIndex + 1], 1.0f, points); |
||||||
|
|
||||||
|
//Updating shadow cam with curent split frustra
|
||||||
|
ShadowUtil.updateShadowCamera(sceneOccluders, sceneReceivers, shadowCam, points, splitOccluders); |
||||||
|
|
||||||
|
return splitOccluders; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected Camera getShadowCam(int shadowMapIndex) { |
||||||
|
return shadowCam; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void doDisplayFrustumDebug(int shadowMapIndex) { |
||||||
|
((Node) viewPort.getScenes().get(0)).attachChild(createFrustum(points, shadowMapIndex)); |
||||||
|
ShadowUtil.updateFrustumPoints2(shadowCam, points); |
||||||
|
((Node) viewPort.getScenes().get(0)).attachChild(createFrustum(points, shadowMapIndex)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void setMaterialParameters(Material material) { |
||||||
|
material.setColor("Splits", splits); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* returns the labda parameter see #setLambda(float lambda) |
||||||
|
* |
||||||
|
* @return lambda |
||||||
|
*/ |
||||||
|
public float getLambda() { |
||||||
|
return lambda; |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* 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) { |
||||||
|
this.lambda = lambda; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* How far the shadows are rendered in the view |
||||||
|
* |
||||||
|
* @see #setShadowZExtend(float zFar) |
||||||
|
* @return shadowZExtend |
||||||
|
*/ |
||||||
|
public float getShadowZExtend() { |
||||||
|
return zFarOverride; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 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) { |
||||||
|
if (fadeInfo != null) { |
||||||
|
fadeInfo.set(zFar - fadeLength, 1f / fadeLength); |
||||||
|
} |
||||||
|
this.zFarOverride = zFar; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Define the length over which the shadow will fade out when using a |
||||||
|
* shadowZextend This is useful to make dynamic shadows fade into baked |
||||||
|
* shadows in the distance. |
||||||
|
* |
||||||
|
* @param length the fade length in world units |
||||||
|
*/ |
||||||
|
public void setShadowZFadeLength(float length) { |
||||||
|
if (length == 0) { |
||||||
|
fadeInfo = null; |
||||||
|
fadeLength = 0; |
||||||
|
postshadowMat.clearParam("FadeInfo"); |
||||||
|
} else { |
||||||
|
if (zFarOverride == 0) { |
||||||
|
fadeInfo = new Vector2f(0, 0); |
||||||
|
} else { |
||||||
|
fadeInfo = new Vector2f(zFarOverride - length, 1.0f / length); |
||||||
|
} |
||||||
|
fadeLength = length; |
||||||
|
postshadowMat.setVector2("FadeInfo", fadeInfo); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* get the length over which the shadow will fade out when using a |
||||||
|
* shadowZextend |
||||||
|
* |
||||||
|
* @return the fade length in world units |
||||||
|
*/ |
||||||
|
public float getShadowZFadeLength() { |
||||||
|
if (fadeInfo != null) { |
||||||
|
return zFarOverride - fadeInfo.x; |
||||||
|
} |
||||||
|
return 0f; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,143 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2012 jMonkeyEngine |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions are |
||||||
|
* met: |
||||||
|
* |
||||||
|
* * Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* * Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||||
|
* may be used to endorse or promote products derived from this software |
||||||
|
* without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
package 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.light.SpotLight; |
||||||
|
import java.io.IOException; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* This Filter does basically the same as a SpotLightShadowRenderer |
||||||
|
* 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 SpotLightShadowFilter extends AbstractShadowFilter<SpotLightShadowRenderer> { |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a SpotLight Shadow Filter |
||||||
|
* @param assetManager the application asset manager |
||||||
|
* @param shadowMapSize the size of the rendered shadowmaps (512,1024,2048, |
||||||
|
* etc...) |
||||||
|
* the more quality, the less fps). |
||||||
|
*/ |
||||||
|
public SpotLightShadowFilter(AssetManager assetManager, int shadowMapSize) { |
||||||
|
super(assetManager, shadowMapSize, new SpotLightShadowRenderer(assetManager, shadowMapSize)); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* return the light used to cast shadows |
||||||
|
* |
||||||
|
* @return the SpotLight |
||||||
|
*/ |
||||||
|
public SpotLight getLight() { |
||||||
|
return shadowRenderer.getLight(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the light to use to cast shadows |
||||||
|
* |
||||||
|
* @param light a SpotLight |
||||||
|
*/ |
||||||
|
public void setLight(SpotLight light) { |
||||||
|
shadowRenderer.setLight(light); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* How far the shadows are rendered in the view |
||||||
|
* |
||||||
|
* @see setShadowZExtend(float zFar) |
||||||
|
* @return shadowZExtend |
||||||
|
*/ |
||||||
|
public float getShadowZExtend() { |
||||||
|
return shadowRenderer.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) { |
||||||
|
shadowRenderer.setShadowZExtend(zFar); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Define the length over which the shadow will fade out when using a |
||||||
|
* shadowZextend |
||||||
|
* |
||||||
|
* @param length the fade length in world units |
||||||
|
*/ |
||||||
|
public void setShadowZFadeLength(float length) { |
||||||
|
shadowRenderer.setShadowZFadeLength(length); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* get the length over which the shadow will fade out when using a |
||||||
|
* shadowZextend |
||||||
|
* |
||||||
|
* @return the fade length in world units |
||||||
|
*/ |
||||||
|
public float getShadowZFadeLength() { |
||||||
|
return shadowRenderer.getShadowZFadeLength(); |
||||||
|
} |
||||||
|
|
||||||
|
@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); |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,211 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2012 jMonkeyEngine |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions are |
||||||
|
* met: |
||||||
|
* |
||||||
|
* * Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* * Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||||
|
* may be used to endorse or promote products derived from this software |
||||||
|
* without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
package com.jme3.shadow; |
||||||
|
|
||||||
|
import com.jme3.asset.AssetManager; |
||||||
|
import com.jme3.light.DirectionalLight; |
||||||
|
import com.jme3.light.SpotLight; |
||||||
|
import com.jme3.material.Material; |
||||||
|
import com.jme3.math.ColorRGBA; |
||||||
|
import com.jme3.math.FastMath; |
||||||
|
import com.jme3.math.Vector2f; |
||||||
|
import com.jme3.math.Vector3f; |
||||||
|
import com.jme3.math.Vector4f; |
||||||
|
import com.jme3.renderer.Camera; |
||||||
|
import com.jme3.renderer.queue.GeometryList; |
||||||
|
import com.jme3.renderer.queue.OpaqueComparator; |
||||||
|
import com.jme3.scene.Node; |
||||||
|
|
||||||
|
/** |
||||||
|
* SpotLightShadowRenderer renderer use Parrallel Split Shadow Mapping technique |
||||||
|
* (pssm)<br> It splits the view frustum in several parts and compute a shadow |
||||||
|
* map for each one.<br> splits are distributed so that the closer they are from |
||||||
|
* the camera, the smaller they are to maximize the resolution used of the |
||||||
|
* shadow map.<br> This result in a better quality shadow than standard shadow |
||||||
|
* mapping.<br> for more informations on this read this <a |
||||||
|
* href="http://http.developer.nvidia.com/GPUGems3/gpugems3_ch10.html">http://http.developer.nvidia.com/GPUGems3/gpugems3_ch10.html</a><br>
|
||||||
|
* <p/> |
||||||
|
* @author Rémy Bouquet aka Nehon |
||||||
|
*/ |
||||||
|
public class SpotLightShadowRenderer extends AbstractShadowRenderer { |
||||||
|
|
||||||
|
protected float zFarOverride = 0; |
||||||
|
protected Camera shadowCam; |
||||||
|
protected GeometryList mapOccluders = new GeometryList(new OpaqueComparator()); |
||||||
|
protected SpotLight light; |
||||||
|
protected Vector3f[] points = new Vector3f[8]; |
||||||
|
//Holding the info for fading shadows in the far distance
|
||||||
|
protected Vector2f fadeInfo; |
||||||
|
protected float fadeLength; |
||||||
|
|
||||||
|
/** |
||||||
|
* Create a SpotLightShadowRenderer This use standard shadow mapping |
||||||
|
* |
||||||
|
* @param assetManager the application asset manager |
||||||
|
* @param shadowMapSize the size of the rendered shadowmaps (512,1024,2048, |
||||||
|
* etc...) the more quality, the less fps). |
||||||
|
*/ |
||||||
|
public SpotLightShadowRenderer(AssetManager assetManager, int shadowMapSize) { |
||||||
|
super(assetManager, shadowMapSize, 1); |
||||||
|
|
||||||
|
shadowCam = new Camera(shadowMapSize, shadowMapSize); |
||||||
|
|
||||||
|
for (int i = 0; i < points.length; i++) { |
||||||
|
points[i] = new Vector3f(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* return the light used to cast shadows |
||||||
|
* |
||||||
|
* @return the SpotLight |
||||||
|
*/ |
||||||
|
public SpotLight getLight() { |
||||||
|
return light; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the light to use to cast shadows |
||||||
|
* |
||||||
|
* @param light a SpotLight |
||||||
|
*/ |
||||||
|
public void setLight(SpotLight light) { |
||||||
|
this.light = light; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void updateShadowCams(Camera viewCam) { |
||||||
|
|
||||||
|
float zFar = zFarOverride; |
||||||
|
if (zFar == 0) { |
||||||
|
zFar = viewCam.getFrustumFar(); |
||||||
|
} |
||||||
|
|
||||||
|
//We prevent computing the frustum points and splits with zeroed or negative near clip value
|
||||||
|
float frustumNear = Math.max(viewCam.getFrustumNear(), 0.001f); |
||||||
|
ShadowUtil.updateFrustumPoints(viewCam, frustumNear, zFar, 1.0f, points); |
||||||
|
//shadowCam.setDirection(direction);
|
||||||
|
|
||||||
|
shadowCam.setFrustumPerspective(light.getSpotOuterAngle() * FastMath.RAD_TO_DEG * 2.0f, 1, 1f, light.getSpotRange()); |
||||||
|
shadowCam.getRotation().lookAt(light.getDirection(), shadowCam.getUp()); |
||||||
|
shadowCam.setLocation(light.getPosition()); |
||||||
|
|
||||||
|
shadowCam.update(); |
||||||
|
shadowCam.updateViewProjection(); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected GeometryList getOccludersToRender(int shadowMapIndex, GeometryList sceneOccluders, GeometryList sceneReceivers) { |
||||||
|
ShadowUtil.getOccludersInCamFrustum(sceneOccluders, shadowCam, mapOccluders); |
||||||
|
return mapOccluders; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected Camera getShadowCam(int shadowMapIndex) { |
||||||
|
return shadowCam; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void doDisplayFrustumDebug(int shadowMapIndex) { |
||||||
|
Vector3f[] points2 = points.clone(); |
||||||
|
|
||||||
|
((Node) viewPort.getScenes().get(0)).attachChild(createFrustum(points, shadowMapIndex)); |
||||||
|
ShadowUtil.updateFrustumPoints2(shadowCam, points2); |
||||||
|
((Node) viewPort.getScenes().get(0)).attachChild(createFrustum(points2, shadowMapIndex)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void setMaterialParameters(Material material) { |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* How far the shadows are rendered in the view |
||||||
|
* |
||||||
|
* @see #setShadowZExtend(float zFar) |
||||||
|
* @return shadowZExtend |
||||||
|
*/ |
||||||
|
public float getShadowZExtend() { |
||||||
|
return zFarOverride; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 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) { |
||||||
|
if (fadeInfo != null) { |
||||||
|
fadeInfo.set(zFar - fadeLength, 1f / fadeLength); |
||||||
|
} |
||||||
|
this.zFarOverride = zFar; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Define the length over which the shadow will fade out when using a |
||||||
|
* shadowZextend This is useful to make dynamic shadows fade into baked |
||||||
|
* shadows in the distance. |
||||||
|
* |
||||||
|
* @param length the fade length in world units |
||||||
|
*/ |
||||||
|
public void setShadowZFadeLength(float length) { |
||||||
|
if (length == 0) { |
||||||
|
fadeInfo = null; |
||||||
|
fadeLength = 0; |
||||||
|
postshadowMat.clearParam("FadeInfo"); |
||||||
|
} else { |
||||||
|
if (zFarOverride == 0) { |
||||||
|
fadeInfo = new Vector2f(0, 0); |
||||||
|
} else { |
||||||
|
fadeInfo = new Vector2f(zFarOverride - length, 1.0f / length); |
||||||
|
} |
||||||
|
fadeLength = length; |
||||||
|
postshadowMat.setVector2("FadeInfo", fadeInfo); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* get the length over which the shadow will fade out when using a |
||||||
|
* shadowZextend |
||||||
|
* |
||||||
|
* @return the fade length in world units |
||||||
|
*/ |
||||||
|
public float getShadowZFadeLength() { |
||||||
|
if (fadeInfo != null) { |
||||||
|
return zFarOverride - fadeInfo.x; |
||||||
|
} |
||||||
|
return 0f; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,154 @@ |
|||||||
|
/* |
||||||
|
* To change this template, choose Tools | Templates |
||||||
|
* and open the template in the editor. |
||||||
|
*/ |
||||||
|
package jme3test.light; |
||||||
|
|
||||||
|
import com.jme3.asset.AssetManager; |
||||||
|
import com.jme3.font.BitmapFont; |
||||||
|
import com.jme3.font.BitmapText; |
||||||
|
import com.jme3.input.InputManager; |
||||||
|
import com.jme3.input.KeyInput; |
||||||
|
import com.jme3.input.controls.ActionListener; |
||||||
|
import com.jme3.input.controls.KeyTrigger; |
||||||
|
import com.jme3.renderer.Camera; |
||||||
|
import com.jme3.renderer.ViewPort; |
||||||
|
import com.jme3.scene.Node; |
||||||
|
import com.jme3.shadow.AbstractShadowFilter; |
||||||
|
import com.jme3.shadow.AbstractShadowRenderer; |
||||||
|
import com.jme3.shadow.CompareMode; |
||||||
|
import com.jme3.shadow.EdgeFilteringMode; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author Nehon |
||||||
|
*/ |
||||||
|
public class ShadowTestUIManager implements ActionListener { |
||||||
|
|
||||||
|
private BitmapText shadowTypeText; |
||||||
|
private BitmapText shadowCompareText; |
||||||
|
private BitmapText shadowFilterText; |
||||||
|
private BitmapText shadowIntensityText; |
||||||
|
private final static String TYPE_TEXT = "(Space) Shadow type : "; |
||||||
|
private final static String COMPARE_TEXT = "(enter) Shadow compare "; |
||||||
|
private final static String FILTERING_TEXT = "(f) Edge filtering : "; |
||||||
|
private final static String INTENSITY_TEXT = "(t:up, g:down) Shadow intensity : "; |
||||||
|
private boolean hardwareShadows = true; |
||||||
|
private AbstractShadowRenderer plsr; |
||||||
|
private AbstractShadowFilter plsf; |
||||||
|
private ViewPort viewPort; |
||||||
|
private int filteringIndex = 0; |
||||||
|
private int renderModeIndex = 0; |
||||||
|
|
||||||
|
|
||||||
|
public ShadowTestUIManager(AssetManager assetManager,AbstractShadowRenderer plsr, AbstractShadowFilter plsf, |
||||||
|
Node guiNode, InputManager inputManager, ViewPort viewPort) { |
||||||
|
this.plsr = plsr; |
||||||
|
this.plsf = plsf; |
||||||
|
this.viewPort = viewPort; |
||||||
|
BitmapFont guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt"); |
||||||
|
shadowTypeText = createText(guiFont); |
||||||
|
shadowCompareText = createText(guiFont); |
||||||
|
shadowFilterText = createText(guiFont); |
||||||
|
shadowIntensityText = createText(guiFont); |
||||||
|
|
||||||
|
shadowTypeText.setText(TYPE_TEXT + "Processor"); |
||||||
|
shadowCompareText.setText(COMPARE_TEXT + (hardwareShadows ? "Hardware" : "Software")); |
||||||
|
shadowFilterText.setText(FILTERING_TEXT + plsr.getEdgeFilteringMode().toString()); |
||||||
|
shadowIntensityText.setText(INTENSITY_TEXT + plsr.getShadowIntensity()); |
||||||
|
|
||||||
|
shadowTypeText.setLocalTranslation(10, viewPort.getCamera().getHeight() - 20, 0); |
||||||
|
shadowCompareText.setLocalTranslation(10, viewPort.getCamera().getHeight() - 40, 0); |
||||||
|
shadowFilterText.setLocalTranslation(10, viewPort.getCamera().getHeight() - 60, 0); |
||||||
|
shadowIntensityText.setLocalTranslation(10, viewPort.getCamera().getHeight() - 80, 0); |
||||||
|
|
||||||
|
guiNode.attachChild(shadowTypeText); |
||||||
|
guiNode.attachChild(shadowCompareText); |
||||||
|
guiNode.attachChild(shadowFilterText); |
||||||
|
guiNode.attachChild(shadowIntensityText); |
||||||
|
|
||||||
|
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)); |
||||||
|
inputManager.addMapping("ThicknessDown", new KeyTrigger(KeyInput.KEY_H)); |
||||||
|
inputManager.addMapping("toggleHW", new KeyTrigger(KeyInput.KEY_RETURN)); |
||||||
|
|
||||||
|
|
||||||
|
inputManager.addListener(this, "toggleHW", "toggle", "ShadowUp", "ShadowDown", "ThicknessUp", "ThicknessDown", "changeFiltering"); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public void onAction(String name, boolean keyPressed, float tpf) { |
||||||
|
if (name.equals("toggle") && keyPressed) { |
||||||
|
renderModeIndex += 1; |
||||||
|
renderModeIndex %= 3; |
||||||
|
|
||||||
|
switch (renderModeIndex) { |
||||||
|
case 0: |
||||||
|
viewPort.addProcessor(plsr); |
||||||
|
shadowTypeText.setText(TYPE_TEXT + "Processor"); |
||||||
|
break; |
||||||
|
case 1: |
||||||
|
viewPort.removeProcessor(plsr); |
||||||
|
plsf.setEnabled(true); |
||||||
|
shadowTypeText.setText(TYPE_TEXT + "Filter"); |
||||||
|
break; |
||||||
|
case 2: |
||||||
|
plsf.setEnabled(false); |
||||||
|
shadowTypeText.setText(TYPE_TEXT + "None"); |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} else if (name.equals("toggleHW") && keyPressed) { |
||||||
|
hardwareShadows = !hardwareShadows; |
||||||
|
plsr.setShadowCompareMode(hardwareShadows ? CompareMode.Hardware : CompareMode.Software); |
||||||
|
plsf.setShadowCompareMode(hardwareShadows ? CompareMode.Hardware : CompareMode.Software); |
||||||
|
|
||||||
|
shadowCompareText.setText(COMPARE_TEXT + (hardwareShadows ? "Hardware" : "Software")); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
if (name.equals("changeFiltering") && keyPressed) { |
||||||
|
filteringIndex = plsr.getEdgeFilteringMode().ordinal(); |
||||||
|
filteringIndex = (filteringIndex + 1) % EdgeFilteringMode.values().length; |
||||||
|
EdgeFilteringMode m = EdgeFilteringMode.values()[filteringIndex]; |
||||||
|
plsr.setEdgeFilteringMode(m); |
||||||
|
plsf.setEdgeFilteringMode(m); |
||||||
|
shadowFilterText.setText(FILTERING_TEXT + m.toString()); |
||||||
|
} |
||||||
|
|
||||||
|
if (name.equals("ShadowUp") && keyPressed) { |
||||||
|
plsr.setShadowIntensity(plsr.getShadowIntensity() + 0.1f); |
||||||
|
plsf.setShadowIntensity(plsf.getShadowIntensity() + 0.1f); |
||||||
|
|
||||||
|
shadowIntensityText.setText(INTENSITY_TEXT + plsr.getShadowIntensity()); |
||||||
|
} |
||||||
|
if (name.equals("ShadowDown") && keyPressed) { |
||||||
|
plsr.setShadowIntensity(plsr.getShadowIntensity() - 0.1f); |
||||||
|
plsf.setShadowIntensity(plsf.getShadowIntensity() - 0.1f); |
||||||
|
shadowIntensityText.setText(INTENSITY_TEXT + plsr.getShadowIntensity()); |
||||||
|
} |
||||||
|
if (name.equals("ThicknessUp") && keyPressed) { |
||||||
|
plsr.setEdgesThickness(plsr.getEdgesThickness() + 1); |
||||||
|
plsf.setEdgesThickness(plsf.getEdgesThickness() + 1); |
||||||
|
System.out.println("Shadow thickness : " + plsr.getEdgesThickness()); |
||||||
|
} |
||||||
|
if (name.equals("ThicknessDown") && keyPressed) { |
||||||
|
plsr.setEdgesThickness(plsr.getEdgesThickness() - 1); |
||||||
|
plsf.setEdgesThickness(plsf.getEdgesThickness() - 1); |
||||||
|
System.out.println("Shadow thickness : " + plsr.getEdgesThickness()); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
private BitmapText createText(BitmapFont guiFont) { |
||||||
|
BitmapText t = new BitmapText(guiFont, false); |
||||||
|
t.setSize(guiFont.getCharSet().getRenderedSize() * 0.75f); |
||||||
|
return t; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,311 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2012 jMonkeyEngine |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions are |
||||||
|
* met: |
||||||
|
* |
||||||
|
* * Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* * Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||||
|
* may be used to endorse or promote products derived from this software |
||||||
|
* without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
package jme3test.light; |
||||||
|
|
||||||
|
import com.jme3.app.SimpleApplication; |
||||||
|
import com.jme3.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.post.FilterPostProcessor; |
||||||
|
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.CompareMode; |
||||||
|
import com.jme3.shadow.DirectionalLightShadowFilter; |
||||||
|
import com.jme3.shadow.DirectionalLightShadowRenderer; |
||||||
|
import com.jme3.shadow.EdgeFilteringMode; |
||||||
|
import com.jme3.shadow.PssmShadowRenderer.FilterMode; |
||||||
|
import com.jme3.texture.Texture; |
||||||
|
import com.jme3.texture.Texture.WrapMode; |
||||||
|
import com.jme3.util.SkyFactory; |
||||||
|
import com.jme3.util.TangentBinormalGenerator; |
||||||
|
|
||||||
|
public class TestDirectionalLightShadow extends SimpleApplication implements ActionListener { |
||||||
|
|
||||||
|
private Spatial[] obj; |
||||||
|
private Material[] mat; |
||||||
|
private boolean hardwareShadows = false; |
||||||
|
private DirectionalLightShadowRenderer dlsr; |
||||||
|
private DirectionalLightShadowFilter dlsf; |
||||||
|
private Geometry ground; |
||||||
|
private Material matGroundU; |
||||||
|
private Material matGroundL; |
||||||
|
|
||||||
|
public static void main(String[] args) { |
||||||
|
TestDirectionalLightShadow app = new TestDirectionalLightShadow(); |
||||||
|
app.start(); |
||||||
|
} |
||||||
|
|
||||||
|
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()); |
||||||
|
|
||||||
|
|
||||||
|
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]); |
||||||
|
|
||||||
|
|
||||||
|
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); |
||||||
|
t.setLocalTranslation(FastMath.nextRandomFloat() * 200f, FastMath.nextRandomFloat() * 30f + 20, 30f * (i + 2f)); |
||||||
|
} |
||||||
|
|
||||||
|
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); |
||||||
|
|
||||||
|
l = new DirectionalLight(); |
||||||
|
//new Vector3f(-0.5973172f, -0.56583486f, 0.8846725f).normalizeLocal()
|
||||||
|
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); |
||||||
|
} |
||||||
|
DirectionalLight l; |
||||||
|
|
||||||
|
@Override |
||||||
|
public void simpleInitApp() { |
||||||
|
// put the camera in a bad position
|
||||||
|
cam.setLocation(new Vector3f(65.25412f, 44.38738f, 9.087874f)); |
||||||
|
cam.setRotation(new Quaternion(0.078139365f, 0.050241485f, -0.003942559f, 0.9956679f)); |
||||||
|
|
||||||
|
flyCam.setMoveSpeed(100); |
||||||
|
|
||||||
|
loadScene(); |
||||||
|
|
||||||
|
dlsr = new DirectionalLightShadowRenderer(assetManager, 1024, 3); |
||||||
|
dlsr.setLight(l); |
||||||
|
dlsr.setLambda(0.55f); |
||||||
|
dlsr.setShadowIntensity(0.6f); |
||||||
|
dlsr.setEdgeFilteringMode(EdgeFilteringMode.Nearest); |
||||||
|
//dlsr.displayFrustum();
|
||||||
|
viewPort.addProcessor(dlsr); |
||||||
|
|
||||||
|
dlsf = new DirectionalLightShadowFilter(assetManager, 1024, 3); |
||||||
|
dlsf.setLight(l); |
||||||
|
dlsf.setLambda(0.55f); |
||||||
|
dlsf.setShadowIntensity(0.6f); |
||||||
|
dlsf.setEdgeFilteringMode(EdgeFilteringMode.Nearest); |
||||||
|
dlsf.setEnabled(false); |
||||||
|
|
||||||
|
FilterPostProcessor fpp = new FilterPostProcessor(assetManager); |
||||||
|
fpp.addFilter(dlsf); |
||||||
|
|
||||||
|
viewPort.addProcessor(fpp); |
||||||
|
|
||||||
|
initInputs(); |
||||||
|
} |
||||||
|
|
||||||
|
private void initInputs() { |
||||||
|
|
||||||
|
inputManager.addMapping("ThicknessUp", new KeyTrigger(KeyInput.KEY_Y)); |
||||||
|
inputManager.addMapping("ThicknessDown", new KeyTrigger(KeyInput.KEY_H)); |
||||||
|
inputManager.addMapping("lambdaUp", new KeyTrigger(KeyInput.KEY_U)); |
||||||
|
inputManager.addMapping("lambdaDown", new KeyTrigger(KeyInput.KEY_J)); |
||||||
|
inputManager.addMapping("switchGroundMat", new KeyTrigger(KeyInput.KEY_M)); |
||||||
|
inputManager.addMapping("splits", new KeyTrigger(KeyInput.KEY_X)); |
||||||
|
|
||||||
|
inputManager.addMapping("up", new KeyTrigger(KeyInput.KEY_NUMPAD8)); |
||||||
|
inputManager.addMapping("down", new KeyTrigger(KeyInput.KEY_NUMPAD2)); |
||||||
|
inputManager.addMapping("right", new KeyTrigger(KeyInput.KEY_NUMPAD6)); |
||||||
|
inputManager.addMapping("left", new KeyTrigger(KeyInput.KEY_NUMPAD4)); |
||||||
|
inputManager.addMapping("fwd", new KeyTrigger(KeyInput.KEY_PGUP)); |
||||||
|
inputManager.addMapping("back", new KeyTrigger(KeyInput.KEY_PGDN)); |
||||||
|
|
||||||
|
|
||||||
|
inputManager.addListener(this, "lambdaUp", "lambdaDown", "ThicknessUp", "ThicknessDown", |
||||||
|
"switchGroundMat", "splits", "up", "down", "right", "left", "fwd", "back"); |
||||||
|
|
||||||
|
ShadowTestUIManager uiMan = new ShadowTestUIManager(assetManager, dlsr, dlsf, guiNode, inputManager, viewPort); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public void onAction(String name, boolean keyPressed, float tpf) { |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (name.equals("lambdaUp") && keyPressed) { |
||||||
|
dlsr.setLambda(dlsr.getLambda() + 0.01f); |
||||||
|
dlsf.setLambda(dlsr.getLambda() + 0.01f); |
||||||
|
System.out.println("Lambda : " + dlsr.getLambda()); |
||||||
|
} else if (name.equals("lambdaDown") && keyPressed) { |
||||||
|
dlsr.setLambda(dlsr.getLambda() - 0.01f); |
||||||
|
dlsf.setLambda(dlsr.getLambda() - 0.01f); |
||||||
|
System.out.println("Lambda : " + dlsr.getLambda()); |
||||||
|
} |
||||||
|
|
||||||
|
if (name.equals("ShadowUp") && keyPressed) { |
||||||
|
dlsr.setShadowIntensity(dlsr.getShadowIntensity() + 0.1f); |
||||||
|
dlsf.setShadowIntensity(dlsr.getShadowIntensity() + 0.1f); |
||||||
|
System.out.println("Shadow intensity : " + dlsr.getShadowIntensity()); |
||||||
|
} |
||||||
|
if (name.equals("ShadowDown") && keyPressed) { |
||||||
|
dlsr.setShadowIntensity(dlsr.getShadowIntensity() - 0.1f); |
||||||
|
dlsf.setShadowIntensity(dlsr.getShadowIntensity() - 0.1f); |
||||||
|
System.out.println("Shadow intensity : " + dlsr.getShadowIntensity()); |
||||||
|
} |
||||||
|
if (name.equals("ThicknessUp") && keyPressed) { |
||||||
|
dlsr.setEdgesThickness(dlsr.getEdgesThickness() + 1); |
||||||
|
dlsf.setEdgesThickness(dlsr.getEdgesThickness() + 1); |
||||||
|
System.out.println("Shadow thickness : " + dlsr.getEdgesThickness()); |
||||||
|
} |
||||||
|
if (name.equals("ThicknessDown") && keyPressed) { |
||||||
|
dlsr.setEdgesThickness(dlsr.getEdgesThickness() - 1); |
||||||
|
dlsf.setEdgesThickness(dlsr.getEdgesThickness() - 1); |
||||||
|
System.out.println("Shadow thickness : " + dlsr.getEdgesThickness()); |
||||||
|
} |
||||||
|
if (name.equals("switchGroundMat") && keyPressed) { |
||||||
|
if (ground.getMaterial() == matGroundL) { |
||||||
|
ground.setMaterial(matGroundU); |
||||||
|
} else { |
||||||
|
ground.setMaterial(matGroundL); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (name.equals("up")) { |
||||||
|
up = keyPressed; |
||||||
|
} |
||||||
|
if (name.equals("down")) { |
||||||
|
down = keyPressed; |
||||||
|
} |
||||||
|
if (name.equals("right")) { |
||||||
|
right = keyPressed; |
||||||
|
} |
||||||
|
if (name.equals("left")) { |
||||||
|
left = keyPressed; |
||||||
|
} |
||||||
|
if (name.equals("fwd")) { |
||||||
|
fwd = keyPressed; |
||||||
|
} |
||||||
|
if (name.equals("back")) { |
||||||
|
back = keyPressed; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
boolean up = false; |
||||||
|
boolean down = false; |
||||||
|
boolean left = false; |
||||||
|
boolean right = false; |
||||||
|
boolean fwd = false; |
||||||
|
boolean back = false; |
||||||
|
float time = 0; |
||||||
|
float s = 1f; |
||||||
|
|
||||||
|
@Override |
||||||
|
public void simpleUpdate(float tpf) { |
||||||
|
if (up) { |
||||||
|
Vector3f v = l.getDirection(); |
||||||
|
v.y += tpf / s; |
||||||
|
setDir(v); |
||||||
|
} |
||||||
|
if (down) { |
||||||
|
Vector3f v = l.getDirection(); |
||||||
|
v.y -= tpf / s; |
||||||
|
setDir(v); |
||||||
|
} |
||||||
|
if (right) { |
||||||
|
Vector3f v = l.getDirection(); |
||||||
|
v.x += tpf / s; |
||||||
|
setDir(v); |
||||||
|
} |
||||||
|
if (left) { |
||||||
|
Vector3f v = l.getDirection(); |
||||||
|
v.x -= tpf / s; |
||||||
|
setDir(v); |
||||||
|
} |
||||||
|
if (fwd) { |
||||||
|
Vector3f v = l.getDirection(); |
||||||
|
v.z += tpf / s; |
||||||
|
setDir(v); |
||||||
|
} |
||||||
|
if (back) { |
||||||
|
Vector3f v = l.getDirection(); |
||||||
|
v.z -= tpf / s; |
||||||
|
setDir(v); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
private void setDir(Vector3f v) { |
||||||
|
l.setDirection(v); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,198 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2012 jMonkeyEngine |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions are |
||||||
|
* met: |
||||||
|
* |
||||||
|
* * Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* * Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||||
|
* may be used to endorse or promote products derived from this software |
||||||
|
* without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
package jme3test.light; |
||||||
|
|
||||||
|
import com.jme3.app.SimpleApplication; |
||||||
|
import com.jme3.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.SpotLight; |
||||||
|
import com.jme3.material.Material; |
||||||
|
import com.jme3.math.*; |
||||||
|
import com.jme3.post.FilterPostProcessor; |
||||||
|
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.shader.VarType; |
||||||
|
import com.jme3.shadow.CompareMode; |
||||||
|
import com.jme3.shadow.EdgeFilteringMode; |
||||||
|
import com.jme3.shadow.SpotLightShadowFilter; |
||||||
|
import com.jme3.shadow.SpotLightShadowRenderer; |
||||||
|
import com.jme3.texture.Texture.WrapMode; |
||||||
|
import com.jme3.util.TangentBinormalGenerator; |
||||||
|
|
||||||
|
public class TestSpotLightShadows extends SimpleApplication { |
||||||
|
|
||||||
|
private Vector3f lightTarget = new Vector3f(12, 3.5f, 30); |
||||||
|
|
||||||
|
public static void main(String[] args) { |
||||||
|
TestSpotLightShadows app = new TestSpotLightShadows(); |
||||||
|
app.start(); |
||||||
|
} |
||||||
|
SpotLight spot; |
||||||
|
Geometry lightMdl; |
||||||
|
|
||||||
|
public void setupLighting() { |
||||||
|
AmbientLight al = new AmbientLight(); |
||||||
|
al.setColor(ColorRGBA.White.mult(0.3f)); |
||||||
|
rootNode.addLight(al); |
||||||
|
|
||||||
|
rootNode.setShadowMode(ShadowMode.CastAndReceive); |
||||||
|
|
||||||
|
spot = new SpotLight(); |
||||||
|
|
||||||
|
spot.setSpotRange(1000); |
||||||
|
spot.setSpotInnerAngle(5f * FastMath.DEG_TO_RAD); |
||||||
|
spot.setSpotOuterAngle(10 * FastMath.DEG_TO_RAD); |
||||||
|
spot.setPosition(new Vector3f(70.70334f, 34.013165f, 27.1017f)); |
||||||
|
spot.setDirection(lightTarget.subtract(spot.getPosition())); |
||||||
|
spot.setColor(ColorRGBA.White.mult(2)); |
||||||
|
rootNode.addLight(spot); |
||||||
|
|
||||||
|
|
||||||
|
// PointLight pl=new PointLight();
|
||||||
|
// pl.setPosition(new Vector3f(77.70334f, 34.013165f, 27.1017f));
|
||||||
|
// pl.setRadius(1000);
|
||||||
|
// pl.setColor(ColorRGBA.White.mult(2));
|
||||||
|
// rootNode.addLight(pl);
|
||||||
|
lightMdl = new Geometry("Light", new Sphere(10, 10, 0.1f)); |
||||||
|
lightMdl.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m")); |
||||||
|
lightMdl.setLocalTranslation(new Vector3f(77.70334f, 34.013165f, 27.1017f)); |
||||||
|
lightMdl.setLocalScale(5); |
||||||
|
rootNode.attachChild(lightMdl); |
||||||
|
|
||||||
|
// DirectionalLight dl = new DirectionalLight();
|
||||||
|
// dl.setDirection(lightTarget.subtract(new Vector3f(77.70334f, 34.013165f, 27.1017f)));
|
||||||
|
// dl.setColor(ColorRGBA.White.mult(0.7f));
|
||||||
|
// rootNode.addLight(dl);
|
||||||
|
|
||||||
|
|
||||||
|
final SpotLightShadowRenderer slsr = new SpotLightShadowRenderer(assetManager, 512); |
||||||
|
slsr.setLight(spot); |
||||||
|
slsr.setShadowIntensity(0.5f); |
||||||
|
slsr.setEdgeFilteringMode(EdgeFilteringMode.PCFPOISSON); |
||||||
|
viewPort.addProcessor(slsr); |
||||||
|
|
||||||
|
SpotLightShadowFilter slsf = new SpotLightShadowFilter(assetManager, 512); |
||||||
|
slsf.setLight(spot); |
||||||
|
slsf.setShadowIntensity(0.5f); |
||||||
|
slsf.setEdgeFilteringMode(EdgeFilteringMode.PCFPOISSON); |
||||||
|
slsf.setEnabled(false); |
||||||
|
|
||||||
|
FilterPostProcessor fpp = new FilterPostProcessor(assetManager); |
||||||
|
fpp.addFilter(slsf); |
||||||
|
viewPort.addProcessor(fpp); |
||||||
|
|
||||||
|
ShadowTestUIManager uiMan = new ShadowTestUIManager(assetManager, slsr, slsf, guiNode, inputManager, viewPort); |
||||||
|
|
||||||
|
inputManager.addListener(new ActionListener() { |
||||||
|
public void onAction(String name, boolean isPressed, float tpf) { |
||||||
|
if (name.equals("stop") && isPressed) { |
||||||
|
stop = !stop; |
||||||
|
// slsr.displayFrustum();
|
||||||
|
System.out.println("pos : " + spot.getPosition()); |
||||||
|
System.out.println("dir : " + spot.getDirection()); |
||||||
|
} |
||||||
|
} |
||||||
|
}, "stop"); |
||||||
|
|
||||||
|
inputManager.addMapping("stop", new KeyTrigger(KeyInput.KEY_1)); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void setupFloor() { |
||||||
|
Material mat = assetManager.loadMaterial("Textures/Terrain/Pond/Pond.j3m"); |
||||||
|
mat.getTextureParam("DiffuseMap").getTextureValue().setWrap(WrapMode.Repeat); |
||||||
|
mat.getTextureParam("NormalMap").getTextureValue().setWrap(WrapMode.Repeat); |
||||||
|
mat.setBoolean("UseMaterialColors", true); |
||||||
|
mat.setColor("Diffuse", ColorRGBA.White.clone()); |
||||||
|
mat.setColor("Ambient", ColorRGBA.White.clone()); |
||||||
|
// mat.setColor("Specular", ColorRGBA.White.clone());
|
||||||
|
// mat.getTextureParam("ParallaxMap").getTextureValue().setWrap(WrapMode.Repeat);
|
||||||
|
mat.setFloat("Shininess", 0); |
||||||
|
// mat.setBoolean("VertexLighting", true);
|
||||||
|
|
||||||
|
|
||||||
|
Box floor = new Box(Vector3f.ZERO, 50, 1f, 50); |
||||||
|
TangentBinormalGenerator.generate(floor); |
||||||
|
floor.scaleTextureCoordinates(new Vector2f(5, 5)); |
||||||
|
Geometry floorGeom = new Geometry("Floor", floor); |
||||||
|
floorGeom.setMaterial(mat); |
||||||
|
floorGeom.setShadowMode(ShadowMode.Receive); |
||||||
|
rootNode.attachChild(floorGeom); |
||||||
|
} |
||||||
|
|
||||||
|
public void setupSignpost() { |
||||||
|
Spatial signpost = assetManager.loadModel("Models/Sign Post/Sign Post.mesh.xml"); |
||||||
|
Material mat = assetManager.loadMaterial("Models/Sign Post/Sign Post.j3m"); |
||||||
|
// mat.setBoolean("VertexLighting", true);
|
||||||
|
signpost.setMaterial(mat); |
||||||
|
signpost.rotate(0, FastMath.HALF_PI, 0); |
||||||
|
signpost.setLocalTranslation(12, 3.5f, 30); |
||||||
|
signpost.setLocalScale(4); |
||||||
|
signpost.setShadowMode(ShadowMode.CastAndReceive); |
||||||
|
TangentBinormalGenerator.generate(signpost); |
||||||
|
rootNode.attachChild(signpost); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void simpleInitApp() { |
||||||
|
cam.setLocation(new Vector3f(27.492603f, 29.138166f, -13.232513f)); |
||||||
|
cam.setRotation(new Quaternion(0.25168246f, -0.10547892f, 0.02760565f, 0.96164864f)); |
||||||
|
flyCam.setMoveSpeed(30); |
||||||
|
|
||||||
|
setupLighting(); |
||||||
|
setupFloor(); |
||||||
|
setupSignpost(); |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
float angle; |
||||||
|
boolean stop = true; |
||||||
|
|
||||||
|
@Override |
||||||
|
public void simpleUpdate(float tpf) { |
||||||
|
if (!stop) { |
||||||
|
super.simpleUpdate(tpf); |
||||||
|
angle += tpf; |
||||||
|
angle %= FastMath.TWO_PI; |
||||||
|
|
||||||
|
spot.setPosition(new Vector3f(FastMath.cos(angle) * 30f, 34.013165f, FastMath.sin(angle) * 30f)); |
||||||
|
lightMdl.setLocalTranslation(spot.getPosition()); |
||||||
|
spot.setDirection(lightTarget.subtract(spot.getPosition())); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue