Skip to content

Instantly share code, notes, and snippets.

@bamfbamf
Last active April 22, 2024 14:16
Show Gist options
  • Save bamfbamf/84ef909a0ec214002ec5bc7f03fdafd0 to your computer and use it in GitHub Desktop.
Save bamfbamf/84ef909a0ec214002ec5bc7f03fdafd0 to your computer and use it in GitHub Desktop.
Infinite grid in GLSL
#version 460 core
/* -----------------------------------------------------------------
INPUTS |
----------------------------------------------------------------- */
layout(location = 0) uniform mat4 VIEW;
layout(location = 1) uniform mat4 PROJECTION;
layout(location = 2) uniform vec3 VIEW_POS;
layout(location = 3) uniform float NEAR_PLANE;
layout(location = 4) uniform float FAR_PLANE;
layout(location = 5) uniform int gridAxis;
layout(location = 6) uniform float gridCellSize;
layout(location = 7) uniform float gridOpacity;
in vec3 pass_NearPoint;
in vec3 pass_FarPoint;
/* -----------------------------------------------------------------
OUTPUTS |
----------------------------------------------------------------- */
out vec4 out_CLR;
/* -----------------------------------------------------------------
HELPERS |
----------------------------------------------------------------- */
const float N = 200.0; // Grid ratio.
float
AnalyticalBoxFilter(vec2 p, vec2 ddx, vec2 ddy) // https://iquilezles.org/articles/filterableprocedurals/
{
// Filter kernel.
vec2 w = max(abs(ddx), abs(ddy)) + 0.01;
// Analytic (box) filtering.
vec2 a = p + 0.5 * w;
vec2 b = p - 0.5 * w;
vec2 i = (floor(a) + min(fract(a) * N, 1.0) - floor(b) - min(fract(b) * N, 1.0)) / (N * w);
// Pattern.
return (1.0 - i.x) * (1.0 - i.y);
}
vec4
Grid(vec2 plane, float cell_size, float grid_opacity, bool filtered)
{
vec2 coord = plane * cell_size; // Use the cell_size variable to set the distance between the lines.
vec2 derivative = fwidth(coord);
vec2 grid = abs(fract(coord - 0.5) - 0.5) / derivative;
float line = min(grid.x, grid.y);
float minimumZ = min(derivative.y, 1);
float minimumX = min(derivative.x, 1);
vec4 color = vec4(0.0, 0.0, 0.0, 1.0 - min(line, 1.0));
color.w *= grid_opacity;
if (filtered)
{
vec2 ddx = dFdx(coord);
vec2 ddy = dFdy(coord);
float filterWeight = AnalyticalBoxFilter(coord, ddx, ddy);
color *= filterWeight;
}
return color;
}
vec2
ComputeDepth(vec3 position, float near_plane, float far_plane, mat4 view, mat4 projection)
{
// Raw depth value of the fragment position in clip space.
vec4 clipSpacePosition = projection * view * vec4(position.xyz, 1.0);
float depth = (clipSpacePosition.z / clipSpacePosition.w);
// Linear depth of the fragment position in view space.
float shiftedDepth = depth * 2.0 - 1.0; // Put back between -1 and 1.
float linearDepth = (2.0 * near_plane * far_plane) / (far_plane + near_plane - shiftedDepth * (far_plane - near_plane)); // Get linear value between 0.01 and 100.
linearDepth = linearDepth / far_plane; // Normalize.
return vec2(depth, linearDepth);
}
/* -----------------------------------------------------------------
MAIN |
----------------------------------------------------------------- */
void
main()
{
if (gridAxis == 0) // X
{
float t = -VIEW_POS.x / (pass_FarPoint.x - VIEW_POS.x);
vec3 position = VIEW_POS + t * (pass_FarPoint - VIEW_POS);
vec2 depth = ComputeDepth(position, NEAR_PLANE, FAR_PLANE, VIEW, PROJECTION);
gl_FragDepth = ((gl_DepthRange.diff * depth.x) + gl_DepthRange.near + gl_DepthRange.far) / 2.0; // https://paroj.github.io/gltut/Illumination/Tut13%20Deceit%20in%20Depth.html
// Draw grid.
vec4 grid = Grid(position.yz, gridCellSize, gridOpacity, true);
float fading = max(0.0, 1 - max(abs(position.y - VIEW_POS.y), abs(position.z - VIEW_POS.z)) * 0.05);
out_CLR = grid;
out_CLR *= vec4(1.0, 1.0, 1.0, max(0.0, fading - float(t < 0.0))); // Hide the grid where it should not be visible.
}
else if (gridAxis == 1) // Y
{
float t = -VIEW_POS.y / (pass_FarPoint.y - VIEW_POS.y);
vec3 position = VIEW_POS + t * (pass_FarPoint - VIEW_POS);
vec2 depth = ComputeDepth(position, NEAR_PLANE, FAR_PLANE, VIEW, PROJECTION);
gl_FragDepth = ((gl_DepthRange.diff * depth.x) + gl_DepthRange.near + gl_DepthRange.far) / 2.0; // https://paroj.github.io/gltut/Illumination/Tut13%20Deceit%20in%20Depth.html
// Draw grid.
vec4 grid = Grid(position.xz, gridCellSize, gridOpacity, true);
float fading = max(0.0, 1 - max(abs(position.x - VIEW_POS.x), abs(position.z - VIEW_POS.z)) * 0.05);
out_CLR = grid;
out_CLR *= vec4(1.0, 1.0, 1.0, max(0.0, fading - float(t < 0.0))); // Hide the grid where it should not be visible.
}
else // Z
{
float t = -VIEW_POS.z / (pass_FarPoint.z - VIEW_POS.z);
vec3 position = VIEW_POS + t * (pass_FarPoint - VIEW_POS);
vec2 depth = ComputeDepth(position, NEAR_PLANE, FAR_PLANE, VIEW, PROJECTION);
gl_FragDepth = ((gl_DepthRange.diff * depth.x) + gl_DepthRange.near + gl_DepthRange.far) / 2.0; // https://paroj.github.io/gltut/Illumination/Tut13%20Deceit%20in%20Depth.html
// Draw grid.
vec4 grid = Grid(position.xy, gridCellSize, gridOpacity, true);
float fading = max(0.0, 1 - max(abs(position.x - VIEW_POS.x), abs(position.y - VIEW_POS.y)) * 0.05);
out_CLR = grid;
out_CLR *= vec4(1.0, 1.0, 1.0, max(0.0, fading - float(t < 0.0))); // Hide the grid where it should not be visible.
}
}
#version 460 core
layout (triangles) in;
layout (triangle_strip, max_vertices = 4) out;
/* -----------------------------------------------------------------
INPUTS |
----------------------------------------------------------------- */
layout(location = 0) uniform mat4 VIEW;
layout(location = 1) uniform mat4 PROJECTION;
/* -----------------------------------------------------------------
OUTPUTS |
----------------------------------------------------------------- */
out vec3 pass_NearPoint;
out vec3 pass_FarPoint;
/* -----------------------------------------------------------------
HELPERS |
----------------------------------------------------------------- */
vec3
ToWorldSpace(vec3 clip_space_position, mat4 view, mat4 projection)
{
vec4 position = inverse(view) * inverse(projection) * vec4(clip_space_position.xyz, 1.0);
return position.xyz / position.w;
}
/* -----------------------------------------------------------------
MAIN |
----------------------------------------------------------------- */
void
main()
{
// Clipped space coordinates for the quad.
vec4 clipSpaceCoords[4] = vec4[]
(
vec4(-1.0, -1.0, 0.0, 1.0),
vec4(1.0, -1.0, 0.0, 1.0),
vec4(-1.0, 1.0, 0.0, 1.0),
vec4(1.0, 1.0, 0.0, 1.0)
);
// Emit vertices for the quad
for (int i = 0; i < 4; ++i)
{
vec4 p = clipSpaceCoords[i];
gl_Position = p; // Using directly the clipped coordinates.
pass_NearPoint = ToWorldSpace(vec3(gl_Position.xy, -1.0), VIEW, PROJECTION);
pass_FarPoint = ToWorldSpace(vec3(gl_Position.xy, 1.0), VIEW, PROJECTION);
EmitVertex();
}
EndPrimitive();
}
#version 460 core
void
main() { }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment