Depth test for light but not for camera

Is it possible to have a DirectionalLight see the depth on a node that has setDepthWrite(False) on it?

I have a cloud model with setDepthWrite(False), this way I can use the z_buffer from the camera in a shader to make the cloud fade out when coming in contact with objects. However I want to be able to cast cloud shadows, but with the DepthWrite disabled on the cloud my DirectionalLight does not see it.

So on the cloud I would like the DepthWrite disabled for the camera, but be enabled for the DirectionalLight.

You can override it by adding a DepthWriteAttrib with a higher priority onto the light’s initial state. Alternatively, you can use tag states; you’d create a tag called “depth-write” (or whatever you want) and set a state on the camera and the light that interprets this tag to imply a different state change.

1 Like

(I’ve been slightly ninja’d by the above, but I have a bit of additional detail here, so I’m going to post it anyway.)

You could perhaps do this by applying an “initial state” to your light that overrides the depth-write assignment.

To be specific, the “Camera” class (from which DirectionalLight is descended) has a method called “setInitialState”, which applies a state as though it were the top of the scene graph, thus affecting everything rendered by the camera.

This means that you could generate a state that includes a call to “setDepthWrite(True, 1)”–the “1” being a priority value that should allow it to override a standard call to “setDepthWrite”. This state, when applied to your camera, should cause all things rendered by the camera to write to the depth buffer. (Presuming that no higher priorities have been set.)

I believe that it might be done something like this:

# Create a temporary NodePath in which to construct our state
tempNP = NodePath(PandaNode("temporary NP"))

# Set up the state
tempNP.setDepthWrite(True, 1)

# And apply the state
self.light.node().setInitialState(tempNP.getState())
1 Like

Thaumaturge,
What you suggested works by enabling the depth map for the light, however it messes up the shadowing. I think the setInitialState(tempNP.getState()) is pulling in other settings from the node that is affecting the light.

1 Like

rdb,
I tried giving the DepthWriteAttrib with a higher priority but I think I am doing something wrong as it does not seem to have any effect:

cube.setDepthWrite(False, 0)
#sun.setDepthWrite(True, 1)
#sun.node().setAttrib(DepthWriteAttrib.make(DepthWriteAttrib.MOn), 1)
sun.setAttrib(DepthWriteAttrib.make(DepthWriteAttrib.MOn), 1)

I am not sure how to use the tag states as you described, do you have an example?

How does it mess up the shadowing? Perhaps we can figure out what setting is being affected, and then give its application on the relevant node a priority value so that it overrides whatever the temporary node is applying.

Here is the shadow:

Here is what happens when I disable the cubes depthwrite:

cube.setDepthWrite(False,)

If I add the followering code there is no change, it looks like the above image:

sun.node().setAttrib(DepthWriteAttrib.make(DepthWriteAttrib.MOn), 1)

If I use this code it then looks like this:

tempNP = NodePath(PandaNode("temporary NP"))
tempNP.setDepthWrite(True, 1)
sun.node().setInitialState(tempNP.getState())

Shadow3

If I just use this code it then looks like this:

cube.setDepthWrite(False, 0)
sun.node().setInitialState(DepthWriteAttrib.make(DepthWriteAttrib.MOn))

Shadow4

I do very much appreciate the time your giving to help me on this.

Ah, that artefact is called “shadow acne”, I believe. I think that I’ve seen a recent thread that involved it–let me see…

All right, based on what I’m seeing, this might result from the fact that shadow-casting is intended to use reversed back-face culling, but the state that we’re applying is overwriting that setting with the default back-face culling.

However, I also stumbled upon a potential solution: just as one can set the “initial state”, one can get it.

So, what happens when you try to first get the extant state from your light, apply that to the temporary node, set the depth-writing state on the temporary node, and finally apply the temporary node’s state to the light as a new “initial state”?

Something like this:

extantState = sun.node().getInitialState()
# (If the above doesn't work, perhaps try just "getState()" instead.)

tempNP = NodePath(PandaNode("temporary NP"))
# NB This next line!
tempNP.setState(extantState)
tempNP.setDepthWrite(True, 1)

sun.node().setInitialState(tempNP.getState())

It’s my pleasure. :slight_smile:

1 Like

Thaumaturge,
Perfect thanks that worked!

Now out of curiosity I wonder if there is a way to just directly change this setting on the light that would be cleaner? Perhaps with the tag states that Rdb was describing?

1 Like

I’m glad that it worked! :slight_smile:

Hmm… That I don’t know, I’m afraid. Perhaps rdb would know!

Something like this should work:

extantState = sun.node().getInitialState()
# (If the above doesn't work, perhaps try just "getState()" instead.)

tempNP = NodePath(PandaNode("temporary NP"))
# NB This next line!
tempNP.setState(extantState)
tempNP.setDepthWrite(True, 1)
state = tempNP.get_state()
sun.tag_state_key = "depth-write"
sun.set_tag_state("cube-depth-write", state)
cube.set_tag("depth-write", "cube-depth-write")

The way this works is that whenever the sun renders a node that has a tag with key "depth-write" assigned to it, it will check that tag’s value and if that value is associated with a particular RenderState for sun (using set_tag_state), it will render that node using that state.

2 Likes

Epihaius,

Now I understand, thank you!