Prevent Mesh/Ocean/Water (Single Water Layer) From Receiving Shadows

TL;DR;

#define DISABLE_FORWARD_DIRECTIONAL_LIGHT_SHADOW 1

Place this define in ‘BasePassPixelShader.usf’ at line 176 (outside the quality define)


Hello!

I would require to prevent an arbitrary object from RECEIVING a shadow. The object in cause is the SingleWaterLayer ocean, however that is not relevant. UE V5.5.4.

These will NOT be considered valid solutions:

  1. Using VSMs (virtual shadow maps)
  2. Using any form of raycasting
  3. Modifying the engine r.Water.SingleLayer.DepthPrepass/ShadersSupportVSMFiltering/VSMFiltering=1 did NOT work
  4. Using ‘Unlit’ color mode, let’s be serious :slight_smile:
  5. Disabling the main scene directional light is out of the question it is required

I have tried:

  1. Using Phase G (Anisotropy) to 1, does not work since the shadow is applied where roughness is larger than 0 too
  2. Switching from SingleWaterLayer to Translucent, but the water looks bad, there is no specularity on it

I would like to implement a production-ready, rather than hobby/experimental solution.

My initial thought was to replicate the ‘Receive Decal’ option already present in the engine.

  1. Have the custom depth-stencil pass enabled
  2. Write a stencil value of 255 and enabling the depth pass
  3. In the shadow combination UE shader disable the shadow addition if the stencil value is 255
  4. Integrate the shader changes (copy-paste) without requiring an engine recompile

Notes:

  • float4 Radiance = GetDynamicLighting() inside ‘DeferredLightPixelShaders.usf’ does NOT handle water lighting/shadows

As per the example image, there is a very blocky/bad looking shadow on the water.

so… you wanna remove the shadow map from the top layer? well…

the shader is an old mess of code. but this does it…

should recompile immediately, when restarting the editor. dunno if it packages like that.

side note: actually this should be controlled by the base color and the opacity. since no opacity at the top is no shadow. again… old mess of a shader. yep

I’ve tried it out and it seems that it’s still visible.

I have tried simply returning like this:

But the result is:

It’s simply darker water.

Looking in render doc it seems that there is a composite phase where there is a GBuffer texture called ‘SLW.SeparatedMainDirLight’:

I was just looking what shader is that pass using and to try and see if I can render that ‘SLW.SeparatedMainDirLight’ without the light.

P.S: In your setup make sure your opacity of the water is 1 and roughness is 1 to duplicate the shadow problem.

P.P.S: I’ve set ‘r.Water.SingleLayer.ShadersSupportDistanceFieldShadow=0’ in DefaultEngine.ini and that pass is missing however now in renderDoc I see the GBuffer SceneColor already containing the shadow (the SingleWaterLayerShading.usf ‘EvaluateWaterVolumeLighting’ function is still disabled):

P.P.P.S:

It seems that the ‘EvaluateWaterVolumeLighting’ is called inside the ‘BasePassPixelShader.usf’. Let’s see if we modify there something we might get the proper effect.

why would you set the opacity to 1? that will only show the basecolor and reflections. also high roughness doesn’t make a lot of sense unless you want a murky top layer. which should be done using the base and opacity. the volume underneath is always computed. the top is the bad code.

i nuked both instances of DirectionaLightShadow, now.

when using a rough top layer for some reason the shadow map still shows up. which makes no sense.

again… this is pretty old bad shader code. : )

For production water to show nice, I have to use roughness on the top of the waves because the SkyLight makes it look absolutely bad. The opacity is required in order to create a nice fake SSS gradient that discolors the water properly. The opacity is not really (1) it is more a bit of a lerp between 0 and 0.6 with a roughness being 0 on the base water and 0.3-0.6 on top of the water plus fresnel so that the ugly reflections caught by the water are dimmed.

But that is the behavior that you’ve also observed, for some reason higher roughness (also lower specularity) causes that ‘interesting’ shadow behavior.

Anyway, back to the P.P.P.S. it seems I have to get into the ugly BasePassPixelShader.usf that uses ‘EvaluateWaterVolumeLighting’ and there I should see if I can discard somehow that shadow that is added on top of the SceneColor.

I think I have found a solution.

In BasePassPixelShader.usf line 174 it seems that on the mobile renderer there is a define called:

// Use mobile like simple shading
// Remove forward lighting directional light shadow
#define DISABLE_FORWARD_DIRECTIONAL_LIGHT_SHADOW 1

Define it outside the

#if SINGLE_LAYER_WATER_SHADING_QUALITY == SINGLE_LAYER_WATER_SHADING_QUALITY_MOBILE_WITH_DEPTH_TEXTURE

directive and the shadow should be gone. It seems that the used pass is the forward one for the water, however I am not sure if this might have unintended side-effects.

It would be nice if someone would try it out too :slight_smile:

i’m not using the mobile path. i defined it at the top of the header and the shadow is gone. yes. confirmed.

and… side effects? well. it’s defined only in the water shader header. should not have side effects. or everything that is forward rendered would have no directional light shadows. which is not the case. tested with shadow mapped and the raytraced icon. works just fine.

case closed? i think so. : )

1 Like