Shadows : There is now an alternative to the PssmRenderer : the PssmFilter that has to be used as any other filter. It does the same ass the PssmRenderer except the post shadow pass is done in screen space making it run very faster on scene that have a lot of shadow recieving Geometries.
git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9787 75d07b2b-3a1a-0410-a2c5-0572b91ccdca3.0
parent
f0d4f86dd8
commit
cbafa1852b
@ -0,0 +1,68 @@ |
||||
#import "Common/ShaderLib/PssmShadows.glsllib" |
||||
|
||||
uniform sampler2D m_Texture; |
||||
uniform sampler2D m_DepthTexture; |
||||
uniform mat4 m_ViewProjectionMatrixInverse; |
||||
uniform vec4 m_ViewProjectionMatrixRow2; |
||||
|
||||
varying vec2 texCoord; |
||||
|
||||
|
||||
const mat4 biasMat = mat4(0.5, 0.0, 0.0, 0.0, |
||||
0.0, 0.5, 0.0, 0.0, |
||||
0.0, 0.0, 0.5, 0.0, |
||||
0.5, 0.5, 0.5, 1.0); |
||||
|
||||
uniform mat4 m_LightViewProjectionMatrix0; |
||||
uniform mat4 m_LightViewProjectionMatrix1; |
||||
uniform mat4 m_LightViewProjectionMatrix2; |
||||
uniform mat4 m_LightViewProjectionMatrix3; |
||||
|
||||
vec3 getPosition(in float depth, in vec2 uv){ |
||||
vec4 pos = vec4(uv, depth, 1.0) * 2.0 - 1.0; |
||||
pos = m_ViewProjectionMatrixInverse * pos; |
||||
return pos.xyz / pos.w; |
||||
} |
||||
|
||||
void main(){ |
||||
|
||||
float depth = texture2D(m_DepthTexture,texCoord).r; |
||||
vec4 color = texture2D(m_Texture,texCoord); |
||||
|
||||
//Discard shadow computation on the sky |
||||
if(depth == 1.0){ |
||||
gl_FragColor = color; |
||||
return; |
||||
} |
||||
|
||||
// get the vertex in world space |
||||
vec4 worldPos = vec4(getPosition(depth,texCoord),1.0); |
||||
|
||||
// populate the light view matrices array and convert vertex to light viewProj space |
||||
vec4 projCoord0 = biasMat * m_LightViewProjectionMatrix0 * worldPos; |
||||
vec4 projCoord1 = biasMat * m_LightViewProjectionMatrix1 * worldPos; |
||||
vec4 projCoord2 = biasMat * m_LightViewProjectionMatrix2 * worldPos; |
||||
vec4 projCoord3 = biasMat * m_LightViewProjectionMatrix3 * worldPos; |
||||
|
||||
|
||||
float shadowPosition = m_ViewProjectionMatrixRow2.x * worldPos.x + m_ViewProjectionMatrixRow2.y * worldPos.y + m_ViewProjectionMatrixRow2.z * worldPos.z + m_ViewProjectionMatrixRow2.w; |
||||
|
||||
float shadow = 0.0; |
||||
if(shadowPosition < m_Splits.x){ |
||||
shadow = GETSHADOW(m_ShadowMap0, projCoord0); |
||||
}else if( shadowPosition < m_Splits.y){ |
||||
shadowBorderScale = 0.5; |
||||
shadow = GETSHADOW(m_ShadowMap1, projCoord1); |
||||
}else if( shadowPosition < m_Splits.z){ |
||||
shadowBorderScale = 0.25; |
||||
shadow = GETSHADOW(m_ShadowMap2, projCoord2); |
||||
}else if( shadowPosition < m_Splits.w){ |
||||
shadowBorderScale = 0.125; |
||||
shadow = GETSHADOW(m_ShadowMap3, projCoord3); |
||||
} |
||||
|
||||
shadow= shadow * m_ShadowIntensity + (1.0 - m_ShadowIntensity); |
||||
gl_FragColor = color * vec4(shadow, shadow, shadow, 1.0); |
||||
|
||||
} |
||||
|
@ -0,0 +1,73 @@ |
||||
MaterialDef Post Shadow { |
||||
|
||||
MaterialParameters { |
||||
Int FilterMode |
||||
Boolean HardwareShadows |
||||
|
||||
Texture2D ShadowMap0 |
||||
Texture2D ShadowMap1 |
||||
Texture2D ShadowMap2 |
||||
Texture2D ShadowMap3 |
||||
|
||||
Float ShadowIntensity |
||||
Vector4 Splits |
||||
|
||||
Matrix4 LightViewProjectionMatrix0 |
||||
Matrix4 LightViewProjectionMatrix1 |
||||
Matrix4 LightViewProjectionMatrix2 |
||||
Matrix4 LightViewProjectionMatrix3 |
||||
|
||||
Float PCFEdge |
||||
|
||||
Float ShadowMapSize |
||||
|
||||
Matrix4 ViewProjectionMatrixInverse |
||||
Vector4 ViewProjectionMatrixRow2 |
||||
|
||||
Int NumSamples |
||||
Int NumSamplesDepth |
||||
Texture2D Texture |
||||
Texture2D DepthTexture |
||||
|
||||
} |
||||
|
||||
Technique { |
||||
VertexShader GLSL150: Common/MatDefs/Shadow/PostShadowFilter15.vert |
||||
FragmentShader GLSL150: Common/MatDefs/Shadow/PostShadowFilter15.frag |
||||
|
||||
WorldParameters { |
||||
WorldViewProjectionMatrix |
||||
} |
||||
|
||||
Defines { |
||||
RESOLVE_MS : NumSamples |
||||
RESOLVE_DEPTH_MS : NumSamplesDepth |
||||
HARDWARE_SHADOWS : HardwareShadows |
||||
FILTER_MODE : FilterMode |
||||
PCFEDGE : PCFEdge |
||||
SHADOWMAP_SIZE : ShadowMapSize |
||||
} |
||||
|
||||
} |
||||
|
||||
Technique { |
||||
VertexShader GLSL100: Common/MatDefs/Shadow/PostShadowFilter.vert |
||||
FragmentShader GLSL100: Common/MatDefs/Shadow/PostShadowFilter.frag |
||||
|
||||
WorldParameters { |
||||
WorldViewProjectionMatrix |
||||
} |
||||
|
||||
Defines { |
||||
HARDWARE_SHADOWS : HardwareShadows |
||||
FILTER_MODE : FilterMode |
||||
PCFEDGE : PCFEdge |
||||
SHADOWMAP_SIZE : ShadowMapSize |
||||
} |
||||
|
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
} |
@ -0,0 +1,10 @@ |
||||
uniform mat4 g_WorldViewProjectionMatrix; |
||||
|
||||
attribute vec4 inPosition; |
||||
attribute vec2 inTexCoord; |
||||
varying vec2 texCoord; |
||||
|
||||
void main() { |
||||
gl_Position = inPosition * 2.0 - 1.0; //vec4(pos, 0.0, 1.0); |
||||
texCoord = inTexCoord; |
||||
} |
@ -0,0 +1,84 @@ |
||||
#import "Common/ShaderLib/MultiSample.glsllib" |
||||
#import "Common/ShaderLib/PssmShadows15.glsllib" |
||||
|
||||
|
||||
uniform COLORTEXTURE m_Texture; |
||||
uniform DEPTHTEXTURE m_DepthTexture; |
||||
uniform mat4 m_ViewProjectionMatrixInverse; |
||||
uniform vec4 m_ViewProjectionMatrixRow2; |
||||
|
||||
in vec2 texCoord; |
||||
out vec4 outFragColor; |
||||
|
||||
const mat4 biasMat = mat4(0.5, 0.0, 0.0, 0.0, |
||||
0.0, 0.5, 0.0, 0.0, |
||||
0.0, 0.0, 0.5, 0.0, |
||||
0.5, 0.5, 0.5, 1.0); |
||||
|
||||
uniform mat4 m_LightViewProjectionMatrix0; |
||||
uniform mat4 m_LightViewProjectionMatrix1; |
||||
uniform mat4 m_LightViewProjectionMatrix2; |
||||
uniform mat4 m_LightViewProjectionMatrix3; |
||||
|
||||
|
||||
vec3 getPosition(in float depth, in vec2 uv){ |
||||
vec4 pos = vec4(uv, depth, 1.0) * 2.0 - 1.0; |
||||
pos = m_ViewProjectionMatrixInverse * pos; |
||||
return pos.xyz / pos.w; |
||||
} |
||||
|
||||
vec4 main_multiSample(in int numSample){ |
||||
float depth = fetchTextureSample(m_DepthTexture,texCoord,numSample).r;//getDepth(m_DepthTexture,texCoord).r; |
||||
vec4 color = fetchTextureSample(m_Texture,texCoord,numSample); |
||||
|
||||
//Discard shadow computation on the sky |
||||
if(depth == 1.0){ |
||||
return color; |
||||
} |
||||
|
||||
// get the vertex in world space |
||||
vec4 worldPos = vec4(getPosition(depth,texCoord),1.0); |
||||
|
||||
// populate the light view matrices array and convert vertex to light viewProj space |
||||
vec4 projCoord0 = biasMat * m_LightViewProjectionMatrix0 * worldPos; |
||||
vec4 projCoord1 = biasMat * m_LightViewProjectionMatrix1 * worldPos; |
||||
vec4 projCoord2 = biasMat * m_LightViewProjectionMatrix2 * worldPos; |
||||
vec4 projCoord3 = biasMat * m_LightViewProjectionMatrix3 * worldPos; |
||||
|
||||
float shadowPosition = m_ViewProjectionMatrixRow2.x * worldPos.x + m_ViewProjectionMatrixRow2.y * worldPos.y + m_ViewProjectionMatrixRow2.z * worldPos.z + m_ViewProjectionMatrixRow2.w; |
||||
|
||||
float shadow = 0.0; |
||||
if(shadowPosition < m_Splits.x){ |
||||
shadow = GETSHADOW(m_ShadowMap0, projCoord0); |
||||
}else if( shadowPosition < m_Splits.y){ |
||||
shadowBorderScale = 0.5; |
||||
shadow = GETSHADOW(m_ShadowMap1, projCoord1); |
||||
}else if( shadowPosition < m_Splits.z){ |
||||
shadowBorderScale = 0.25; |
||||
shadow = GETSHADOW(m_ShadowMap2, projCoord2); |
||||
}else if( shadowPosition < m_Splits.w){ |
||||
shadowBorderScale = 0.125; |
||||
shadow = GETSHADOW(m_ShadowMap3, projCoord3); |
||||
} |
||||
|
||||
shadow= shadow * m_ShadowIntensity + (1.0 - m_ShadowIntensity); |
||||
|
||||
return color * vec4(shadow, shadow, shadow, 1.0); |
||||
} |
||||
|
||||
void main(){ |
||||
|
||||
#ifdef RESOLVE_MS |
||||
vec4 color = vec4(0.0); |
||||
for (int i = 0; i < m_NumSamples; i++){ |
||||
color += main_multiSample(i); |
||||
} |
||||
outFragColor = color / m_NumSamples; |
||||
#else |
||||
outFragColor = main_multiSample(0); |
||||
#endif |
||||
|
||||
} |
||||
|
||||
|
||||
|
@ -0,0 +1,12 @@ |
||||
uniform mat4 g_WorldViewProjectionMatrix; |
||||
|
||||
in vec4 inPosition; |
||||
in vec2 inTexCoord; |
||||
|
||||
out vec2 texCoord; |
||||
|
||||
void main() { |
||||
vec2 pos = (g_WorldViewProjectionMatrix * inPosition).xy; |
||||
gl_Position = vec4(pos, 0.0, 1.0); |
||||
texCoord = inTexCoord; |
||||
} |
@ -0,0 +1,151 @@ |
||||
#ifdef HARDWARE_SHADOWS |
||||
#define SHADOWMAP sampler2DShadow |
||||
#define SHADOWCOMPARE(tex,coord) shadow2DProj(tex, coord).r |
||||
#else |
||||
#define SHADOWMAP sampler2D |
||||
#define SHADOWCOMPARE(tex,coord) step(coord.z, texture2DProj(tex, coord).r) |
||||
#endif |
||||
|
||||
#if FILTER_MODE == 0 |
||||
#define GETSHADOW Shadow_DoShadowCompare |
||||
#define KERNEL 1.0 |
||||
#elif FILTER_MODE == 1 |
||||
#ifdef HARDWARE_SHADOWS |
||||
#define GETSHADOW Shadow_DoShadowCompare |
||||
#else |
||||
#define GETSHADOW Shadow_DoBilinear_2x2 |
||||
#endif |
||||
#define KERNEL 1.0 |
||||
#elif FILTER_MODE == 2 |
||||
#define GETSHADOW Shadow_DoDither_2x2 |
||||
#define KERNEL 1.0 |
||||
#elif FILTER_MODE == 3 |
||||
#define GETSHADOW Shadow_DoPCF |
||||
#define KERNEL 4.0 |
||||
#elif FILTER_MODE == 4 |
||||
#define GETSHADOW Shadow_DoPCFPoisson |
||||
#define KERNEL 4 |
||||
#elif FILTER_MODE == 5 |
||||
#define GETSHADOW Shadow_DoPCF |
||||
#define KERNEL 8.0 |
||||
#endif |
||||
|
||||
|
||||
uniform SHADOWMAP m_ShadowMap0; |
||||
uniform SHADOWMAP m_ShadowMap1; |
||||
uniform SHADOWMAP m_ShadowMap2; |
||||
uniform SHADOWMAP m_ShadowMap3; |
||||
|
||||
uniform vec4 m_Splits; |
||||
|
||||
uniform float m_ShadowIntensity; |
||||
|
||||
const vec2 pixSize2 = vec2(1.0 / SHADOWMAP_SIZE); |
||||
float shadowBorderScale = 1.0; |
||||
|
||||
float Shadow_DoShadowCompareOffset(in SHADOWMAP tex, in vec4 projCoord, in vec2 offset){ |
||||
vec4 coord = vec4(projCoord.xy + offset.xy * pixSize2 * shadowBorderScale, projCoord.zw); |
||||
return SHADOWCOMPARE(tex, coord); |
||||
} |
||||
|
||||
float Shadow_DoShadowCompare(in SHADOWMAP tex, vec4 projCoord){ |
||||
return SHADOWCOMPARE(tex, projCoord); |
||||
} |
||||
|
||||
float Shadow_BorderCheck(in vec2 coord){ |
||||
// Fastest, "hack" method (uses 4-5 instructions) |
||||
vec4 t = vec4(coord.xy, 0.0, 1.0); |
||||
t = step(t.wwxy, t.xyzz); |
||||
return dot(t,t); |
||||
} |
||||
|
||||
float Shadow_DoDither_2x2(in SHADOWMAP tex, in vec4 projCoord){ |
||||
float border = Shadow_BorderCheck(projCoord.xy); |
||||
if (border > 0.0) |
||||
return 1.0; |
||||
|
||||
|
||||
float shadow = 0.0; |
||||
vec2 o = mod(floor(gl_FragCoord.xy), 2.0); |
||||
shadow += Shadow_DoShadowCompareOffset(tex,projCoord,vec2(-1.5, 1.5) + o); |
||||
shadow += Shadow_DoShadowCompareOffset(tex,projCoord,vec2( 0.5, 1.5) + o); |
||||
shadow += Shadow_DoShadowCompareOffset(tex,projCoord,vec2(-1.5, -0.5) + o); |
||||
shadow += Shadow_DoShadowCompareOffset(tex,projCoord,vec2( 0.5, -0.5) + o); |
||||
shadow *= 0.25 ; |
||||
return shadow; |
||||
} |
||||
|
||||
float Shadow_DoBilinear_2x2(in SHADOWMAP tex, in vec4 projCoord){ |
||||
float border = Shadow_BorderCheck(projCoord.xy); |
||||
if (border > 0.0) |
||||
return 1.0; |
||||
vec4 gather = vec4(0.0); |
||||
gather.x = Shadow_DoShadowCompareOffset(tex, projCoord, vec2(0.0, 0.0)); |
||||
gather.y = Shadow_DoShadowCompareOffset(tex, projCoord, vec2(1.0, 0.0)); |
||||
gather.z = Shadow_DoShadowCompareOffset(tex, projCoord, vec2(0.0, 1.0)); |
||||
gather.w = Shadow_DoShadowCompareOffset(tex, projCoord, vec2(1.0, 1.0)); |
||||
|
||||
vec2 f = fract( projCoord.xy * SHADOWMAP_SIZE ); |
||||
vec2 mx = mix( gather.xz, gather.yw, f.x ); |
||||
return mix( mx.x, mx.y, f.y ); |
||||
} |
||||
|
||||
float Shadow_DoPCF(in SHADOWMAP tex, in vec4 projCoord){ |
||||
float shadow = 0.0; |
||||
float border = Shadow_BorderCheck(projCoord.xy); |
||||
if (border > 0.0) |
||||
return 1.0; |
||||
float bound = KERNEL * 0.5 - 0.5; |
||||
bound *= PCFEDGE; |
||||
for (float y = -bound; y <= bound; y += PCFEDGE){ |
||||
for (float x = -bound; x <= bound; x += PCFEDGE){ |
||||
shadow += clamp(Shadow_DoShadowCompareOffset(tex,projCoord,vec2(x,y)) + |
||||
border, |
||||
0.0, 1.0); |
||||
} |
||||
} |
||||
|
||||
shadow = shadow / (KERNEL * KERNEL); |
||||
return shadow; |
||||
} |
||||
|
||||
|
||||
//12 tap poisson disk |
||||
const vec2 poissonDisk0 = vec2(-0.1711046, -0.425016); |
||||
const vec2 poissonDisk1 = vec2(-0.7829809, 0.2162201); |
||||
const vec2 poissonDisk2 = vec2(-0.2380269, -0.8835521); |
||||
const vec2 poissonDisk3 = vec2(0.4198045, 0.1687819); |
||||
const vec2 poissonDisk4 = vec2(-0.684418, -0.3186957); |
||||
const vec2 poissonDisk5 = vec2(0.6026866, -0.2587841); |
||||
const vec2 poissonDisk6 = vec2(-0.2412762, 0.3913516); |
||||
const vec2 poissonDisk7 = vec2(0.4720655, -0.7664126); |
||||
const vec2 poissonDisk8 = vec2(0.9571564, 0.2680693); |
||||
const vec2 poissonDisk9 = vec2(-0.5238616, 0.802707); |
||||
const vec2 poissonDisk10 = vec2(0.5653144, 0.60262); |
||||
const vec2 poissonDisk11 = vec2(0.0123658, 0.8627419); |
||||
|
||||
float Shadow_DoPCFPoisson(in SHADOWMAP tex, in vec4 projCoord){ |
||||
float shadow = 0.0; |
||||
float border = Shadow_BorderCheck(projCoord.xy); |
||||
if (border > 0.0) |
||||
return 1.0; |
||||
|
||||
vec2 texelSize = vec2( 4.0 * PCFEDGE * shadowBorderScale); |
||||
|
||||
shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk0 * texelSize); |
||||
shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk1 * texelSize); |
||||
shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk2 * texelSize); |
||||
shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk3 * texelSize); |
||||
shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk4 * texelSize); |
||||
shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk5 * texelSize); |
||||
shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk6 * texelSize); |
||||
shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk7 * texelSize); |
||||
shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk8 * texelSize); |
||||
shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk9 * texelSize); |
||||
shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk10 * texelSize); |
||||
shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk11 * texelSize); |
||||
|
||||
shadow = shadow * 0.08333333333;//this is divided by 12 |
||||
return shadow; |
||||
} |
||||
|
@ -0,0 +1,164 @@ |
||||
// Because gpu_shader5 is actually where those |
||||
// gather functions are declared to work on shadowmaps |
||||
#extension GL_ARB_gpu_shader5 : enable |
||||
|
||||
#ifdef HARDWARE_SHADOWS |
||||
#define SHADOWMAP sampler2DShadow |
||||
#define SHADOWCOMPAREOFFSET(tex,coord,offset) textureProjOffset(tex, coord, offset) |
||||
#define SHADOWCOMPARE(tex,coord) textureProj(tex, coord) |
||||
#define SHADOWGATHER(tex,coord) textureGather(tex, coord.xy, coord.z) |
||||
#else |
||||
#define SHADOWMAP sampler2D |
||||
#define SHADOWCOMPAREOFFSET(tex,coord,offset) step(coord.z, textureProjOffset(tex, coord, offset).r) |
||||
#define SHADOWCOMPARE(tex,coord) step(coord.z, textureProj(tex, coord).r) |
||||
#define SHADOWGATHER(tex,coord) step(coord.z, textureGather(tex, coord.xy)) |
||||
#endif |
||||
|
||||
|
||||
#if FILTER_MODE == 0 |
||||
#define GETSHADOW SHADOWCOMPARE |
||||
#define KERNEL 1 |
||||
#elif FILTER_MODE == 1 |
||||
#ifdef HARDWARE_SHADOWS |
||||
#define GETSHADOW SHADOWCOMPARE |
||||
#else |
||||
#define GETSHADOW Shadow_DoBilinear_2x2 |
||||
#endif |
||||
#define KERNEL 1 |
||||
#elif FILTER_MODE == 2 |
||||
#define GETSHADOW Shadow_DoDither_2x2 |
||||
#define KERNEL 1 |
||||
#elif FILTER_MODE == 3 |
||||
#define GETSHADOW Shadow_DoPCF |
||||
#define KERNEL 4 |
||||
#elif FILTER_MODE == 4 |
||||
#define GETSHADOW Shadow_DoPCFPoisson |
||||
#define KERNEL 4 |
||||
#elif FILTER_MODE == 5 |
||||
#define GETSHADOW Shadow_DoPCF |
||||
#define KERNEL 8 |
||||
#endif |
||||
|
||||
|
||||
|
||||
uniform SHADOWMAP m_ShadowMap0; |
||||
uniform SHADOWMAP m_ShadowMap1; |
||||
uniform SHADOWMAP m_ShadowMap2; |
||||
uniform SHADOWMAP m_ShadowMap3; |
||||
|
||||
uniform vec4 m_Splits; |
||||
uniform float m_ShadowIntensity; |
||||
|
||||
const vec2 pixSize2 = vec2(1.0 / SHADOWMAP_SIZE); |
||||
float shadowBorderScale = 1.0; |
||||
|
||||
float Shadow_BorderCheck(in vec2 coord){ |
||||
// Fastest, "hack" method (uses 4-5 instructions) |
||||
vec4 t = vec4(coord.xy, 0.0, 1.0); |
||||
t = step(t.wwxy, t.xyzz); |
||||
return dot(t,t); |
||||
} |
||||
|
||||
float Shadow_DoDither_2x2(in SHADOWMAP tex, in vec4 projCoord){ |
||||
float border = Shadow_BorderCheck(projCoord.xy); |
||||
if (border > 0.0) |
||||
return 1.0; |
||||
|
||||
vec2 pixSize = pixSize2 * shadowBorderScale; |
||||
|
||||
float shadow = 0.0; |
||||
ivec2 o = ivec2(mod(floor(gl_FragCoord.xy), 2.0)); |
||||
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy+pixSize*(vec2(-1.5, 1.5)+o), projCoord.zw)); |
||||
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy+pixSize*(vec2( 0.5, 1.5)+o), projCoord.zw)); |
||||
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy+pixSize*(vec2(-1.5, -0.5)+o), projCoord.zw)); |
||||
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy+pixSize*(vec2( 0.5, -0.5)+o), projCoord.zw)); |
||||
shadow *= 0.25; |
||||
return shadow; |
||||
} |
||||
|
||||
float Shadow_DoBilinear_2x2(in SHADOWMAP tex, in vec4 projCoord){ |
||||
float border = Shadow_BorderCheck(projCoord.xy); |
||||
if (border > 0.0) |
||||
return 1.0; |
||||
|
||||
#ifdef GL_ARB_gpu_shader5 |
||||
vec4 coord = vec4(projCoord.xyz / projCoord.www,0.0); |
||||
vec4 gather = SHADOWGATHER(tex, coord); |
||||
#else |
||||
vec4 gather = vec4(0.0); |
||||
gather.x = SHADOWCOMPAREOFFSET(tex, projCoord, ivec2(0, 0)); |
||||
gather.y = SHADOWCOMPAREOFFSET(tex, projCoord, ivec2(1, 0)); |
||||
gather.z = SHADOWCOMPAREOFFSET(tex, projCoord, ivec2(0, 1)); |
||||
gather.w = SHADOWCOMPAREOFFSET(tex, projCoord, ivec2(1, 1)); |
||||
#endif |
||||
|
||||
vec2 f = fract( projCoord.xy * SHADOWMAP_SIZE ); |
||||
vec2 mx = mix( gather.xz, gather.yw, f.x ); |
||||
return mix( mx.x, mx.y, f.y ); |
||||
} |
||||
|
||||
float Shadow_DoPCF(in SHADOWMAP tex, in vec4 projCoord){ |
||||
|
||||
vec2 pixSize = pixSize2 * shadowBorderScale; |
||||
float shadow = 0.0; |
||||
float border = Shadow_BorderCheck(projCoord.xy); |
||||
if (border > 0.0) |
||||
return 1.0; |
||||
|
||||
float bound = KERNEL * 0.5 - 0.5; |
||||
bound *= PCFEDGE; |
||||
for (float y = -bound; y <= bound; y += PCFEDGE){ |
||||
for (float x = -bound; x <= bound; x += PCFEDGE){ |
||||
vec4 coord = vec4(projCoord.xy + vec2(x,y) * pixSize, projCoord.zw); |
||||
shadow += SHADOWCOMPARE(tex, coord); |
||||
} |
||||
} |
||||
|
||||
shadow = shadow / (KERNEL * KERNEL); |
||||
return shadow; |
||||
} |
||||
|
||||
|
||||
//12 tap poisson disk |
||||
const vec2 poissonDisk0 = vec2(-0.1711046, -0.425016); |
||||
const vec2 poissonDisk1 = vec2(-0.7829809, 0.2162201); |
||||
const vec2 poissonDisk2 = vec2(-0.2380269, -0.8835521); |
||||
const vec2 poissonDisk3 = vec2(0.4198045, 0.1687819); |
||||
const vec2 poissonDisk4 = vec2(-0.684418, -0.3186957); |
||||
const vec2 poissonDisk5 = vec2(0.6026866, -0.2587841); |
||||
const vec2 poissonDisk6 = vec2(-0.2412762, 0.3913516); |
||||
const vec2 poissonDisk7 = vec2(0.4720655, -0.7664126); |
||||
const vec2 poissonDisk8 = vec2(0.9571564, 0.2680693); |
||||
const vec2 poissonDisk9 = vec2(-0.5238616, 0.802707); |
||||
const vec2 poissonDisk10 = vec2(0.5653144, 0.60262); |
||||
const vec2 poissonDisk11 = vec2(0.0123658, 0.8627419); |
||||
|
||||
|
||||
float Shadow_DoPCFPoisson(in SHADOWMAP tex, in vec4 projCoord){ |
||||
|
||||
float shadow = 0.0; |
||||
float border = Shadow_BorderCheck(projCoord.xy); |
||||
if (border > 0.0){ |
||||
return 1.0; |
||||
} |
||||
|
||||
vec2 texelSize = pixSize2 * 4.0 * PCFEDGE * shadowBorderScale; |
||||
|
||||
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk0 * texelSize, projCoord.zw)); |
||||
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk1 * texelSize, projCoord.zw)); |
||||
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk2 * texelSize, projCoord.zw)); |
||||
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk3 * texelSize, projCoord.zw)); |
||||
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk4 * texelSize, projCoord.zw)); |
||||
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk5 * texelSize, projCoord.zw)); |
||||
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk6 * texelSize, projCoord.zw)); |
||||
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk7 * texelSize, projCoord.zw)); |
||||
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk8 * texelSize, projCoord.zw)); |
||||
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk9 * texelSize, projCoord.zw)); |
||||
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk10 * texelSize, projCoord.zw)); |
||||
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk11 * texelSize, projCoord.zw)); |
||||
|
||||
//this is divided by 12 |
||||
return shadow * 0.08333333333; |
||||
} |
||||
|
||||
|
@ -0,0 +1,262 @@ |
||||
/* |
||||
* Copyright (c) 2009-2010 jMonkeyEngine |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* |
||||
* * Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* |
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||
* may be used to endorse or promote products derived from this software |
||||
* without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
package com.jme3.shadow; |
||||
|
||||
import com.jme3.asset.AssetManager; |
||||
import com.jme3.export.InputCapsule; |
||||
import com.jme3.export.JmeExporter; |
||||
import com.jme3.export.JmeImporter; |
||||
import com.jme3.export.OutputCapsule; |
||||
import com.jme3.material.Material; |
||||
import com.jme3.math.Matrix4f; |
||||
import com.jme3.math.Vector3f; |
||||
import com.jme3.math.Vector4f; |
||||
import com.jme3.post.Filter; |
||||
import com.jme3.renderer.RenderManager; |
||||
import com.jme3.renderer.ViewPort; |
||||
import com.jme3.renderer.queue.RenderQueue; |
||||
import com.jme3.shadow.PssmShadowRenderer.CompareMode; |
||||
import com.jme3.shadow.PssmShadowRenderer.FilterMode; |
||||
import com.jme3.texture.FrameBuffer; |
||||
import java.io.IOException; |
||||
|
||||
/** |
||||
* |
||||
* This Filter does basically the same as a PssmShadowRenderer except it renders |
||||
* the post shadow pass as a fulscreen quad pass instead of a geometry pass. |
||||
* It's mostly faster than PssmShadowRenderer as long as you have more than a about ten shadow recieving objects. |
||||
* The expense is the draw back that the shadow Recieve mode set on spatial is ignored. |
||||
* So basically all and only objects that render depth in the scene receive shadows. |
||||
* See this post for more details http://jmonkeyengine.org/groups/general-2/forum/topic/silly-question-about-shadow-rendering/#post-191599
|
||||
* |
||||
* API is basically the same as the PssmShadowRenderer; |
||||
* |
||||
* @author Rémy Bouquet aka Nehon |
||||
*/ |
||||
public class PssmShadowFilter extends Filter { |
||||
|
||||
private PssmShadowRenderer pssmRenderer; |
||||
private ViewPort viewPort; |
||||
|
||||
/** |
||||
* Creates a PSSM Shadow Filter |
||||
* More info on the technique at <a href="http://http.developer.nvidia.com/GPUGems3/gpugems3_ch10.html">http://http.developer.nvidia.com/GPUGems3/gpugems3_ch10.html</a>
|
||||
* @param manager the application asset manager |
||||
* @param size the size of the rendered shadowmaps (512,1024,2048, etc...) |
||||
* @param nbSplits the number of shadow maps rendered (the more shadow maps the more quality, the less fps). |
||||
*/ |
||||
public PssmShadowFilter(AssetManager manager, int size, int nbSplits) { |
||||
super("Post Shadow"); |
||||
material = new Material(manager, "Common/MatDefs/Shadow/PostShadowFilter.j3md"); |
||||
pssmRenderer = new PssmShadowRenderer(manager, size, nbSplits, material); |
||||
pssmRenderer.needsfallBackMaterial = true; |
||||
} |
||||
|
||||
@Override |
||||
protected Material getMaterial() { |
||||
return material; |
||||
} |
||||
|
||||
@Override |
||||
protected boolean isRequiresDepthTexture() { |
||||
return true; |
||||
} |
||||
|
||||
public Material getShadowMaterial() { |
||||
return material; |
||||
} |
||||
Vector4f tmpv = new Vector4f(); |
||||
|
||||
@Override |
||||
protected void preFrame(float tpf) { |
||||
pssmRenderer.preFrame(tpf); |
||||
material.setMatrix4("ViewProjectionMatrixInverse", viewPort.getCamera().getViewProjectionMatrix().invert()); |
||||
Matrix4f m = viewPort.getCamera().getViewProjectionMatrix(); |
||||
material.setVector4("ViewProjectionMatrixRow2", tmpv.set(m.m20, m.m21, m.m22, m.m23)); |
||||
|
||||
} |
||||
|
||||
@Override |
||||
protected void postQueue(RenderQueue queue) { |
||||
pssmRenderer.postQueue(queue); |
||||
} |
||||
|
||||
@Override |
||||
protected void postFrame(RenderManager renderManager, ViewPort viewPort, FrameBuffer prevFilterBuffer, FrameBuffer sceneBuffer) { |
||||
pssmRenderer.setPostShadowParams(); |
||||
} |
||||
|
||||
@Override |
||||
protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) { |
||||
pssmRenderer.initialize(renderManager, vp); |
||||
this.viewPort = vp; |
||||
} |
||||
|
||||
/** |
||||
* returns the light direction used by the processor |
||||
* @return |
||||
*/ |
||||
public Vector3f getDirection() { |
||||
return pssmRenderer.getDirection(); |
||||
} |
||||
|
||||
/** |
||||
* Sets the light direction to use to compute shadows |
||||
* @param direction |
||||
*/ |
||||
public void setDirection(Vector3f direction) { |
||||
pssmRenderer.setDirection(direction); |
||||
} |
||||
|
||||
/** |
||||
* returns the labda parameter<br> |
||||
* see {@link setLambda(float lambda)} |
||||
* @return lambda |
||||
*/ |
||||
public float getLambda() { |
||||
return pssmRenderer.getLambda(); |
||||
} |
||||
|
||||
/* |
||||
* Adjust the repartition of the different shadow maps in the shadow extend |
||||
* usualy goes from 0.0 to 1.0 |
||||
* a low value give a more linear repartition resulting in a constant quality in the shadow over the extends, but near shadows could look very jagged |
||||
* a high value give a more logarithmic repartition resulting in a high quality for near shadows, but the quality quickly decrease over the extend. |
||||
* the default value is set to 0.65f (theoric optimal value). |
||||
* @param lambda the lambda value. |
||||
*/ |
||||
public void setLambda(float lambda) { |
||||
pssmRenderer.setLambda(lambda); |
||||
} |
||||
|
||||
/** |
||||
* How far the shadows are rendered in the view |
||||
* see {@link setShadowZExtend(float zFar)} |
||||
* @return shadowZExtend |
||||
*/ |
||||
public float getShadowZExtend() { |
||||
return pssmRenderer.getShadowZExtend(); |
||||
} |
||||
|
||||
/** |
||||
* Set the distance from the eye where the shadows will be rendered |
||||
* default value is dynamicaly computed to the shadow casters/receivers union bound zFar, capped to view frustum far value. |
||||
* @param zFar the zFar values that override the computed one |
||||
*/ |
||||
public void setShadowZExtend(float zFar) { |
||||
pssmRenderer.setShadowZExtend(zFar); |
||||
} |
||||
|
||||
/** |
||||
* returns the shdaow intensity<br> |
||||
* see {@link setShadowIntensity(float shadowIntensity)} |
||||
* @return shadowIntensity |
||||
*/ |
||||
public float getShadowIntensity() { |
||||
return pssmRenderer.getShadowIntensity(); |
||||
} |
||||
|
||||
/** |
||||
* Set the shadowIntensity, the value should be between 0 and 1, |
||||
* a 0 value gives a bright and invisilble shadow, |
||||
* a 1 value gives a pitch black shadow, |
||||
* default is 0.7 |
||||
* @param shadowIntensity the darkness of the shadow |
||||
*/ |
||||
final public void setShadowIntensity(float shadowIntensity) { |
||||
pssmRenderer.setShadowIntensity(shadowIntensity); |
||||
} |
||||
|
||||
/** |
||||
* returns the edges thickness <br> |
||||
* see {@link setEdgesThickness(int edgesThickness)} |
||||
* @return edgesThickness |
||||
*/ |
||||
public int getEdgesThickness() { |
||||
return pssmRenderer.getEdgesThickness(); |
||||
} |
||||
|
||||
/** |
||||
* Sets the shadow edges thickness. default is 1, setting it to lower values can help to reduce the jagged effect of the shadow edges |
||||
* @param edgesThickness |
||||
*/ |
||||
public void setEdgesThickness(int edgesThickness) { |
||||
pssmRenderer.setEdgesThickness(edgesThickness); |
||||
} |
||||
|
||||
/** |
||||
* returns true if the PssmRenderer flushed the shadow queues |
||||
* @return flushQueues |
||||
*/ |
||||
public boolean isFlushQueues() { |
||||
return pssmRenderer.isFlushQueues(); |
||||
} |
||||
|
||||
/** |
||||
* Set this to false if you want to use several PssmRederers to have multiple shadows cast by multiple light sources. |
||||
* Make sure the last PssmRenderer in the stack DO flush the queues, but not the others |
||||
* @param flushQueues |
||||
*/ |
||||
public void setFlushQueues(boolean flushQueues) { |
||||
pssmRenderer.setFlushQueues(flushQueues); |
||||
} |
||||
|
||||
/** |
||||
* sets the shadow compare mode see {@link CompareMode} for more info |
||||
* @param compareMode |
||||
*/ |
||||
final public void setCompareMode(CompareMode compareMode) { |
||||
pssmRenderer.setCompareMode(compareMode); |
||||
} |
||||
|
||||
/** |
||||
* Sets the filtering mode for shadow edges see {@link FilterMode} for more info |
||||
* @param filterMode |
||||
*/ |
||||
final public void setFilterMode(FilterMode filterMode) { |
||||
pssmRenderer.setFilterMode(filterMode); |
||||
} |
||||
|
||||
@Override |
||||
public void write(JmeExporter ex) throws IOException { |
||||
super.write(ex); |
||||
OutputCapsule oc = ex.getCapsule(this); |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public void read(JmeImporter im) throws IOException { |
||||
super.read(im); |
||||
InputCapsule ic = im.getCapsule(this); |
||||
|
||||
} |
||||
} |
@ -0,0 +1,182 @@ |
||||
/* |
||||
* Copyright (c) 2009-2010 jMonkeyEngine |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* |
||||
* * Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* |
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||
* may be used to endorse or promote products derived from this software |
||||
* without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
package jme3test.light; |
||||
|
||||
import com.jme3.app.SimpleApplication; |
||||
import com.jme3.input.KeyInput; |
||||
import com.jme3.input.controls.ActionListener; |
||||
import com.jme3.input.controls.KeyTrigger; |
||||
import com.jme3.light.AmbientLight; |
||||
import com.jme3.light.DirectionalLight; |
||||
import com.jme3.light.PointLight; |
||||
import com.jme3.material.Material; |
||||
import com.jme3.math.ColorRGBA; |
||||
import com.jme3.math.Quaternion; |
||||
import com.jme3.math.Vector2f; |
||||
import com.jme3.math.Vector3f; |
||||
import com.jme3.renderer.queue.RenderQueue.ShadowMode; |
||||
import com.jme3.scene.Geometry; |
||||
import com.jme3.scene.Spatial; |
||||
import com.jme3.scene.shape.Box; |
||||
import com.jme3.scene.shape.Sphere; |
||||
import com.jme3.shadow.PssmShadowRenderer; |
||||
import com.jme3.shadow.PssmShadowRenderer.CompareMode; |
||||
import com.jme3.shadow.PssmShadowRenderer.FilterMode; |
||||
import com.jme3.util.TangentBinormalGenerator; |
||||
import java.util.logging.Level; |
||||
import java.util.logging.Logger; |
||||
|
||||
public class TestShadowsPerf extends SimpleApplication { |
||||
|
||||
float angle; |
||||
PointLight pl; |
||||
Spatial lightMdl; |
||||
|
||||
public static void main(String[] args) { |
||||
TestShadowsPerf app = new TestShadowsPerf(); |
||||
app.start(); |
||||
} |
||||
Geometry sphere; |
||||
Material mat; |
||||
|
||||
@Override |
||||
public void simpleInitApp() { |
||||
Logger.getLogger("com.jme3").setLevel(Level.SEVERE); |
||||
flyCam.setMoveSpeed(50); |
||||
flyCam.setEnabled(false); |
||||
viewPort.setBackgroundColor(ColorRGBA.DarkGray); |
||||
cam.setLocation(new Vector3f(-53.952988f, 27.15874f, -32.875023f)); |
||||
cam.setRotation(new Quaternion(0.1564309f, 0.6910534f, -0.15713608f, 0.6879555f)); |
||||
|
||||
// cam.setLocation(new Vector3f(53.64627f, 130.56f, -11.247704f));
|
||||
// cam.setRotation(new Quaternion(-6.5737107E-4f, 0.76819664f, -0.64021313f, -7.886125E-4f));
|
||||
////
|
||||
cam.setFrustumFar(500); |
||||
|
||||
mat = assetManager.loadMaterial("Textures/Terrain/Pond/Pond.j3m"); |
||||
|
||||
Box b = new Box(Vector3f.ZERO, 800, 1, 700); |
||||
b.scaleTextureCoordinates(new Vector2f(50, 50)); |
||||
Geometry ground = new Geometry("ground", b); |
||||
ground.setMaterial(mat); |
||||
rootNode.attachChild(ground); |
||||
ground.setShadowMode(ShadowMode.Receive); |
||||
|
||||
Sphere sphMesh = new Sphere(32, 32, 1); |
||||
sphMesh.setTextureMode(Sphere.TextureMode.Projected); |
||||
sphMesh.updateGeometry(32, 32, 1, false, false); |
||||
TangentBinormalGenerator.generate(sphMesh); |
||||
|
||||
sphere = new Geometry("Rock Ball", sphMesh); |
||||
sphere.setLocalTranslation(0, 5, 0); |
||||
sphere.setMaterial(mat); |
||||
sphere.setShadowMode(ShadowMode.CastAndReceive); |
||||
rootNode.attachChild(sphere); |
||||
|
||||
|
||||
|
||||
|
||||
DirectionalLight dl = new DirectionalLight(); |
||||
dl.setDirection(new Vector3f(0, -1, 0).normalizeLocal()); |
||||
dl.setColor(ColorRGBA.White); |
||||
rootNode.addLight(dl); |
||||
|
||||
AmbientLight al = new AmbientLight(); |
||||
al.setColor(ColorRGBA.White.mult(0.7f)); |
||||
rootNode.addLight(al); |
||||
//rootNode.setShadowMode(ShadowMode.CastAndReceive);
|
||||
|
||||
createballs(); |
||||
|
||||
final PssmShadowRenderer pssmRenderer = new PssmShadowRenderer(assetManager, 1024, 4); |
||||
viewPort.addProcessor(pssmRenderer); |
||||
//
|
||||
// final PssmShadowFilter pssmRenderer = new PssmShadowFilter(assetManager, 1024, 4);
|
||||
// FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
|
||||
// fpp.addFilter(pssmRenderer);
|
||||
// viewPort.addProcessor(fpp);
|
||||
|
||||
pssmRenderer.setDirection(dl.getDirection()); |
||||
pssmRenderer.setLambda(0.55f); |
||||
pssmRenderer.setShadowIntensity(0.55f); |
||||
pssmRenderer.setCompareMode(CompareMode.Software); |
||||
pssmRenderer.setFilterMode(FilterMode.PCF4); |
||||
//pssmRenderer.displayDebug();
|
||||
|
||||
inputManager.addListener(new ActionListener() { |
||||
|
||||
public void onAction(String name, boolean isPressed, float tpf) { |
||||
if (name.equals("display") && isPressed) { |
||||
//pssmRenderer.debugFrustrums();
|
||||
System.out.println("tetetetet"); |
||||
} |
||||
if (name.equals("add") && isPressed) { |
||||
createballs(); |
||||
} |
||||
} |
||||
}, "display", "add"); |
||||
inputManager.addMapping("display", new KeyTrigger(KeyInput.KEY_SPACE)); |
||||
inputManager.addMapping("add", new KeyTrigger(KeyInput.KEY_RETURN)); |
||||
} |
||||
int val = 0; |
||||
|
||||
private void createballs() { |
||||
System.out.println((frames / time) + ";" + val); |
||||
|
||||
|
||||
for (int i = val; i < val + 200; i++) { |
||||
|
||||
Geometry s = sphere.clone().clone(false); |
||||
s.setMaterial(mat); |
||||
s.setLocalTranslation(i - 30, 5, (((i) * 2) % 40) - 50); |
||||
s.setShadowMode(ShadowMode.CastAndReceive); |
||||
rootNode.attachChild(s); |
||||
} |
||||
if (val == 300) { |
||||
//stop();
|
||||
} |
||||
val += 1; |
||||
time = 0; |
||||
frames = 0; |
||||
} |
||||
float time; |
||||
float frames = 0; |
||||
|
||||
@Override |
||||
public void simpleUpdate(float tpf) { |
||||
time += tpf; |
||||
frames++; |
||||
if (time > 1) { |
||||
//createballs();
|
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue