Directional light(sun) penetrates model from the backside

Hi all,

I am trying to make a sunrise/sunset effect, but the directional light penetrates the model from the backside. So I need your helps to deal with it.

My system is Fedora 32, master Panda3D, master Simplepbr, master blend2bam, Blender 2.8. Everything else works very well. The model (terrain) you see on this picture is just one single static mesh, with a very basic material and a very basic texture, nothing more. The shadow effect of simplepbr is on, and it works very well. The shadow caster is the directional light (the sun), it works very well because I set up the frustum and the shadow mapping size very carefully.

The only problem is that, when the sun going below the horizon, it slightly penetrates from the backside of the terrain model, as you can see in the picture. I have tried something but most of them doesn’t help to fix the issue:

Solidify the terrain model – Doesn’t help.

Made a plane under the terrain to block the sun – Doesn’t help.

terrain.set_two_sides(True) – Doesn’t help

sun.set_color(0) after sunset – It helps a little, but I don’t like this way, because it also disables the beautiful sunset twilight effect when the sun just slightly below the horizon. And also, sometime if my character (camera) stands beside a high mountain, the directional light penetrates the mountain too, even if the directional light’s angle is 30 degrees from the horizon like 10 o’clock in the morning. I certainly do not want to sun.set_color(0) at daytime.

I added a picture here to show that even if the directional light (sun) is above the horizon, it sometime still penetrates the mountain terrain.

So any helps or advices are deeply appreciated!

An updates:

Looks like it is all about the metal roughness number of the model. If I turn the metal roughness to a higher number, it looks much better. But I don’t think this should be a good solution too, because maybe sometime I need a shiny terrain surface like an iced lake.

So I really need your help and advice about how I could set up my codes to avoid or reduce this problem. Thank you very much again.

I thing your problem is that your shadow map does not cover your scene properly. Could you check, using bufferViewer or modifying the SimplePBR shader to output only the shadow value, that the area where you see the artefact is properly covered by the shadows ? (It’s not clear from your screenshot that there is actually a shadow over)

SimplePBR, like several PBR shaders I’ve looked at, does not clamp the output pixel color to (0, 0, 0) when N dot L < 0 (i.e. when the source light direction is below the surface) but instead clamp the value of the vector parameters to 0 (e.g. NdotL, VdotL, …). SimplePBR goes a bit beyond and clamp the values not to 0 but to 0.001, and also takes the abs value of NdotV, which I think could be the root cause of what you see (Though you should not see it anyway due to the surface self-shadowing).

Hello eldee,

Thank you so much for your reply. I turned on the bufferViewer, and made a video for it.

http://5.2.75.224/static/webup-2020-06-22-100946-screencast-from-2020-06-22-060703-am.webm

From this video, I think we can actually see that the shadow is working, but I don’t know if it really properly covers this area. (It does not cover a big area though because I set the frustum smaller.) Can you please take a look?

Thank you so much again for your help!

Ah, it looks like you’ve got shadow acne on the terrain; so some parts get no longer covered by the shadow and the specular artefacts become visible. You should apply a bias or use backface culling to solve it (or at least diminish the visual impact). Note that to see the problem (and solve it), it’s better to use a uniform bright color for the mesh (for example a saturated red) and disable all other light sources. Even better, use a debug shader to only output the shadow value.

(Btw, the specular artefacts look quite bright to me, something I would see with a more classical Phong specular. Maybe check also that simplepbr is applied on the terrain too)

I do not really understand about this, because I think Panda3D already turned on Backface culling defaultly to every model. So, I think you mean something else. Do you have any resource for me?

haha, I actually did turn up specular and reduce roughness to make it brighter to see.

Panda does indeed enable reverse culling already on shadow cameras. However, this is nullified if your model is double-sided. You should make sure your terrain is single-sided and does not use the solidifier modifier.

You should also make sure that the near/far clips of the camera are as tight as you can make them. Also see:

Hello rdb,

thank you for your help.

Yes, my terrain is single-sided and has no solidifier. I cannot see it if I put the camera underground.

I think when you said the “camera”, you mean the light’s camera right? My scene and project design are very different from your example, but I already try some similar ways to reduce the near/far clips.

I am now thinking about another way. Is it possible to cast a ray like the bullet’s world.ray_test_closest() to detect the backside of the terrain? Be like

if ray_hit_backside:
    sun.set_color(0)

If I remember correctly, you can use setDepthOffset(x) on your model to apply a bias, try -2 as a start.

I guess that’s only a convoluted way to set the sun colour when the angle between the normal and the light direction is greater than 90° :slight_smile:
If the shadow bias or frustum adjustment does not work, maybe it’s easier to modify simplepbr and add a check on ndotl > 0 in the fragment shader ?

I will try the depth offset first and see how it go.

After trying all of these ways: set depth offset, adjusted the frustum to a more plausible size, set_color based on the sunset time, it finally became slightly better. The penetrated specular artefacts is not very obvious now, but sometime still can see a little bit.

So maybe my next step will be taking a look at the simplepbr.

Hi, I think it still has some issues. I think I should not be able to see anything at the frontside if the directional light is casting from the backside of an object, even if I turn off the shadow. However, I still can see the specular artifact even if there is no shadow at all.

Video: http://5.2.75.224/static/webup-2020-06-22-232605-screencast-from-2020-06-22-072059-pm.webm

In this video, I turned off all the shadow, removed the ambient light, removed the texture from the terrain, only plain green color. As you can see, the directional light lit up the house as what we expect, the front face of the house the bright, and the back face is dark. However, for the ground, although the surface is dark, we still can see the specular artifacts.

I don’t think there is anything to do with the shadow anymore at this time, so how can I solve or at least reduce this issue?

Any advices and helps are so much appreciated! Thanks again!

I had some time today to recreate your setup will a simple card geom. I can confirm the problem is due to the clamp values used by simplepbr when calculating N.L and N.V.

With the default simplebr I have artefact with a surface with a very low roughness when the light is 1° below the surface :

If I clamp the value to 0.0, the artefact disappear :

I will submit a PR to fix this.

Isn’t this simply due to the Fresnel effect?

That’s what i thought at first, but in my test the light direction is actually coming from under the surface, the dot product of the surface normal and the light direction is negative, so there shouldn’t be any lighting at all on the surface.

The current clamp value may be small, but with smooth surface it still gives some light reflection

Hi eldee,

Thank you so much for your help. After changing N.L N.V clamp value to 0, it works as what I expect.