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.
-
draw my scene normally
-
draw everything to a framebuffer that casts shadows (creates an occlusion map). the framebuffer stores the depth in the red variable
-
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.
-
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.