Godot Version
4.4 / 4.5
Question
` The grass in my scene is drawn using imposter cards, essentially two quads at right angles in
a cross shape. The shadows from the trees fall onto the cards and unfortunately they produce weird streaks instead of accurate shadows - this is obviously because the shader doesn’t take the depth of the grass into account - it actually has no depth its just a pair of quads after all.
I found this article from GPU Gems chapter 4… (in particular ‘example 4-1 Pixel Shader Code to Apply Shadow Maps with Offsets’).
Ive pasted the code in … basically I just need to know how to implement this in Godot:
float PSShadowMapFetch(Input In)
{
// Let In.VP and In.VV be float3;
// In.VP - interpolated Vertex Position output by VS
// In.VV - View Vector output by VS
// OCT - Offset Coefficient Texture
// SMPP - Shadow Map Pixel Position
// SMMatrix - transform to Shadow Map space
float3 SMPP = In.VP + In.VV * tex2D(OCT, In.TexCoord).x;
float3 SMCoord = mul(SMMatrix, float4(SMPP, 1));
float SM = tex2D(SMTexture, SMCoord);
return SM;
}
I made a 3d model of some grass, and created a depth texture using the Godot imposter addon.
From here I’m not sure how to access the shadow pass in Godot - any help or example would be much appreciated.
Cheers
`
Maybe the previous post is a bit unclear. There seems to be several differences between what i need and the problem solved in the article - the grass in my project is not a shadow caster, and none of the leaves turn to face the camera.
I am just trying to improve the shadows cast onto the grass from the trees. So the idea is to fake the depth of the grass using a depth texture. In my case this is based on a mesh built using the grass texture as reference.
I took the top left corner image (dimensions 256*256) from the depth texture of the octahedral imposter made from the mesh made from the grass texture, assuming I could write to DEPTH when the alpha value was less than 0.5.
float depth = texture(u_depth, UV).r;
vec4 clip_pos = PROJECTION_MATRIX * wpos;
clip_pos.xyz /= clip_pos.w;
if ( ALPHA < 0.5 ){
DEPTH = clip_pos.z;// + depth;
}
else
{
DEPTH = clip_pos.z + (2.0*depth-1.0)*some_scale_factor;
}
The results were a total disaster - writing to DEPTH is confusing as hell and I’m not even sure what the correct values would be … so the depth buffer uses reverse Z but theres no (I cant find) easy formula like ‘DEPTH = a*1/z + b’ that can map the range of the z buffer. Assuming the range of the
the grass started showing through over the top of other objects - and the shadows still looked bad. Also the framerate dropped really low.
To write to depth properly I used a function from a water shader addon
float z_diff_refracted = depth_from_water_to_object(SCREEN_UV , INV_PROJECTION_MATRIX, VERTEX);
float depth_scale = 0.5 / (far - near );
float h = sqrt(1.0 - UV.x*UV.x - UV.y*UV.y);
vec4 col = texture(u_albedo_alpha, UV);
ALPHA = col.a * COLOR.a;// - clamp(1.4 - UV.y, 0.0, 1.0);//* 0.5 + 0.5*cos(2.0*TIME);
if (col.a > 0.5 ){
DEPTH = (z_diff_refracted + h);//texture(u_depth, UV).r);
}
This version was supposed to make the grass simulate a round surface (calculation of h ) but it didnt’ seem to get rid of the streaks. I dont know i’m really confused at this stage. In the shader I sampled from the original screen depth and tried to overwrite but i cant tell if its affecting the shadow pass. Posting the function used in case it can help someone in the future.
(code taken from the Boujie water shader addon)
// Calculate depth of solid object beneath the water by reading the depth texture
float depth_from_water_to_object(vec2 screen_uv, mat4 inv_projection_matrix, vec3 vertex) {
float depth_raw = textureLod(depth_texture, screen_uv, 0.0).r;
// https://www.reddit.com/r/godot/comments/wb0jw7/godot_4_alpha_12_depth_texture_not_working/ii4awtb/
// In Godot 4 Vulcan, depth_raw goes from 0 to 1 and doesn't need to be normalzied anymore!!! Holy smokes.
vec3 ndc = vec3(screen_uv * 2.0 - 1.0, depth_raw);
vec4 view = inv_projection_matrix * vec4(ndc, 1.0);
view.xyz /= view.w;
float z_depth = -view.z;
float z_pos = -vertex.z;
return z_depth - z_pos;
}
In the picture the grass depth affects the grass near characters legs. The depth would also be wrong for quads rendered at an angle (in this case … there is nothing wrong with the above code, just the change in depth where i added h).
I think you can take the “26 views, no replies” as all of us looking at this and saying to ourselves “Huh, that’s a problem. That I don’t know how to solve…”.
If I was trying to do this, I might be tempted to try making the grass slightly translucent and shutting off shadows for the grass entirely, in the hopes that it would kind of pick up shadowing from the color of the ground below it when it blends.
Or perhaps consider just tinting the entire grass card based on whatever the shadow value is at the model origin, or something like that. I think your options are to either hack your way out of this or use a full grass model that will shadow properly.
Hi, thanks for the input, I agree this problem is tough and so a workaround would make life easier.
I did have a fresh look at the problem and realized if the quads have tangent and normal vectors then its possible to write spherical depth properly (with radius 0.25 in this case) - the uv.x increases in the direction of the tangent (for example), so you can calculate adjusted depth … the problem is this would also be a wrong answer and the shadows would probably look terrible.
I also discovered that writing to depth would break the depth-prepass.
I decided to try disabling the cascaded shadows and used directional shadows instead. Then I tried rendering the grass mesh again and this time i was surprised to get interactive frame rates.
The terrain is the hterrain addon, with spacial gardener for foilage and the recent godot imposter addon for distant trees.
The Left hand side shows the results with grass mesh, and on the right I’ve used quad mesh imposter cards.
The visual difference isn’t dramatic until theyr’e viewed from above, and the shadows seem okay and the artifact is hardly noticable for short grass. The frame rates are much better for imposter grass. The version with the grass mesh also used the imposter for distant grass.
1 Like
I had the same problem with shadows on the grass 2x cards , add this magic to - void fragment() NORMAL *= FRONT_FACING ? 1.0 : -1.0;
This is what it looked before.