3

I have an issue with shadows cast by object really far away from the light source. I am using the depth map approach for rendering shadows in my Solar System simulation. The sun is a point light source and I would like to observe the shadow of the moon on the earth. But since the moon is a really tiny object relative to the distance between it and the sun and since the depth map resolution is limited, the presence of the moon and earth are ignored when rendering the depth cube map texture.

Solar System Depth Map:

enter image description here

You can see that even with the size of the moon exaggerated, it only leaves a small footprint on the depth cube map. With this big of a moon, the eclipses do work but once i shrink the moon to its actual size it is no longer rendered in the depth map and because of that, no longer taken into account for shadow calculations. I am using a 4096 X 4096 texture. Is there a way to solve this problem or is my approach doomed to fail? Any help would be much appreciated.

Grupa
  • 41
  • 5
  • 1
    Are you sure that depth maps are a good approach for shadows in such a scene? Since you have a tiny number of tiny objects, shadow volumes may suit you better. – lisyarus Mar 11 '19 at 13:31
  • I am not sure its the best approach. That's why I am asking. Shadow Mapping is the only approach I know. – Grupa Mar 11 '19 at 13:33

1 Answers1

6

There is a crucial observation to make: when you look up close at earth you, probably, don't care about shadows on mars. Therefore, instead of using a cube-map to shadow map the entire solar system, use a planar shadow map to cover only the near-earth region.

With a 4096x4096 depth map and distance to moon of 384000 km, you get a resolution of ~100km per texel and the moon will take up a disk of ~20 texels in radius on the shadow map.

There is, however, a better approach. Since planets and moons are approximately spherical and there are just a handful of them, you can simply do ray-sphere intersections per fragment to calculate the shadows. It's possible to calculate the angular area of the intersection between the moon and the sun disks in order to get real-time umbra/penumbra rendering. Here is a function that approximates the shadow factor in the shader:

float soft_shadow(vec3 light, float light_radius,
    vec3 occluder, float occluder_radius, vec3 fragment)
{
    vec3 v0 = light - fragment;
    vec3 v1 = occluder - fragment;

    float R0 = length(v0);
    float R1 = length(v1);

    float a0 = light_radius/R0;
    float a1 = occluder_radius/R1;

    float a = length(cross(v0, v1))/(R0*R1);
    a = smoothstep(a0 - a1, a0 + a1, a);
    return 1 - (1 - a)*pow(a1/a0, 2);
}

Here 0.0 means full shadow, 1.0 means no shadow at all. The light, occluder and fragment are the locations of the sun, moon and the fragment in the non-projective space, whereas light_radius and occluder_radius are the radii of the sun and the moon.

For realistic dimensions this code gives me these images:

If I decrease the size of the sun by half, I get these:

Yakov Galka
  • 70,775
  • 16
  • 139
  • 220
  • 2
    Since I had to lay off this project for a while I forgot to tell you how much of a tremendous help you've been. I am pretty new and I have spent an embarrassing amount of time trying to figure out an accurate enough solution for my problem. I know that perhaps you gave me what might seem like a trivial calculation but I just wanted to let you know that this has proved most useful for me and I am truly grateful for your time. – Grupa Mar 21 '19 at 10:35
  • I'm trying to implement this but something is not working and I get no visible results. With *non-projective space* do you mean the fragment in world coordinates (Can the gl_FragCoord constant be used in the fragment shader)? Am I using the results correctly when I multiply it with my current light vec3 that I've calculated using the Phong model? – Jesper Oct 16 '22 at 16:16
  • non-projective: M (world space) or MV (camera space) but not MVP (clip space) and not gl_FragCoord (device coordinates). gl_FragCoord is not a constant. For best results I'd use MV. For the rest please ask a separate question that includes your code. The comments section is not appropriate for helping you with debugging your code. – Yakov Galka Oct 17 '22 at 04:01