Shadow not behaving as expected

Hello,

I’m trying to simulate the sun in a scene with a house model to see the how the shadow behaves.

I’ve got a funky shadow at the moment!

weird-shadow

I don’t have an online repro as I don’t know where to upload my gltf file on a service that keeps the extension so that I’m still able to use the loader. If anyone knows of one please let me know and I may try to get a live repro.

Hopefully the pieces of code I’m about to share still help to see more clearly for someone knowing more than me :slight_smile:

For the light, based on what I read, the DirectionalLight seems to be the more appropriate (?).
Here’s what I’ve used:

this.light = new DirectionalLight(
  'sunLight',
  new Vector3(0, -1, -1),
  this.scene
);

The movement you see is just for debugging, I’ve added:

setInterval(() => {
  this.light.position.y -= 0.01;
}, 10);

For the ground I’ve got:

const ground = MeshBuilder.CreateGround(
  'ground',
  { width: 40, height: 40, subdivisions: 2 },
  this.scene
);

ground.receiveShadows = true;

And finally for the loading of the mesh and the shadows I’ve got:

    const mesh = await SceneLoader.ImportMeshAsync(
      undefined,
      './assets/',
      'house-v1.gltf',
      game.getScene()
    );

    const shadowGenerator = new ShadowGenerator(1024, game.getLight());

    mesh.meshes.forEach((m) => {
      shadowGenerator.addShadowCaster(m);
      m.receiveShadows = true;
    });
    shadowGenerator.useExponentialShadowMap = true;

I don’t have anything else fancy in the scene except the ground and the house. How is the shadow behaving as such?

Thanks for any help (and do let me know how to get my mesh somewhere so I can provide a live repro please)

1 Like

See this doc page for some solutions to host the files you want to reference from the Playground.

Something you can try:

  • put this.light.position = new BABYLON.Vector3(0, 8, 8); after creating the light

By default, the position of a directional light is the negated viewDirection vector you pass in, so (0,1,1) in your case. It’s likely that this position is too close of the house (or even inside), and this.light.position.y -= 0.01 will stuck it even more.

Try to use the inspector to debug your shadows. With a directional light, the “Display frustum” switch is of a great help for debugging purpose (see bottom right of the screenshot):

Also, some advices to help debugging shadows:

4 Likes

Thank you so much for the reply, this is fantastic!

I took a look and here’s what I’ve got so far:

So indeed it doesn’t look like it’s going to behave correctly :slight_smile:

I’ll keep digging a bit into that in the next week or so and try to make a minimal repro if I don’t get the expected result! :slight_smile: thanks again!

Actually, I can see the shadow is now behaving correctly! :tada:

But I have no idea why my mesh is so dark.

On the previous picture when the shadow was buggy the mesh color looked better:

image

We could see the shadow more easily. I’ve tried to attach a StandardMaterial to the list of meshes but nothing changes unless I set material.emissiveColor = new Color3(1, 1, 1) which makes the house all white and the shadow isn’t even on it. I’d like a reasonable color so I can distinguish the house and the shadow (especially the chimney one).

On top of that, is there any tweak I can make to the light so that it looks more “realistic” for a day time light? As in, the back face of the house shouldn’t be 100% dark, during day time I can still see the opposite side of my house compared to the sun angle. It’s not pitch dark. As I don’t have anything reflecting toward it in the scene I don’t know if it’s possible to make it look nice while still keeping an accurate shadow :thinking:

1 Like

Try using material.diffuseColor instead.

To lit even the dark side, you can try adding an hemispherical light with a low intensity (0.2 or 0.3).

Well, first I godda say you did a very good debugging on this peculiar topic of using shadows with a directional light. It is not easy to understand at first and making a visual representation is really a smart way to get a better understanding of it.

Yes, fancy, isn’t it? :grinning: What you need to understand here is that the darkness of the shadow uses the emissive. Understand the emissive color ‘emits a color’ that will superseed your shadow. By making a white emissive with a default level 1, you are emitting strong white color against the light/shadow. If you want nice dark shadows while keeping with a realistic lighting effect on your material, you should use an emissiveTexture that is slightly darker than the diffuse (base or albedo) with a dark emissiveColor. You can next play with the emissive*.level to adjust the level of light/shadow. Usually a setting between 0.1 to 0.5 works best (though it depends on your emissiveTexture, the type of material and the desire result).

Of course. Well, I guess your best option is to add a second light to the scene. The directional light alone will only diffuse light in the selected direction. If the light is obstructed from the other side, well… it is :wink: So, adding a ‘global type’ of light to your scene is I believe the way to go. It could be a hemi or a point light.

This goes with the above. Realistic means there’s not just one light source of a certain type. So here again, adding a second and eventually a third light in your scene will help with that. One thing I often do is that I use two shadow generators and three lights. 2 lights cast shadows and one is used for the global (environment) lighting. Here you just need to understand that light only adds to light! :thinking: :wink: This means that when doing this, you should use a lower level intensity on your lights (and adjust them depending on the ambience you want). Also note that for keeping with nice dark shadows, you can 1) use contact hardening shadows 2) set an intensity lower than 0 (i.e. -1) on the light that is just for shadow casting. Though in this case, you will need to compensate by setting a higher intensity on your other light(s).

1 Like

@Evgeni_Popov

I tried it already. I’ve actually tried all of them to see if the following to see if there was a difference: diffuseColor, specularColor, emissiveColor, ambientColor. With Color3(1, 1, 1).

Except for the emissiveColor, where I get it all white as explained (and no shadows), the others don’t change anything at all. And actually, as soon as I set a material, the house goes full black:

But if I don’t set the material at all, it’s dark, but not as much:

Maybe your normals are inverted? Try to display them and see if they are pointing to the right direction:

If you don’t set a material explicitely, you get a standard one automatically, with the diffuse color being a middle grey.

Could you set-up a playground so we can debug it. Without a PG, it’s hard to tell.

@Evgeni_Popov I think the normals are ok:

If you don’t set a material explicitely, you get a standard one automatically, with the diffuse color being a middle grey

yes, I was just trying to say that basically I’ve tried all the possibilities. Apply a material without setting anything on it. Then try setting one by one diffuseColor, specularColor, emissiveColor, ambientColor with Color3(1, 1, 1) and only the emissiveColor had an effect. All the others, didn’t change anything

@mawa

first I godda say you did a very good debugging on this peculiar topic of using shadows with a directional light

Thanks for the kind words! That said, I only followed exactly what @Evgeni_Popov wrote here, which was perfect :ok_hand:

What you need to understand here is that the darkness of the shadow uses the emissive. Understand the emissive color ‘emits a color’ that will superseed your shadow. By making a white emissive with a default level 1, you are emitting strong white color against the light/shadow

Ok that makes sense! Thanks

If the light is obstructed from the other side, well… it is :wink: So, adding a ‘global type’ of light to your scene is I believe the way to go

Makes sense as well!

set an intensity lower than 0 (i.e. -1) on the light that is just for shadow casting

Oooow. Good to know!

Your active material in this screenshot has a real funny name. Again, I encourage you to set-up a playground (shouldn’t be too hard at this stage). With this, we will likely spot the issue within minutes.

@Evgeni_Popov thanks for explaining how to upload a mesh on external service!

I’ve managed to get a repro in the online playground :smile: ! I thought it might make your life easier while trying to help me out :pray:!

Live repro: https://playground.babylonjs.com/#SLUR5N#1

EDIT: (oh, @mawa I just saw your comment, after posting that! Good timing ha)

Yes, so it really is the issue from having no lights on these materials.
Here I quickly added a hemi.

The rest depends on how you want your surfaces lit and the darkness (and type of) shadows.

Edit: OK, since it’s sunday :sunglasses: it might be a good time to experience a little with shadows and lights, so I quickly enhanced the PG adding a couple more lights and a second shadow generator. I have also added some options you can play with.
I encourage you to experience with these lights, set their intensity, exclude or include meshes, change the lights position, direction and intensity. Also, for the different types of shadows #realistic (hard, soft…) I would recom you take a look at the doc to see what parameters you can set (and there are many). You can also try adding shadow from a spotlight and changing the light angle to see what it does. Just keep in mind that 1) light only adds to light 2) the further the light, the bigger the area that is lit (eventually exploding a material/surface and in any case flattening the light on the volume)

Edit 2: If you wish, you can see some of the ‘semi-realistic’ shadows I created in my demos. The first demo (snowball) includes an animated light/shadow from the sun using a directional light (press KB 1 to 7 to change time of day):

1 Like