Setting up shadow caster with DirectionalLight

I’m using Panda3D for a few years now, and I’m trying to write a simple game to write a tutorial series.
The game is almost done, but I can’t figure out how to have drop shadows. I tried several solutions:

  • the “default” solution, using set_shadow_caster() and render.set_shader_auto() : the shader generator works great with everything, except for drop shadows (I tried several resolutions, from 512 to 8192);
  • the solution offered in the book “Panda3D Tutorial” by Fireclaw the Fox worked for a previous project (but sometimes stopped to work for no obvious reasons when I started to add geometry to the terrain), but I have not managed to make it work for this project;
  • I tried other solutions, based on the sample program (converted to GLSL), but it seemed to be too specific and I could not manage to make it suitable for my setup;
  • I tried also some other solutions implying GLSL, which I’m not really familiar with (I’ve only developped basic shaders): Shadows: direction, parameters, and inputs in GLSL but for some reason, it did not worked either.

I also looked at pure GLSL solutions, trying to port them for Panda3D but my understanding of rendering pipelines is not advanced enough to make it work.

My setup is simple: the terrain is composed of a rescaled cube, on which I apply a 32×32 solid color texture (this allows me to have a single cube model retextured and rescaled to compose my whole scene). In the center of the terrain I have a big “tower” (again, a very basic geometry), and along the terrain, many cubes representing obstacles (exact number is random, but should be around 2000-3000). The terrain is 1600m×1600m and the player is represented by a 1m×1m cube.

I use Panda3D 1.10 devel, with deploy-ng, installed with pip on Ubuntu 18.04 and last updated a few days ago.

So basically, what I need is a basic solution to have dynamic drop shadows on this terrain, acting in a realistic way (shadows should not be projected only on the ground, but also on other objects). A few particular cases I have: I use a particle system around the center tower, and the particles should not cast any shadows. Also, a portable solution would be great: I am working on an other project, in which I use a heightmap for the terrain (based on the shader-terrain sample), and what I dream of is a solution I could use there too.

The source code of this project is now a private gitlab repo (because I’m refactoring it, so I feel a bit ashamed of half the existing code :innocent:), but I can open it if needed :slight_smile:

Thanks!

DirectionalLights derive from the Camera class and use an OrthographicLens to render the shadow maps. In order to see shadows, you need to configure the film size and near/far of the lens. Film size determines the width and height of the lens, and near/far determines the minimum and maximum distance that the lens will render. The default film size on a DirectionalLight is way too small to render any shadow maps.

You can do this with dlight.node().getLens().setFilmSize(x, y) and dlight.node().getLens().setNearFar(near, far).

You can also visualize the lens with dlight.node().showFrustum().

Note that a larger film size will result in blockier shadow maps, and a larger near/far will reduce the precision of the depth buffer and might result in shadow acne.

Also, to prevent specific nodes from casting shadows, you can give the DirectionalLight camera a unique bit, and any node that you don’t want casting shadows can be hidden from the camera.
Example:
dlight.node().setCameraMask(BitMask32.bit(1))
render.show(BitMask32.bit(1)) # entire scene will be visible to the dlight camera
node.hide(BitMask32.bit(1)) # this particular node will not be visible to the dlight camera

1 Like

Thanks! I was actually randomly tweaking values for set_film_size, but without having any order of magnitude, nor idea of what it actually did.
Now a few things are annoying me: shadows are blocky. I set a film size of 256, a shadow map size of 4096, and that’s the best settings I found, but its way too blocky. Is there a way to smooth that? (I do not render shadows for the whole map, just for an area around the player).
A second thing is: I have for the red cubes and the blue cube a custom shader. Is there a way to access the shadow map there (I’m aware of sampler2DShadow shadowMap in p3d_LightSource, but I haven’t found yet how to use it).

This might help for accessing lights in shaders:

http://rdb.name/glsl-lighting.zip

Thanks, now the result looks way better/cleaner. But I noticed that when I move my character, the shadow map is a bit “offsetted”, like if the movement speed was faster than the shaders processing. Is there a way to avoid that ? I know it is possible to set a priority to a task, but are the shaders calculation done by a task?

Are you using CommonFilters?

yes, for bloom effect

I think I miss something here: removing CommonFilters fixes the problem, but it also makes both HDR and antialiasing inoperent.