question was re-written to better explain the problem

I have a scene of big thin parallelepiped, small cube, and a light source, all aligned on Y axis, like so:

| |
| |----[ ]----Light

Both objects are static and light is sliding on Y axis only.

Also, a tiny (32x32) depth texture from Light's PointOfView is being rendered off-screen and then applied to both cube and parallelepiped on on-screen rendering stage, making effect of a shadow being casted by a small cube on a big parallelepiped.

The problem i am experiencing is that when light moves away from cube, such low-res depth texture is getting updated only 6-7 times, but it's projection on surfaces updates constantly and wrongly: while shadow is supposed to shrink when lightsource moves away and grow when lightsource moves closer, it is in fact doing the reverse between updates of texture projection! In other words, between two updates of texture, it's projection on a parallelepiped grows when light moves away and shrinks when light moves closer and then "jumps" when texture updates, which is looking very wrong.

To better show the problem, i've made this video: http://www.youtube.com/watch?v=XOraTZimmUU (the square in right-upper corner is the depth texture, made from light's POV). As you can see, at first i am moving light out (decresing negative Y) and you can notice projection growing between "jumps" of texture updates. Then i am moving light in and you can notice projection shrinking between the same "jumps".

My question is: how to reverse this shrinking-growing behavior without increasing shadowmap texture resolution (which only make problem less noticable, but not completly solved)?

Shaders used to map texture on:


#version 120
struct light_t {
  vec3 spot_dir;
  vec3 position;
  mat4 MVP;
  mat4 V;
  mat4 P;
attribute vec4 in_position;
uniform mat4 MVP;
uniform mat4 M;
uniform mat4 V;
uniform mat4 P;
uniform light_t light;
varying vec4 shadowcoord;
void main() {
  gl_Position = MVP * in_position;
  mat4 bias = 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);
  shadowcoord = bias * light.MVP * in_position;


#version 120
varying vec4 shadowcoord;
uniform sampler2D shadowmap;
void main() {
  vec4 color = vec4(0.5);
  float factor = 1.0;
  float z = texture2DProj(shadowmap, shadowcoord.xyw).z;
  if (z < (shadowcoord.z-0.0005)/shadowcoord.w) factor = 0.2;
  gl_FragColor = factor * color;

The full self-contained source of minimal (~900 lines, meh) example (extracted from full-scale project) is here (glm math library, C++ compiler and glut is needed):

Compile line:

g++ -g -o example main.cpp  -lGL -lGLU -lglut -lGLEW

Actual source: http://paste.eientei.org/show/287/

WebGL playground: webglplayground.net/saved/NAfoKmQqJb

  • \$\begingroup\$ Should lights[1].MVP be lights[i].MVP ? \$\endgroup\$ – Lachlan Easton Aug 14 '13 at 2:43
  • \$\begingroup\$ yes, thanks for noticing, but this is not really the issue, as in search for problem i resorted to using only light #1, with shadowmap #1, as you can see in fragment shader. \$\endgroup\$ – Alexander Tumin Aug 14 '13 at 5:21
  • \$\begingroup\$ Isn't the problem that the shadow map isn't being updated regularly? If you don't update the shadow map, it is as if the cube is being moved with the light, so its shadow on the parallelepiped will grow. \$\endgroup\$ – GuyRT Aug 19 '13 at 16:19
  • \$\begingroup\$ But it is being updated each frame... \$\endgroup\$ – Alexander Tumin Aug 23 '13 at 16:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.