Here's how Godot does it with the distance fade in SpatialMaterial (trimmed to just essentials):
shader_type spatial;
render_mode blend_mix,depth_draw_opaque,cull_back,diffuse_burley,specular_schlick_ggx;
uniform vec4 albedo : hint_color;
uniform float distance_fade_min;
uniform float distance_fade_max;
void fragment() {
ALBEDO = albedo.rgb;
ALPHA = albedo.a;
// Original - exactly how it was converted
// ALPHA *= clamp(smoothstep(distance_fade_max,distance_fade_min,-VERTEX.z),0.0,1.0);
// Flipped min and max so it fades as you get farther away, rather than closer
ALPHA *= clamp(smoothstep(distance_fade_max,distance_fade_min,-VERTEX.z),0.0,1.0);
}
It looks like the alpha is being manipulated to cause the fading.
Edit: Turns out it has the same shadow issue. The Turns out the only distance fade that Godot supports out of the box that supports shadows as well is ObjectDither...
Edit 2: In the ObjectDither code, it uses discard. If you swap distance_fade_min and distance_fade_max around though, it looses its shadow as well. I'm thinking this may be a bug or something, to be honest, as the behavior doesn't make too much sense.
Edit 3: I don't know. I've been messing around with the shaders and I'm not sure why it casts a shadow if fading in using ObjectDither, but not fading out. I guess as a possible, though not optimal workaround would be to have two objects, one that just casts shadows and the other that is the visuals only that does not cast shadows.