Shadows with directional light source: strange behaviour


I just bumped into a strange behaviour I can’t explain.
I set up a directional Red light source, with shadow processing enabled as per attached code.

Now what happens is the following:

only half the scene (negative Y) actually gets light

whenever I move the camera with the trackball, illuminated areas appear to change (ie the lit/dark plane limit moves)

Any idea what is going on here?


render = window->get_render();
render.set_shader_auto(); // enable shadows

NodePath environment = window->load_model(framework.get_models(), "environment.egg");
environment.set_scale(0.4, 0.4, 0.4);
environment.reparent_to(render);		// Reparent the model to render.

DirectionalLight *dlight = new DirectionalLight("dlight"); // eclairer scene
dlight->set_color(LVecBase4f(1, 0, 0, 1));		// red light
dlight->set_shadow_caster(true, 512, 512);
//  dlight->get_lens()->set_fov(90);			// certainly irrelevant here!
dlight->show_frustum();							// should be a box: it is!
NodePath dlnp = render.attach_new_node(dlight); 
dlnp.set_pos(-300, 150, 300);					// light source location
dlnp.look_at(0, 0, 0); 


Directional lights that cast shadows actually have a frustum. Try visualising it using show_frustum() and adjusting the near/far or film size properties on the orthographic lens of the directional light.

Also keep in mind that DirectionalLight is reference counted, so use a special pointer wrapper in this line:

PT(DirectionalLight) dlight = new DirectionalLight("dlight"); // eclairer scene 

Thanks rdb,

A few comments however :

(1) I indeed did use show_frustum() and already adapted the box frustum with adequate near/far values.
The stuff I’m not sure of is:


I don’t understand this notion for a light, and I was not able to find an explanation on the doc. (maybe I overlooked it)

set_shadow_caster(true, ?, ?);

Same question, what are the use of the two parameters?

(2) BTW. I was able to fix the issue by using the quick and dirty turnaround

// Dummy trick
Spotlight *dummy_sp = new Spotlight("dummy_SP");
dummy_sp->set_color( Colorf( 0.0f, 0.0f, 0.0f, 1.0f ));
NodePath dummy_spn =render.attach_new_node(dummy_sp);

It works, although the shadows are strangely casted.
But once again this “halfway black magic” is not satisfying for getting an understanding

(3) More globally, a question related to the use of PT(

PT(vvv) fff;    versus  vvv *fff;

Is is recommended to only use this form of smart pointer and to ban the usual one for Panda objects?

If not, how to know what is referenced counted or not :question:

(1) The film size is the width and height of the frustum, when viewing directly through it.

As for the two parameters to set_shadow_caster, it represents the width and height of the shadow buffer. The two parameters need to be powers of two, and an acceptable texture size. 512x512 seems to be a popular size, but you’ll probably want to do tweaking until you find the setting that’s right for you.
(Note that the buffer does not need to be square. 8x1024 would be an acceptable size, for instance.)

Basically, every pixel on the shadow map will be film_size / buffer_size large.

(2) On a sidenote, I should point out that spot lights are easier to configure and it’s significantly easier to avoid shadowing artifacts with them, because of the slight angle.

(3) The Panda objects that inherit from ReferenceCount hold a reference count, which means that they are deleted when the reference count reaches zero. The PT() wrapper holds one reference to the object, which guarantees that it will not be deleted as long as the PT() exists. Otherwise the object might be garbage collected and you’ll get a segfault when trying to use it.

Note that you should not attempt to delete reference-counted objects yourself, this will result in a double free.

tl;dr: check in the API reference if the class inherits from ReferenceCount or not.