PDA

View Full Version : Shadow Mapping. Strange effect



Asmodeus
07-04-2015, 01:11 PM
Hello , i am noticing this strange effect after i created the shadow mapping for my engine. The shadows map perfectly onto the terrain. But it seems like the shadows are mapping onto the objects as well.
Here is the screen shot from my engine , i will apply some basic code that i am using. Also i am using PCF smooth shadows. Also from the screen shot on the depth texture you can notice that it looks like the bricks plane is "over" the tree (meaning the bricks are closer to the camera but that is not true .?!) I assume that this glitch has to do with the sequence of the objects that are rendered.

Vertex Shader


worldPosition = modelMatrix * vertex;
ShadowCoords = mProjection_Shadow * mView_Shadow * worldPosition;


Fragment Shader


float shadow_amt = 1.0;
float bias = (1.0 / SHADOW_MAP_RESOLUTION) * SHADOW_MAP_BIAS;
vec3 scoords = ShadowCoords.xyz / ShadowCoords.w) * 0.5 + 0.5;
shadow_amt = clamp(linearShadowMappingPCF(shadowMap,scoords.xy, (scoords.z - bias)), 0.6 , 1.0);


1914

EDIT: Obviously i am dumb , the problem was solved , simple thing i have over looked.

Asmodeus
07-06-2015, 05:15 AM
I did Not Want to make a new Thread. So i would like to post my Question in my old Thread from the other day.
I got shadow Mapping working perfectly. But now i am facing the problem of the shadow map being static. What i mean by that is that the "light" looks at exact same location each and every frame. If i have a "player" model which can move , he moves outside the view frustrum and shadows are no longer casted because the "light" does not look at that direction.

My Question is how would i make the "light" view matrix follow the camera all the time. Here is my current proj and view matrices for the light. As you can see the view is looking at the same static point in the world (the origin 0,0,0).


this->ShadowProjectionMatrix = glm::ortho<float>(-300, 300, -300, 300, -500, 100);
this->ShadowViewMatrix = glm::lookAt<float>(vec3(1,1,1), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));

Dark Photon
07-06-2015, 07:29 PM
My Question is how would i make the "light" view matrix follow the camera all the time.
Having the light where the camera is all the time won't be too useful - shadows will always be behind objects from the vantage point of your camera.

OTOH, if you want your light to be always at a fixed orientation/translation offset from the camera, just do that. Then compute your light's viewing transform (mView_Shadow) accordingly for the new light position. You'llalso need to adjust the light projection (mProjection_Shadow) so that it encompasses all the shadow casters that cast into your camera's scene.

Asmodeus
07-07-2015, 02:05 AM
Having the light where the camera is all the time won't be too useful - shadows will always be behind objects from the vantage point of your camera.

OTOH, if you want your light to be always at a fixed orientation/translation offset from the camera, just do that. Then compute your light's viewing transform (mView_Shadow) accordingly for the new light position. You'llalso need to adjust the light projection (mProjection_Shadow) so that it encompasses all the shadow casters that cast into your camera's scene.

I think you have misunderstood me. My idea was to have the light camera pointing to the player(or to some specified target). Then this target will be the actual target in glm::lookat , and the position will be target.pos + orthobox.size/2 this way the player will stay at the center of the ortho box no matter where he goes. and the light will always light everything around him
Simple example


vec3 position = targetPosition + vec3(orthosize/2, orthosize/2, orthosize/2) * lightDir;
ShadowViewMatrix = glm::lookAt<float>(position, targetPosition, glm::vec3(0, 1, 0));


I tried this technique, the player does indeed stand in the center of the box, but i notice strange shimmering of the shadows. Probably because the movement is uneven. So I should increment the movement by world space texel size ? The problem is how do i get it ?

GClements
07-07-2015, 04:12 AM
I tried this technique, the player does indeed stand in the center of the box, but i notice strange shimmering of the shadows. Probably because the movement is uneven. So I should increment the movement by world space texel size ? The problem is how do i get it ?
You should translate in multiples of a shadow-map pixel to prevent the shadows from "crawling". Rather than trying to do this with glm::lookAt, I suggest either modifying the glm::ortho parameters or adding a glm::translate between the lookAt and the ortho.

Asmodeus
07-07-2015, 04:42 AM
Yea. The code snippet from my last post is how the position gets updated each frame when the target moves, the look at gets reconstructed. So shouldn't i just add(+) pixel size to position.x / .y / .z before i construct the look at?

EDIT: Another problem i have, but ignored for a while is that i somehow i can not create a square shadow map resolution. If i try to make the shadow map 1024 by 1024 the shadow wont map correctly , but if the resolution of the shadow map is WINDOW_WIDTH and WINDOW_HEIGHT it does work.

GClements
07-07-2015, 05:32 AM
Yea. The code snippet from my last post is how the position gets updated each frame when the target moves, the look at gets reconstructed. So shouldn't i just add(+) pixel size to position.x / .y / .z before i construct the look at?
The translation should be specified in "screen" space (after the glm::lookAt rotation), rather than in world space. To use a world-space translation, you'd need to inverse-project one pixel translations in X and Y from screen space back to world space.


EDIT: Another problem i have, but ignored for a while is that i somehow i can not create a square shadow map resolution. If i try to make the shadow map 1024 by 1024 the shadow wont map correctly , but if the resolution of the shadow map is WINDOW_WIDTH and WINDOW_HEIGHT it does work.
Did you remember to call glViewport() when using the shadow map framebuffer? The first time a context is bound to a rendering surface (e.g. window), the viewport is automatically set to the bounds of the surface. But after that it remains fixed unless changed explicitly.

Asmodeus
07-07-2015, 05:49 AM
The translation should be specified in "screen" space (after the glm::lookAt rotation), rather than in world space. To use a world-space translation, you'd need to inverse-project one pixel translations in X and Y from screen space back to world space.


Did you remember to call glViewport() when using the shadow map framebuffer? The first time a context is bound to a rendering surface (e.g. window), the viewport is automatically set to the bounds of the surface. But after that it remains fixed unless changed explicitly.

You got me , sometimes i just dive into asking before even looking , i was missing glViewport i just added it seconds ago and came here to edit my last edit.

Currently i am here - snapping the texel size and going to shadow's/light's space


float worldTexelSize = (orthoBoxSize) / (float)SHADOW_MAP_RESOLUTION;
screenPos.x = worldTexelSize * floor(position.x / worldTexelSize);
screenPos.y = worldTexelSize * floor(position.y / worldTexelSize);
screenPos.z = worldTexelSize * floor(position.z / worldTexelSize);

screenPos = ShadowProjectionMatrix * screenPos;

Asmodeus
07-10-2015, 10:51 AM
I am still having the problem with the shimmering , i am stuck after finding the texel size and i dont think i quite understand what to do next even after to Shadow Screen pos with Shadow's Projection matrix as GClements purposed. Thanks in advance

GClements
07-10-2015, 02:03 PM
Try:


glm::mat4 proj = glm::ortho(-shadow_w/2, shadow_w/2, -shadow_h/2, shadow_h/2, near, far);
glm::mat4 view = glm::lookAt(glm::vec3(1,1,1), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
glm::mat4 shadow = proj * view;
glm::vec4 spos = shadow * glm::vec4(world_pos, 1.0);
glm::vec2 off = -glm::round(glm::vec2(spos));
glm::mat4 offset = glm::translate(glm::mat4(1.0), glm::vec3(off, 0.0));
this->ShadowMatrix = offset * shadow;

where shadow_w and shadow_h are the size of the shadow map in texels, and world_pos is the world-space position that should be in the centre of the shadow map.

Asmodeus
07-10-2015, 02:55 PM
Great thanks , i will try ASAP. One Question tho' , since shadow_w is the size of the shadow map , in my case 1024 x 1024 , so the ortho box size will be 1024/2, testing this, results in poor shadow Quality , currently i am using ortho size 200 which is enought to surround the player, the terrain and the entities around and i am getting nice Shadow Quality. Ortho Box with size of 512 gives some peter-panning and low shadow Quality overall.

GClements
07-10-2015, 04:32 PM
Try:
Sorry, ignore that. Try this:


glm::mat4 proj = glm::ortho(-shadow_w/2, shadow_w/2, -shadow_h/2, shadow_h/2, near, far);
glm::mat4 direction = glm::lookAt(glm::vec3(1,1,1), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
glm::mat4 view = glm::scale(glm::mat4(1.0), glm::vec3(scale_x, scale_y, 1.0)) * direction;
glm::vec4 spos = view * glm::vec4(world_pos, 1.0);
glm::vec2 off = -glm::round(glm::vec2(spos));
glm::mat4 offset = glm::translate(glm::mat4(1.0), glm::vec3(off, 0.0));
this->ShadowMatrix = proj * offset * view;

The main change is that the offset is calculated and applied before the ortho projection. Also, a scaling has been added; adjust scale_x and scale_y to control the world-space size of the shadowed area.

In any case, the key point is that you need a coordinate system where a shift of one unit in x or y corresponds to a shift of one texel in the shadow map.

Asmodeus
07-11-2015, 12:17 AM
Greatly appreciate, worked like charm , clean and understandable explanation and took me less than a minute to implement that in my project. Thanks again.

EDIT: One problem i am noticing is that if i walk too much in any direction, the player does follow the center of the ortho box , but he gets clipped (even when in the center) if i crank up the far/near planes it does get better but still gets clipped after some time again