I'm trying to figure out how to make a shader to render an infinite grid in the game world. This requires me to cover the entire screen with a quad, and then use a fragment shader to determine the color of each fragment based on where a ray that extends out from the camera and through the fragment intersects the world XZ plane.
Here's the fragment shader code (vertex shader is empty at this point):
void fragment()
{
vec3 cam_pos = (CAMERA_MATRIX * vec4(0.0, 0.0, 0.0, 1.0)).xyz;
vec3 frag_dir = (CAMERA_MATRIX * vec4(VIEW, 0.0)).xyz;
float t = -cam_pos.y / frag_dir.y;
vec3 frag_intersect = cam_pos + (t * frag_dir);
ALBEDO = vec3(float((fract(abs(frag_intersect.x)) < 0.05 || fract(abs(frag_intersect.z)) < 0.05) && t < 0.0));
}
On a simple (non-fullscreen) quad, everything works nicely:

However, once I try to make the quad fullscreen as per the advanced post-processing tutorial by putting POSITION = vec4(VERTEX, 1.0);
in the vertex shader, things get wonky:

Both screenshots are taken from the exact same camera position, but once I make the quad fullscreen, changing the camera position or zooming in/out causes the grid to get stretched and sheared to infinity and back. Why is this happening?