To draw an infinite ground plane that extends beyond near / far planes, in old school desktop GL, you could enable GL_DEPTH_CLAMP.
Any tips for how to do the equivalent with WebGL? Manipulating gl_FragDepth isn't quite right because clipping occurs before fragment shading.
My use case is a modeling app with a large grid, and the user zooms out and doesn't want to see the grid clipped. My camera has fairly tight near / far planes to allow for good depth precision and nice SSAO.
Displaying a really infinite plan cannot be done with a mesh because you cannot set infinite coordinates to the corners of your plan.
What you could do is use a ray-tracing technique. Your mesh becomes a rectangle that covers the full screen and most of the job is done in the fragment shader.
To simplify let's imagine your infinite plan is on the ground, defined by this simple equation: z = 0
. What you need is to find the intersection between your infinite plan and the ray that is thrown from the camera position.
I wrote an example with a perspective camera that has 90° of field of view. If the view port is a square and if the camera is at rest, the ray that goes from the camera center through the top right corner of the screen is align with this vector: vec3(1.0, 1.0, 1.0)
. Since its z coordinate is positive (and because the camera is above the plane) that means that the ray do not cross the plane. Of course, the bottom right corner has a ray intersecting and we can compute this intersection in the plane (x,y) coordinates.
Here is the vertex shader:
#version 300 es
uniform mat3 uniCameraOrientation;
in vec2 attRay;
out vec3 varRay;
void main() {
varRay = uniCameraOrientation * vec3(1.0, attRay);
gl_Position = vec4(attRay, 0.0, 1.0);
}
And here is the fragment shader:
#version 300 es
precision mediump float;
in vec3 varRay;
out vec4 FragColor;
const vec3 cameraPosition = vec3(0, 0, 1);
void main() {
if (varRay.z >= 0.0) discard;
float factor = -1.0 / varRay.z;
float x = cameraPosition.x + factor * varRay.x;
float y = cameraPosition.y + factor * varRay.y;
float r = cos(x) * cos(y);
FragColor = vec4(r > 0.0 ? vec3(0.2, .8, 0) : vec3(.3, .6, .1) , 1.0);
}
See it in action here: https://codepen.io/tolokoban/full/WNaXBQb