PDA

View Full Version : Need help with 2D Shadows. They're a bit off.



somners
12-22-2014, 02:56 PM
First, I'm very new to OpenGL, so I probably break a lot of convention (please point these out if you see any :) )

Secondly, I'll explain the process I'm going through here, then show some code, then images.

1) draw my scene normally

2) draw everything to a framebuffer that casts shadows (creates an occlusion map). the framebuffer stores the depth in the red variable

3) make a shader pass that calculates the angle between each fragment and the light origin point. it then checks the occlusion map to see if it is a shadow caster, if it is write to shadow map this distance at the calculated angle. shadow map is a 360x1 texture.

4) then finally, we draw to the screen with a fragmet shader. get the fragments angle to the light source, get the distance from the shadow map, if distance is equal to or greater than the distance in the shadow map, draw.

I"ll only show the shadow map and drawing of light shaders (unless otherwise requested):

shadowmap shader:


#version 430 core
#define PI 3.1415926

uniform vec2 screenSize;
uniform mat4 MVP;
uniform vec3 _light_position;

layout(location = 0) out vec4 color;

layout(binding = 0, r16f) uniform readonly image2D _occlusion_map;
layout(binding = 1, r32f) uniform image2D _shadow_map;
layout(binding = 2, r32f) uniform image2D _distance_map;
void main()
{
ivec2 destination_coordinates = ivec2(1,0);
ivec2 current_coordinates = ivec2(gl_FragCoord);
vec2 size = screenSize;

float angle = atan((gl_FragCoord.y - _light_position.y), (gl_FragCoord.x - _light_position.x)) / PI;
angle = (angle * .5 + .5) ;
destination_coordinates.x = int(round(angle*360));

memoryBarrier();
float is_occluder = imageLoad(_occlusion_map, ivec2(current_coordinates)).r;
memoryBarrier();

float depth = 0;

if (is_occluder > 0)
{
depth = distance(_light_position.xy, gl_FragCoord.xy);
}

memoryBarrier();
float cur_depth = imageLoad(_distance_map,destination_coordinates).r ;
memoryBarrier();

if (cur_depth > 0)
{
if (depth > 0)
{
depth = min(cur_depth, depth);
}
else
{
depth = cur_depth;
}
}

memoryBarrier();
color = vec4(1,0,0,1);
imageStore(_distance_map, destination_coordinates, vec4(depth,0,0,1));
memoryBarrier();


if (is_occluder == 0 ){
color = vec4(-1,0,0,0);
}
}


shadow drawing shader:


#version 430 core
#define PI 3.1415926

uniform vec2 screenSize;
uniform vec3 _light_position;
layout(location = 0) out vec4 color;

layout(binding = 0, r32f) uniform readonly image2D _distance_map;
void main()
{
ivec2 destination_coordinates = ivec2(1,0);
ivec2 current_coordinates = ivec2(gl_FragCoord);
vec2 size = screenSize;

float angle = atan((gl_FragCoord.y - _light_position.y), (gl_FragCoord.x - _light_position.x)) / PI;
angle = (angle * .5 + .5);
destination_coordinates.x = int(round(angle*360));

memoryBarrier();
float depth = imageLoad(_distance_map, ivec2(destination_coordinates)).r;
memoryBarrier();
float cur_depth = distance(_light_position.xy, gl_FragCoord.xy);

if (depth < cur_depth && depth != 0)
{
color = vec4(0,0,0,.5);
}
else if (cur_depth >= 200)
{
color = vec4(0,0,0,.5);
}
else
{
color = vec4(0,0,0,0);
}
}




As you can see, my method, 'kind of' works. But the shadows aren't drawn in some pixels that they are supposed to.

somners
12-22-2014, 02:59 PM
The WHole Scene:
http://i.imgur.com/0jdVrul.png

Occlusion Map:
http://i.imgur.com/w6ASu9D.png

ShadowMap:
http://i.imgur.com/PAReUBx.png

dorbie
12-24-2014, 05:53 AM
Any occlusion map that just shows occluders and not distance to nearest occlusion is going to introduce a sampling nightmare when detecting actual occlusion. Occlusion maps should not draw occluders but occlusion or distance or at the very least your shadow map should but I don't see it anywhere. In your case you want a radial projection onto a map storing distance from light. So render your scene with distance from light and compare with nearest occlusion from light. Your shadow map should be a 1D radial map texture storing nearest occluder from light that you compare to distance from light without iterating samples. You have a very constrained case, it's quite simple.