godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
89.92k stars 21.06k forks source link

Object with "Distance Fade" enabled does not cast shadows. #97537

Open RonYanDaik opened 1 week ago

RonYanDaik commented 1 week ago

Tested versions

System information

Win 10

Issue description

The wall has Distance Fade enabled. It stops to casting shadows. image

https://github.com/godotengine/godot/issues/69329#issuecomment-1330895397

To resolve this, use the Pixel Dither or Object Dither transparency mode for Distance Fade.

Pixel Dither does not resolve this.

Also if this is intended then the tooltip should say that the object will stop casting shadows. image

But object still do cast shadows from direct light: image

Which makes me think that light camera is affected by same shader and are just to close to object. Which means light camera pass should use different settings/different shader.

Changing distance to very small number solves the shadows but looses its usability meaning ofc: image

Another detail: This is GridMap. Which means that material was assigned to mesh material slot and not to OverrideMaterial Slot of MeshInstance (because GridMap has no Override Material slot, but it should!) image

Steps to reproduce

Enable Distance Fade on material and put light close to object.

Minimal reproduction project (MRP)

N/A

RonYanDaik commented 1 week ago

Probably could be solved by this: https://github.com/godotengine/godot-proposals/issues/4443

clayjohn commented 1 week ago

I think you are on the right track and the problem is that the shader considers the distance to the light instead of the distance to the camera.

See here: https://github.com/godotengine/godot/blob/76a135926aef1f02f27e4e09093787f2c670956d/scene/resources/material.cpp#L1668 here: https://github.com/godotengine/godot/blob/76a135926aef1f02f27e4e09093787f2c670956d/scene/resources/material.cpp#L1673 and here: https://github.com/godotengine/godot/blob/76a135926aef1f02f27e4e09093787f2c670956d/scene/resources/material.cpp#L1689

We solved a similar problem with billboards in https://github.com/godotengine/godot/pull/72638. A similar solution should be applied here

RonYanDaik commented 1 week ago

I've solved it with this custom shader for now. But works only for DualParaboloid shadow mapping.


bool is_shadow_pass = (PROJECTION_MATRIX[2][3] == 0.0);
if(!is_shadow_pass)
    {

        // Distance Fade: Pixel Dither
        float fade_distance = length(VERTEX);

        // Use interleaved gradient noise, which is fast but still looks good.
        const vec3 magic = vec3(0.06711056, 0.00583715, 52.9829189);

        float dfmn = distance_fade_min;
        float dfmx = distance_fade_max;
        if(is_shadow_pass){
             dfmn= 0.0;
             dfmx= 0.1;
        }

        float fade = clamp(smoothstep(dfmn, dfmx, fade_distance), 0.0, 1.0);
        // Use a hard cap to prevent a few stray pixels from remaining when past the fade-out distance.
        if (fade < 0.001 || fade < fract(magic.z * fract(dot(FRAGCOORD.xy, magic.xy)))) {
            discard;
        }
    }