Can't make transparent objects receive pssm shadows properly

Hi, I can’t get the pssm shadows to work. Casting works great, but receiving does not.



Example: The tree-model in jme tests does not work with cast & receive. Large transparent areas of the leaves are shadowed. It uses the default lighting material etc.



This is also true for my grass that are quads using textures with an alpha channel.



Could anyone try getting the tree to work with ShadowMode.CastAndRecieve (In JME-testdata /models/tree), and see if I’m doing something wrong? Or just simply tell me if they know.



Thanks.

Yeah i know it’s a known issue.



the problem is that the shadow receive pass is done by forcing the post shadow material to the renderer. This material does not have the alpha information of the original pixel. It would require to use a technique (for unshaded and lighting) so the post shadow rendering pass has the actual diffuse map of the rendered object.

But doing so would prevent the pass to be rendered with proper render state…(polygon offset mostly)

so basically shadows would have to be rendered in the lighting pass…that would be faster…but would clutter the (already pretty cluttered) lighting.frag code…or would bring shader injection onto the table…and who would want that?



Actually this issue would require almost a redesign of the pssmRenderer…

@Momoko_Fan i’d like to hear your thoughts on this.

@nehon said:
….or would bring shader injection onto the table…and who would want that?

I want, I want, I want, please :P

ah… yea i didn’t think about it at first, but now it makes sense the recieving process is much more complicated.



thanks!

Can’t we use a “PostShadow” custom technique like we did for the PreShadow?

@Momoko_Fan I looked a bit into it and actually that’s possible…the render states are used for the pre pass…

The only problem is that we’d have to set the technique of all the objects in the receiving queue to postShadow and set the correct parameters to the material…



But while we’re at it…if we have to do that, why not render the shadows in the lighting pas instead of doing an additional post pass.

We would get a nice speed boost IMO.

2 Likes

ok I worked on that yesterday night and i now have a working solution.

I did it the way @Momoko_Fan suggested, keep the post pass but make it a lighting and unshaded technique.

It works and give nice results, but the branching in the post pass (discarding pixels if their alpha value are below the threshold) is draining around 20% of the fps compared to the old way to do it. This performance hit is only here when you have transparent objects receiving shadows but still…



Also the shadow params have to be set to all the receiving objects’ materials on a frame basis, and this can make some overhead on crowded scenes…



I’m really considering rendering shadow during the lighting pass (like ambient is rendered, with the first light).

This would have several pros :

  • A lot faster, we spare one render pass
  • ability to mix shadow value and lightmap value (to avoid casting shadows in a shadowed area, which makes no sense)
  • don’t compute specular lighting that is expensive in shadowed area.



    The cons are that it’s possibly a breaking change for people having their own material definition and using shadows, they’ll have to intergrate the change in their shader.

    Also this will add to the complexity of the lighting and unshaded shaders.

    These issues could be easily addressed if shader injection had been invented…but…well…too bad



    Anyway i’m gonna try that and test performance to see if it worth the shot.
2 Likes

I must admit I have not looked much at the shadowcode. But it has always felt strange to me that shadowing is not present inside the Lighting material.



I invented a rather nice way to hide the packing and unpacking of the GBuffer in my deferred rendering pipeline, which might be applicable to the light/shadow system aswell.



I have created a glsllib file which defines a struct, GBuffer which has several fields like normal, position, depth, color, specularity and so on.



I also has two functions:

gbuffer_encode()

gbuffer_decode()



Which will pack respective unpack values into the GBuffer struct.



This struct serves as a API between my packing/unpacking layer and the rest of my shading code.



The lighting could maybe be done in a similar way with a Light struct. This might not make sense in the context of light/shadow but who knows…

@nehon

Wow this is nice. 20% increase for transparent objects is that so bad? If people absolutely want to use transparent objects casting pssm-shadows onto transparent surfaces, let them suffer. :stuck_out_tongue:



I don’t have much knowledge in this area, just saying what I, as a user, think would be nice. If you make it possible to add a post shadow technique for shadow-recieving transparent object materials (like with preshadow) it would be very, very nice and easy to work with.

yeah, i guess you’re right.

I’m stuck on a strange issue though, if i set the comparison mode to hardware, the shadows are not rendered…but it works in software mode, no error in the output.

It looks like a driver issue, i’ll update and see what it does.

Then I’ll commit this change and I’ll see later if i integrate shadow rendering in the lighting pass.

1 Like

@nehon
is it now possible to use transparent surfaces with DirectionalLightShadowRenderer?

yes…
But maybe you’ll have to elaborate on the question if you want a more detailed answer :stuck_out_tongue:

ok let me explain this:

I use the DirectionalLightShadowRenderer as a post processor like this:
[java]
DirectionalLightShadowRenderer directionalLightShadowRenderer = new DirectionalLightShadowRenderer(assetManager, 4096, 4);
directionalLightShadowRenderer.setLight(sun);
directionalLightShadowRenderer.setLambda(0.65f);
directionalLightShadowRenderer.setShadowZExtend(128f); // distance how far away from camera shadows will still be computed
directionalLightShadowRenderer.setShadowIntensity(0.5f); // shadow darkness (1 black, 0 invisible)
directionalLightShadowRenderer.setEdgesThickness(10); // 1…10
directionalLightShadowRenderer.setShadowCompareMode(CompareMode.Hardware);
directionalLightShadowRenderer.setEdgeFilteringMode(EdgeFilteringMode.PCF4);
viewPort.addProcessor(directionalLightShadowRenderer);
[/java]

further I use a LightingMaterial like this:
[java]
mat.setTexture(“DiffuseMap”, tex);
mat.setTexture(“NormalMap”, tex_nm);
mat.setFloat(“AlphaDiscardThreshold”, 0.5f);
mat.setBoolean(“UseAlpha”, true);
[/java]

together it looks like this :smiley:

and I want shadows which works with transparent surfaces / alpha textures. I tried to modify the AbstractShadowRenderer and the shader files
like this:

AbstractShadowRenderer.java
[java]
private void init(AssetManager assetManager, int nbShadowMaps, int shadowMapSize)
{

preshadowMat.setFloat(“AlphaDiscardThreshold”, 0.5f);
postshadowMat.setFloat(“AlphaDiscardThreshold”, 0.5f);
preshadowMat.setBoolean(“UseAlpha”, true);
postshadowMat.setBoolean(“UseAlpha”, true);

}
[/java]
i.e. PostShadow.j3md
[java]
MaterialDef Post Shadow {
MaterialParameters {

// Apha threshold for fragment discarding
Float AlphaDiscardThreshold (AlphaTestFallOff)

    // Output alpha from the diffuse map
    Boolean UseAlpha

}

Technique {

Defines {

DISCARD_ALPHA : UseAlpha
}
}
[/java]

But the only thing that has happened, that the shadows are disappearing :confused:

hope you understand me :smiley:

@nehon

Regarding the very old post mentioning shader injection to do the shadows in the light pass, now with the shadernodes this might be a possible way, or am i wrong here?

@alrik that’s not possible. Shadow mappingis based on depth maps, so the color or transparency (when it’s partial) is not applicable.
You could have the “glass” object to not cast shadows, but idk if they are independent objects in your scene.

What you want here sounds pretty simple, but it’s not, it’s even pretty advanced.

@EmprirePhoenix I tried the shadows in the light pss once (before shader nodes) and the perfs were a bit better than the additional geometry pass. However it was a lot slower than the post filter pass technique. So idk if we should do it in the end.

Why use transparency rather than modelling them as empty frames?

If you model the frame and then model the glass separately you can turn off cast and receive shadows on the glass and that will solve most of your problems.

<cite>@nehon said:</cite> @alrik that's not possible. Shadow mappingis based on depth maps, so the color or transparency (when it's partial) is not applicable. You could have the "glass" object to not cast shadows, but idk if they are independent objects in your scene.

So the shadow pass ignores the alpha discard threshold?

<cite>@pspeed said:</cite> So the shadow pass ignores the alpha discard threshold?
No it doesn't, but what the op want is shadows through semi transparent surface. @alrik, am i wrong? Here if he sets a discard threshold the surface will be completely transparent
<cite>@nehon said:</cite> No it doesn't, but what the op want is shadows through semi transparent surface. @alrik, am i wrong? Here if he sets a discard threshold the surface will be completely transparent

I’m just going from the picture of a frame that has a totally transparent area that is casting shadows and from the code that sets the alpha discard threshold.

I thought the shadow pass just renders depth and doesn’t render the colour at each point? So it wouldn’t know the alpha in order to discard…