Grass not receiving shadows properly

Hi, my grass meshes do not receive shadows properly in dark areas compared to the underlying landscape material. See the below picture, on the left side the grass meshes are lit properly, but on the right side, where the shadows are, they are still bright whereas the underlying landscape is darker.

My scene is using dynamic lighting: a directional light, a skylight (both set to Movable) and a BP_Sky_Sphere. The 3D grass is spawned using the Grass Tool. The 3D grass material is using the Masked blend mode and Two Sided Foliage shading model (I tried with Subsurface too but have the same type of issue).

In order to have my grass normals same as the ones of the landscape, I am using a technique mentioned in this thread. Basically my grass material setting is set with Tangent Space Normal off, and in the Normal input I am setting the normal up (0,0,1) converted to world space:

This, I believe, should give me a normal identical to the one of the landscape provided the grass mesh is orientated along the landscape normal, which is the case.

Despite all these, I still have too much light on my grass meshes. Maybe the reason is the one explained here where the slope is too steep and the grass too short to catch the shadows. In such a case is there a workaround ?

It should be local2world, not tangent2world.

Ah ok! So I made the change and the result is slightly better, the top grass seem to blend better with the terrain, but the lighting problem is still there:

To me it looks like the grass has something in it’s emissive input, which prevents it from being shadowed…

no there is nothing in the Emissive input.

Maybe you should show the Material and the Foliage Settings of the Grass

Ok here they are below. I simplified my material for the purpose of posting but the problem is the same. I am also posting a screen made with this material for reference. In the Grass Type settings, Use Landscape Lightmap is not checked but checking it has no effect since I am using dynamic lighting.

looks to me that it’s not a shadow issue, but a shading issue
the terrain seems to be not in the shadows since there’s still some light hitting it. so the light angle against the landscape is sharp enough for it to be almost dark, but not sharp enough to cause a shadow
now the main issue is that the landscape has its normals pointing perpendicular to the ground surface (i.e. up in flat areas), while the grass normals do not follow the same pattern (they mostly point towards the sides), and as such, they catch the light in a totally different way.
if you want to check if what I say is true, rotate the light even more so the landscape and grass are really fully in the shadows, and then the way they are lit should match much more closely.

take a look at this page. it talks about trees but the principle is the same: it’s about the normals of the geometry (in your case, the grass).

a “hard” fix would be to modify your grass vertex normals so they point upwards. but then you’d get quite a “flat” look. you’ll need to find the right setup for your vertex normals

I’d agree with message from Chosker above. It is important to note, that it is shading issue, not a shadowing problem. Check world normal buffer,base color and roughness and specular visualizations and maybe post them here. If on all of them, normal being particularly important, it is hard to distinguish grass from landscape, you are on the right way.

This is what I am doing! Look at my material, I am inputing (0,0,1) and converting from local space to world space, my material being configured with normals in world space. Unless (0,0,1) is not the right value for an up normal in local space?

Also I tried to change my normals in Blender but I didn’t manage to get a proper result. Anyone knows a good tool to manipulate mesh normals?

I rotated the light on my scene and the result is rather catastrophic! Now the grass in lit areas becomes darker (so it looks better in the dark, but not in light this time!):


For debugging purposes change Shading mode to Default Lit.
Can you also post screenshots from Buffer Visualization: World normal, base color, specular and roughness. These should look almost identical between landscape grass and foliage grass.

Guys, I think we nailed it! Problem solved I would say, see below image! For debugging, I hard-coded roughness and specular of both landscape and grass materials to respectively 1 and 0. I looked at buffer visualizations, only the World Normal was differing between the two materials. So I modified the landscape material to input the same normal calculation as for the grass, that is (0,0,1) converted from local to world space, material being set to handle world space normal, and that did it!

Now can you help confirming that (0,0,1) the right value for an up normal in local space? I am a bit confused with all these spaces. What is the normal up vector in tangent space?


Default up vector in tangent space is (0,0,1).
For grass you want it to be same as underlying face normal. Because each instance is oriented based on underlying face normal you can use (0,0,1) for local space and then transform that to world space. This transformation should be done at vertex shader. There are some limitations what instance parameter can be used at pixel shader.

I am doing this now for both the grass and landscape material (with material setup to handle world space normals) :


How can I know whether this is running on the vertex or pixel shader ?

I also tried to input (0,0,1) directly into the normal input, the material being configured to handle normals in tangent space (the default). But this doesn’t provide a good result visually, so I will stick to the above. I am not sure why this is not equivalent to (0,0,1) in local space converted to world space…

In fact it would make sense, but this is not what works best from my experiments. If I wanted to have my grass normal same as the terrain mesh normal, per my understanding I would need to input (0,0,1) in tangent space. But I am imputting (0,0,1) in world space, which means my normals will point up regardless of the terrain mesh normal. And this is what works best (when this is made on both the landscape material and the grass material).

Local space to worldspace for Lanscape is not same that it’s for foliage. Leave normal input empty at landscape material and then check in use tangent space normal map. Or Put vertex normal to normal slot and check out tangent space box.
If you want something to happen at vertex shader you need to either output results to custom uv or use Vertex Interpolator node.

making your landscape normals point upward in world space is only going to make things worse. any polygons that are not strictly pointing upwards (i.e. flat areas) will have wrong shading. make a tall cliff with the light pointing straight downwards and you’ll see what I mean

straight downwards lighting does not look so bad actually. My normals are pointing upwards only on the grass, not other landscape layers. I had to combine the up normals with the grass normals a bit to have a good layer blend though. But this technique is providing the best results for me, and also provides some smooth aspect to the grass which is quite pleasing. And if I had issue with a specific light orientation, I could use global params to ajust my normals dynamically.