Shadows …again

Hey all.

I committed some changes in lighting and shadows (PSSM only)


  1. I reverted the change announced here http://hub.jmonkeyengine.org/groups/development-discussion-jme3/forum/topic/transparency-and-shadows-possible-breaking-change/

    I was quite disappointed to do it, because it took me a lot of time when i did it. The reasons are that the AlphaFolloff uses GL_ALPHA_TEST and GL_ALPHA_FUNC that are deprecated in opengl 3. Worst…those attributes don’t exists in OpenglES 2.0.

    The reason of the deprecation is that discarding transparent pixel should now be done in the pixel shader with an alpha test and a discard call…that’s precisely what the AlphaDiscardThreshold was doing…so i put it back in.

    Also Shadow blending is back to modulate that is more conventional. (i had to set it to alpha for the change)

    I apologize to all of you that have proper shadow shader that made the change ( @androlo and @thetoucher). guys i may have break again your shadows.

    But that’s for a greater good…


  2. I added a new filtering algorithm PCFPOISSON. The idea is to use classic PCF filtering but instead of using a grid kernel, use a 12 tap poisson disk. You can google that up because i won’t get too much into the details, but the idea is to make 12 ‘random’ fetches instead of 4x4 aligned for PCF4 and 8x8 for PCF8. This result in an irregular penumbra that is softer to the bare eye than regular PCF…with better performances (12 fetches instead of 16 and 64).



    Here are some shots with all the filtering available. For each filtering I made a shot with a plain colored ground and with a textured ground.

    Note that on the textured ground the PCFPOISSON and PCF8 looks very similar, but PCFPOISSON is a lot faster.

    Also it’s not the case on the screen shot but from all the tests PCFPOISSON has slightly better performances than PCF4.

    The images are full resolution with no compression so the penumbra are not altered.

    http://i.imgur.com/WCA1I.jpg

    http://i.imgur.com/2UHdm.jpg


  3. fixed the hardcoded shadow map size in pssm shadow shader for GLSL 1.0. Thanks to @t0neg0d for finding this. Also passing it as a define made the shader slightly faster too.


  4. Added a small poly offset to the post shadow pass to fix shadow acne issues that some users ran into (thinking of @yezu, @lostgamer66 and @oxplay2 ). could you guys test if it fixed your issue.



    And that’s pretty much it.
1 Like

Cool. Very excited about the new filtering. Wonder how it affects the “flickering” when you move around. Have you noticed any difference (more/less/the same)?

Awesome stuff!

@androlo said:
Cool. Very excited about the new filtering. Wonder how it affects the "flickering" when you move around. Have you noticed any difference (more/less/the same)?


This is the same dithering technique I used (minus the hard-coded poisson disk). It won't make a difference in the flickering, as this is caused by the shadow map being stretched. If it is large area flickering you are talking about... it's because the shadow map is hitting a point on the scene between pixels in the depth map. The noise filter bias helps with this slightly... but no depth is still no depth.

Sorry again... last edit. I just wanted to mention why I changed the the dithering technique at all... the poisson disk (if you look at the picture) keeps a defined line at the edge of the shadow, which (imo) looks unnatural. By removing that and using a slightly modified way to limit how far your random sample is taken from, you produce a nicer looking edge to the shadow.

Eh... sorry for the edit... this part is for @nehon

What solutions are out there for the "between pixels in the depth map" issue? I really struggled with this when trying to fix it. The solution I came up with was a fall back plan that I wasn't overly thrilled with.
@androlo said:
Cool. Very excited about the new filtering. Wonder how it affects the "flickering" when you move around. Have you noticed any difference (more/less/the same)?

Flickering is the same as any other PCF. For this i itend to try the temproal reprojection @EmpirePhoenix talked about in an earlier post.

@t0neg0d said:
Sorry again... last edit. I just wanted to mention why I changed the the dithering technique at all... the poisson disk (if you look at the picture) keeps a defined line at the edge of the shadow, which (imo) looks unnatural. By removing that and using a slightly modified way to limit how far your random sample is taken from, you produce a nicer looking edge to the shadow.

I don't find a define line edge, no more than with PCF8. How do you fetch your samples?

@t0neg0d said:
What solutions are out there for the "between pixels in the depth map" issue? I really struggled with this when trying to fix it. The solution I came up with was a fall back plan that I wasn't overly thrilled with.

I don't get what is the "between pixels in the depth map" issue.
@nehon said:
I don't get what is the "between pixels in the depth map" issue.


When projecting a shadow map... there are a multitude of areas (especially on rounded surfaces) that are not part of the depth map, are not behind a depth in the depth map, but ARE part of the rendered scene. How shadows end up being stretched across these areas is erratic and can cause flickering (which I am fairly sure is what @androlo was referring to).

@nehon said:
For this i itend to try the temproal reprojection @EmpirePhoenix talked about in an earlier post.


This will not work... for the reason I gave him in that post.

@nehon said:
I don’t find a define line edge, no more than with PCF8.


I'm not sure what to tell you... it's there... and easy to see... just compare it to the PCF8 shot beside it. It's not just kinda there... it's THERE :) The PCF8 fades to a lighter color constantly... the poisson seems to ramp back towards a darker shadow right at the end of the shadow line. I still think the basic idea behind this is a good one (the random samples and limiting the range you sample from)... it (imo) gives great results at as little as 2 samples.
@t0neg0d said:
When projecting a shadow map... there are a multitude of areas (especially on rounded surfaces) that are not part of the depth map, are not behind a depth in the depth map, but ARE part of the rendered scene. How shadows end up being stretched across these areas is erratic and can cause flickering (which I am fairly sure is what @androlo was referring to).

Ok i see what you are talking about, and that's not what androlo means. He means temporal aliasing. Moving the camera or shadow caster makes the penumbra flicker.
You are talking about the bleeding of the shadow maps on rounded lighted surfaces. this is due to the fact the shadow map pixels are not aligned with the receiver. And it's un-avoidable on round surfaces. The filtering makes it even worse and the wider your penumbra is the worst the effect.

@t0neg0d said:
This will not work... for the reason I gave him in that post.

Well...no offense but I doubt you're right.... He just made a quick and dirty test, and his way of doing it may produce the effect. But he proved that the technique is valid IMO.
Did you read the paper he linked in the mentioned post? The aim of all this is to have pixel accurate shadows and eliminate as much as possible temporal aliasing. They don't store the 12 previous screen space shadow map they store the stacked shadow amount of the pixel since the beginning in one texture. Also they have a confidence factor to help determine if the pixel is more likely to be shadowed, which result in stable shadows. Then, they have an adjustment factor to make the algorithm converge in 10 to 60 frames. So ultimately, if motion blur effect is noted it can be alleviated with that factor. But they don't mention this effect at all in the draw backs.
Anyway it worth the shot, and this ofc would be optional on the Shadow renderer.

@t0neg0d said:
I'm not sure what to tell you... it's there... and easy to see... just compare it to the PCF8 shot beside it. It's not just kinda there... it's THERE :) The PCF8 fades to a lighter color constantly... the poisson seems to ramp back towards a darker shadow right at the end of the shadow line. I still think the basic idea behind this is a good one (the random samples and limiting the range you sample from)... it (imo) gives great results at as little as 2 samples.

That's the point the penumbra is linear with PCF8, and random with PCF poisson. It has not a better looking as PCF8 obviously. But it's a lot faster and except on bright low frequency textures areas you won't notice the pattern.
It has draw back of course, for example it produce a noisy shadow with very high frequency shadow maps, ( for example in the test transparent shadows with the tree's foliage), But it's still faster...
@nehon said:
Well...no offense but I doubt you're right.... He just made a quick and dirty test, and his way of doing it may produce the effect. But he proved that the technique is valid IMO.
Did you read the paper he linked in the mentioned post? The aim of all this is to have pixel accurate shadows and eliminate as much as possible temporal aliasing. They don't store the 12 previous screen space shadow map they store the stacked shadow amount of the pixel since the beginning in one texture. Also they have a confidence factor to help determine if the pixel is more likely to be shadowed, which result in stable shadows. Then, they have an adjustment factor to make the algorithm converge in 10 to 60 frames. So ultimately, if motion blur effect is noted it can be alleviated with that factor. But they don't mention this effect at all in the draw backs.
Anyway it worth the shot, and this ofc would be optional on the Shadow renderer.


I did read it... and by no means am I saying that it isn't worth a shot...but I think the underlying concept is flawed. If your not moving... this has an interesting effect, but once you incorporate movement... it doesn't do a bit of good aside from adding some extra overhead. The faster the movement, the less likely the shadows will be even remotely close to correct and it is going to lead to all sorts of aftifacting issues that would be nightmarish (i.e. artifacting on areas of the screen that aren't even close to a shadow-- potentially... less likely if we had access to the geometry shader and previous object positions... but eh). No offense, but I doubt this will produce any usable results... unless everyone starts writing games that involve completely stationary game play.

@nehon said:
That's the point the penumbra is linear with PCF8, and random with PCF poisson. It has not a better looking as PCF8 obviously. But it's a lot faster and except on bright low frequency textures areas you won't notice the pattern.
It has draw back of course, for example it produce a noisy shadow with very high frequency shadow maps, ( for example in the test transparent shadows with the tree's foliage), But it's still faster...


That's why I ended up using this approach in both the SSAO filter and the basic shadow renderer I put together... however, I made some slight changes to help alleviate the noticeable edge on the outside of the shadows. It's not that big of deal really... it was a person preference thing for me... you put it over a texture and you would be hard pressed to see what I am talking about... for that matter the *noisiness* this method produces. And I personally think film grain is a post process effect ALL games should have anyways... which would hide any of the noise you might see otherwise. :)

Well i’ll try it anyway and we’ll see.

@t0neg0d said:
I did read it... and by no means am I saying that it isn't worth a shot...but I think the underlying concept is flawed. If your not moving... this has an interesting effect, but once you incorporate movement... it doesn't do a bit of good aside from adding some extra overhead. The faster the movement, the less likely the shadows will be even remotely close to correct and it is going to lead to all sorts of aftifacting issues that would be nightmarish (i.e. artifacting on areas of the screen that aren't even close to a shadow-- potentially... less likely if we had access to the geometry shader and previous object positions... but eh). No offense, but I doubt this will produce any usable results... unless everyone starts writing games that involve completely stationary game play.


Here is a bit more to read, from 2011 "A Survey on Temporal Coherence Methods in Real-Time Rendering" by among other Daniel Scherzer that co-authored the paper from 2007 that the Phoenix referred to (Pixel-Correct Shadow Maps with Temporal Reprojection and
Shadow Test Confidence)
http://www.cse.ust.hk/~psander/docs/tempco.pdf

In the more recent paper they say:
"The authors found out that m should be balanced with camera movement. When the camera moves fast m can be small because noise at the shadow borders is not noticed. Only for a slowly moving camera or a still image are higher values of m necessary. This is motivated by the human visual system, which tends to integrate over motion, thereby allowing for noisier edges when strong movement is present"

I think there is a lot of merit to temporal reprojection of one kind or other, for more than shadows also, some papers say they accelerate other shaders by simply eliminating the need to recalculate fragments that haven't changed.
@jmaasing said:
I think there is a lot of merit to temporal reprojection of one kind or other, for more than shadows also, some papers say they accelerate other shaders by simply eliminating the need to recalculate fragments that haven't changed.

I agree, I read the siggraph presentations you linked the other day, and they refer to it as a state of the art technique.
I mean...temporal reprojection it's not a thesis or something experimental...it is already used in the game industry.

Youare not complelty right, the way i did it yes,

but with a actuall reprojection, you restore the shadows with movement , so only the new shaded pixels are affected with the default uncertainity. Also it might work way faster when not moving to fast, as you are able to determine the pcf kernel based on the confidence faktor.



I’m not sure what other flaws are therer, but i guess it is wort a try, even if we just find out its not workin, thats valuable result. as it will safe others from wastig time.

Nightly throws shadow related exceptions at me…



Java init code:

[java]

PssmShadowRenderer shadow = new PssmShadowRenderer(assetManager, 512, 3);

viewPort.addProcessor(shadow);

[/java]



Thrown exception:

Code:
2012-sep-19 12:30:27 com.jme3.renderer.lwjgl.LwjglRenderer updateShaderSourceData VARNING: Bad compile of: 1 #define FILTER_MODE 1 2 #define HARDWARE_SHADOWS 1 3 #define PCFEDGE 1.0 4 #define SHADOWMAP_SIZE 1024.0 5 #ifdef HARDWARE_SHADOWS 6 #define SHADOWMAP sampler2DShadow 7 #define SHADOWCOMPARE(tex,coord) shadow2DProj(tex, coord).r 8 #else 9 #define SHADOWMAP sampler2D 10 #define SHADOWCOMPARE(tex,coord) step(coord.z, texture2DProj(tex, coord).r) 11 #endif 12 13 #if FILTER_MODE == 0 14 #define GETSHADOW Shadow_DoShadowCompare 15 #define KERNEL 1.0 16 #elif FILTER_MODE == 1 17 #ifdef HARDWARE_SHADOWS 18 #define GETSHADOW Shadow_DoShadowCompare 19 #else 20 #define GETSHADOW Shadow_DoBilinear_2x2 21 #endif 22 #define KERNEL 1.0 23 #elif FILTER_MODE == 2 24 #define GETSHADOW Shadow_DoDither_2x2 25 #define KERNEL 1.0 26 #elif FILTER_MODE == 3 27 #define GETSHADOW Shadow_DoPCF 28 #define KERNEL 4.0 29 #elif FILTER_MODE == 4 30 #define GETSHADOW Shadow_DoPCFPoisson 31 #define KERNEL 4 32 #elif FILTER_MODE == 5 33 #define GETSHADOW Shadow_DoPCF 34 #define KERNEL 8.0 35 #endif 36 37 38 uniform SHADOWMAP m_ShadowMap0; 39 uniform SHADOWMAP m_ShadowMap1; 40 uniform SHADOWMAP m_ShadowMap2; 41 uniform SHADOWMAP m_ShadowMap3; 42 43 uniform vec4 m_Splits; 44 45 uniform float m_ShadowIntensity; 46 47 varying vec4 projCoord0; 48 varying vec4 projCoord1; 49 varying vec4 projCoord2; 50 varying vec4 projCoord3; 51 52 varying float shadowPosition; 53 54 55 const vec2 pixSize2 = vec2(1.0 / SHADOWMAP_SIZE); 56 float scale = 1.0; 57 58 float Shadow_DoShadowCompareOffset(in SHADOWMAP tex, in vec4 projCoord, in vec2 offset){ 59 vec4 coord = vec4(projCoord.xy + offset.xy * pixSize2, projCoord.zw); 60 return SHADOWCOMPARE(tex, coord); 61 } 62 63 float Shadow_DoShadowCompare(in SHADOWMAP tex, vec4 projCoord){ 64 return SHADOWCOMPARE(tex, projCoord); 65 } 66 67 float Shadow_BorderCheck(in vec2 coord){ 68 // Fastest, "hack" method (uses 4-5 instructions) 69 vec4 t = vec4(coord.xy, 0.0, 1.0); 70 t = step(t.wwxy, t.xyzz); 71 return dot(t,t); 72 } 73 74 float Shadow_DoDither_2x2(in SHADOWMAP tex, in vec4 projCoord){ 75 float border = Shadow_BorderCheck(projCoord.xy); 76 if (border > 0.0) 77 return 1.0; 78 79 80 float shadow = 0.0; 81 vec2 o = mod(floor(gl_FragCoord.xy), 2.0); 82 shadow += Shadow_DoShadowCompareOffset(tex,projCoord,vec2(-1.5, 1.5) + o); 83 shadow += Shadow_DoShadowCompareOffset(tex,projCoord,vec2( 0.5, 1.5) + o); 84 shadow += Shadow_DoShadowCompareOffset(tex,projCoord,vec2(-1.5, -0.5) + o); 85 shadow += Shadow_DoShadowCompareOffset(tex,projCoord,vec2( 0.5, -0.5) + o); 86 shadow *= 0.25 ; 87 return shadow; 88 } 89 90 float Shadow_DoBilinear_2x2(in SHADOWMAP tex, in vec4 projCoord){ 91 float border = Shadow_BorderCheck(projCoord.xy); 92 if (border > 0.0) 93 return 1.0; 94 vec4 gather = vec4(0.0); 95 gather.x = Shadow_DoShadowCompareOffset(tex, projCoord, vec2(0.0, 0.0)); 96 gather.y = Shadow_DoShadowCompareOffset(tex, projCoord, vec2(1.0, 0.0)); 97 gather.z = Shadow_DoShadowCompareOffset(tex, projCoord, vec2(0.0, 1.0)); 98 gather.w = Shadow_DoShadowCompareOffset(tex, projCoord, vec2(1.0, 1.0)); 99 100 vec2 f = fract( projCoord.xy * SHADOWMAP_SIZE ); 101 vec2 mx = mix( gather.xz, gather.yw, f.x ); 102 return mix( mx.x, mx.y, f.y ); 103 } 104 105 float Shadow_DoPCF(in SHADOWMAP tex, in vec4 projCoord){ 106 float shadow = 0.0; 107 float border = Shadow_BorderCheck(projCoord.xy); 108 if (border > 0.0) 109 return 1.0; 110 float bound = KERNEL * 0.5 - 0.5; 111 bound *= PCFEDGE; 112 for (float y = -bound; y <= bound; y += PCFEDGE){ 113 for (float x = -bound; x <= bound; x += PCFEDGE){ 114 shadow += clamp(Shadow_DoShadowCompareOffset(tex,projCoord,vec2(x,y)) + 115 border, 116 0.0, 1.0); 117 } 118 } 119 120 shadow = shadow / (KERNEL * KERNEL); 121 return shadow; 122 } 123 124 125 //12 tap poisson disk 126 const vec2 poissonDisk[12] =vec2[12]( vec2(-0.1711046, -0.425016), 127 vec2(-0.7829809, 0.2162201), 128 vec2(-0.2380269, -0.8835521), 129 vec2(0.4198045, 0.1687819), 130 vec2(-0.684418, -0.3186957), 131 vec2(0.6026866, -0.2587841), 132 vec2(-0.2412762, 0.3913516), 133 vec2(0.4720655, -0.7664126), 134 vec2(0.9571564, 0.2680693), 135 vec2(-0.5238616, 0.802707), 136 vec2(0.5653144, 0.60262), 137 vec2(0.0123658, 0.8627419)); 138 139 float Shadow_DoPCFPoisson(in SHADOWMAP tex, in vec4 projCoord){ 140 float shadow = 0.0; 141 float border = Shadow_BorderCheck(projCoord.xy); 142 if (border > 0.0) 143 return 1.0; 144 145 vec2 texelSize = vec2( 4.0 * PCFEDGE * scale); 146 147 shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk[0] * texelSize); 148 shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk[1] * texelSize); 149 shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk[2] * texelSize); 150 shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk[3] * texelSize); 151 shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk[4] * texelSize); 152 shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk[5] * texelSize); 153 shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk[6] * texelSize); 154 shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk[7] * texelSize); 155 shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk[8] * texelSize); 156 shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk[9] * texelSize); 157 shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk[10] * texelSize); 158 shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk[11] * texelSize); 159 160 shadow = shadow * 0.08333333333;//this is divided by 12 161 return shadow; 162 } 163 164 #ifdef DISCARD_ALPHA 165 #ifdef COLOR_MAP 166 uniform sampler2D m_ColorMap; 167 #else 168 uniform sampler2D m_DiffuseMap; 169 #endif 170 uniform float m_AlphaDiscardThreshold; 171 varying vec2 texCoord; 172 #endif 173 174 void main(){ 175 176 #ifdef DISCARD_ALPHA 177 #ifdef COLOR_MAP 178 float alpha = texture2D(m_ColorMap,texCoord).a; 179 #else 180 float alpha = texture2D(m_DiffuseMap,texCoord).a; 181 #endif 182 if(alpha<=m_AlphaDiscardThreshold){ 183 discard; 184 } 185 186 #endif 187 188 189 vec4 shadowPerSplit = vec4(0.0); 190 float shadow; 191 //shadowPosition 192 if(shadowPosition < m_Splits.x){ 193 shadow= GETSHADOW(m_ShadowMap0, projCoord0); 194 }else if( shadowPosition < m_Splits.y){ 195 scale = 0.5; 196 shadow = GETSHADOW(m_ShadowMap1, projCoord1); 197 }else if( shadowPosition < m_Splits.z){ 198 scale = 0.25; 199 shadow= GETSHADOW(m_ShadowMap2, projCoord2); 200 }else if( shadowPosition < m_Splits.w){ 201 scale = 0.125; 202 shadow= GETSHADOW(m_ShadowMap3, projCoord3); 203 } 204 /* 205 shadowPerSplit.x = GETSHADOW(m_ShadowMap0, projCoord0); 206 shadowPerSplit.y = GETSHADOW(m_ShadowMap1, projCoord1); 207 shadowPerSplit.z = GETSHADOW(m_ShadowMap2, projCoord2); 208 shadowPerSplit.w = GETSHADOW(m_ShadowMap3, projCoord3); 209 */ 210 211 /* 212 vec4 less = step( shadowPosition, m_Splits ); 213 vec4 more = vec4(1.0) - step( shadowPosition, vec4(0.0, m_Splits.xyz) ); 214 float shadow = dot(shadowPerSplit, less * more ); 215 */ 216 shadow = shadow * m_ShadowIntensity + (1.0 - m_ShadowIntensity); 217 218 219 gl_FragColor = vec4(shadow, shadow, shadow, 1.0); 220 221 }

2012-sep-19 12:30:27 com.jme3.app.Application handleError
ALLVARLIG: Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main]
com.jme3.renderer.RendererException: compile error in:ShaderSource[name=Common/MatDefs/Shadow/PostShadowPSSM.frag, defines, type=Fragment, language=GLSL100] error:ERROR: 0:126: ‘]’ : syntax error syntax error
ERROR: 0:137: ‘;’ : syntax error syntax error

-_-… let me guess…you have a mac?

yes, a mac with a ATI card :stuck_out_tongue:

Could you try to remove the const modifier before the array declaration?

You do realize that your implementation of poisson isn’t actually random… it’s just a 12 step pattern. You should at least randomize the index your using when referencing poissonDisk. This is probably why there is such a prominent line on the edge of the shadow. If you do this, you’ll probably be able to cut the number of samples down to 4 and get better results than what you’re seeing now.

I do, it’s a random pattern not a random fetch.

To go further you can rotate the poisson disk on each pixel so the pattern is less noticeable, but I must have missed something because it was producing an very irregular penumbra with just a very basic trigonometric formula.

Some use a rotation texture but i didn’t want to delve into this because i have much things to do. also the results were already good enough IMO.

[java]2012-09-19 15:25:52 com.jme3.app.Application handleError

SEVERE: Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main]

com.jme3.renderer.RendererException: compile error in:ShaderSource[name=Common/MatDefs/Shadow/PostShadowPSSM.frag, defines, type=Fragment, language=GLSL100] error:ERROR: 0:125: ‘const 2-component vector of float’ : cannot declare arrays of this qualifier

ERROR: 0:125: ‘const’ : non-matching types for const initializer

ERROR: 0:148: ‘[’ : field selection out of range ‘2’

ERROR: 0:149: ‘[’ : field selection out of range ‘3’

ERROR: 0:150: ‘[’ : field selection out of range ‘4’

ERROR: 0:151: ‘[’ : field selection out of range ‘5’

ERROR: 0:152: ‘[’ : field selection out of range ‘6’

ERROR: 0:153: ‘[’ : field selection out of range ‘7’

ERROR: 0:154: ‘[’ : field selection out of range ‘8’

ERROR: 0:155: ‘[’ : field selection out of range ‘9’

ERROR: 0:156: ‘[’ : field selection out of range ‘10’

ERROR: 0:157: ‘[’ : field selection out of range ‘11’

at com.jme3.renderer.lwjgl.LwjglRenderer.updateShaderSourceData(LwjglRenderer.java:1009)

at com.jme3.renderer.lwjgl.LwjglRenderer.updateShaderData(LwjglRenderer.java:1032)

at com.jme3.renderer.lwjgl.LwjglRenderer.setShader(LwjglRenderer.java:1098)

at com.jme3.material.Material.render(Material.java:1058)

at com.jme3.renderer.RenderManager.renderGeometry(RenderManager.java:509)

at com.jme3.renderer.queue.RenderQueue.renderGeometryList(RenderQueue.java:301)

at com.jme3.renderer.queue.RenderQueue.renderShadowQueue(RenderQueue.java:319)

at com.jme3.shadow.PssmShadowRenderer.postFrame(PssmShadowRenderer.java:467)

at com.jme3.renderer.RenderManager.renderViewPort(RenderManager.java:985)

at com.jme3.renderer.RenderManager.render(RenderManager.java:1023)

at com.jme3.app.SimpleApplication.update(SimpleApplication.java:251)

at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:151)

at com.jme3.system.lwjgl.LwjglDisplay.runLoop(LwjglDisplay.java:185)

at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:228)

at java.lang.Thread.run(Thread.java:662)

[/java]



hehe, for me, it need to have other initializing of “const vec2 poissonDisk[12]”.

you have a mac too?