unicornlox
Here's the shader. It will project "ground grid" to any piece of geometry. It just uses geometry as a silhouette to render pixels. It will write the depth value as well making the grid always appear on ground no matter where the geometry is.
To make the grid always visible, regardless of camera position/orientation, parent a quad or a 3D sprite to the camera so that it faces the camera and covers the whole view, and assign the shader to it.
shader_type spatial;
render_mode blend_mix,depth_draw_opaque, unshaded;
uniform vec4 albedo: source_color;
uniform float fadeDistance = 100.0;
uniform float unitSize = 1.0;
uniform float lineThickness = 1.0;
void fragment() {
// ray from camera to fragemnt in wrold space
vec3 rayWorld = normalize(mat3(INV_VIEW_MATRIX) * VIEW);
// calculate fragment position in world space
vec3 posWorld;
float t = -CAMERA_POSITION_WORLD.y / rayWorld.y;
posWorld.y = 0.0;
posWorld.xz = CAMERA_POSITION_WORLD.xz + t * rayWorld.xz;
// calculate planar distance from camera to fragment (for fading)
float distPlanar = distance(posWorld.xz, CAMERA_POSITION_WORLD.xz);
// calculate line mask, using a bit of fwidth() magic to make line width not affected by perspective
vec2 line = step(fwidth(posWorld.xz) * lineThickness / unitSize, fract(posWorld.xz / unitSize));
float lineMask = 1.0 - clamp(line.x * line.y, 0.0, 1.0);
// eliminate grid above the horizon
lineMask *= step(t, 0.0);
// fade into distance
lineMask *= mix(1.0, 0.0, clamp(distPlanar/fadeDistance, 0.0, 1.0));
// write ground plane depth into z buffer
vec4 pp = (PROJECTION_MATRIX * (VIEW_MATRIX * vec4(posWorld, 1.0)));
DEPTH = pp.z / pp.w;
ALPHA = lineMask * albedo.a;
ALBEDO = albedo.rgb;
}