Unwanted nodes are casting shadows even after `subnode.setAutoShader()`

I have light above a table and balls that move on the table. I also have lines to show the trajectories of the balls. Here is a screenshot:

The balls have a self-shadowing effect (good), they are casting some nice shadows onto the table (good), but the lines are also casting shadows (bad). Initially, this made sense, because the node hierarchy looked like this:

render
└── table
    ├── ball1
    │   └── ball1_trail
    ├── ball2
    │   └── ball2_trail
    ├── ball2
    │   └── ball2_trail
    └── etc...

Since I was calling table.setAutoShader(), all of the child nodes would be set too, which includes the line trails ball1_trail, bail2_trail, etc.

To avoid shading the trail lines, I created the following node hierarchy:

render
├── trails
│   ├── ball1_trail
│   ├── ball2_trail
│   └── etc.
└── table
    ├── ball1
    ├── ball2
    └── etc.

Yet after setting table.setAutoShader(), the trails still cast shadows upon the table, as shown in the picture. This is despite the trail nodes being in a totally separate node. I think what I’ve learned is that since the autoshader has been applied to the table, all objects cast shadows on it, regardless of whether autoshader has been applied to them. Does anyone have a solution to this problem? I would like to be selective about which objects are capable of casting shadows.

Cheers.

(I’m presuming that you’re using Panda’s out-of-the-box shadows; if not, then the question may depend on the specifics of your setup.)

If I’m not much mistaken, the problem lies not with the object that’s receiving the shadows, but with the objects that are casting them–in this case, the lines.

You see, the shadows are generated by virtue of rendering the scene (to be specific, its depth information) via a secondary shadow-camera. The object onto which the shadows are cast then uses that render to determine whether a given pixel is in shadow or not.

Thus any object that’s visible to the shadow-camera may cast shadows–regardless of whether it’s under the auto-shader or not.

The solution, then, might be to hide from the shadow-camera any objects that you want to have casting no shadows (in this case, your lines).

This is done much like hiding an object entirely, via the “hide” method. However, where normally one would call “hide” without any parameters, here one would provide a parameter that specifies the camera from which the object should be hidden. The camera is identified to “hide” by its camera-mask (accessed via the “getCameraMask” method of the “Camera” class).

(I’m not sure of whether you have to set the camera-mask first, offhand.)

The shadow-camera in question should be your light, I believe–all lights (save ambient lights) being cameras.

Thus the code should look something like this:

self.trailRoot.hide(self.lightNode.getCameraMask())
2 Likes

That’s exactly right—and you do have to set your own camera mask. You could reserve a bit for this, for example light.node().setCameraMask(0b0001) and then hide the object with the same mask, eg. object.hide(0b0001).

1 Like

@Thaumaturge Thank you so much. Not only did you solve my problem, but I understand so much better how shadows are made.

@rdb Thank you for this additional tip. I have implemented this convenience.

1 Like