bevy_2d_grid 0.2.0

A infinite 2D grid for Bevy
Documentation
struct InfiniteGrid2DSettings {
    grid_size: f32,
    x_axis_col: vec3<f32>,
    y_axis_col: vec3<f32>,
    line_col: vec4<f32>,
};

struct View {
    projection: mat4x4<f32>,
    inverse_projection: mat4x4<f32>,
    view: mat4x4<f32>,
    inverse_view: mat4x4<f32>,
    world_position: vec2<f32>,
};

@group(0) @binding(0) var<uniform> view: View;
@group(1) @binding(0) var<uniform> grid_settings: InfiniteGrid2DSettings;

struct Vertex {
    @builtin(vertex_index) index: u32,
};

struct VertexOutput {
    @builtin(position) clip_position: vec4<f32>,
    @location(0) world_position: vec2<f32>,
};

@vertex
fn vertex(vertex: Vertex) -> VertexOutput {
    // Generate a full-screen quad
    var positions = array<vec2<f32>, 4>(
        vec2<f32>(-1.0, -1.0),
        vec2<f32>(-1.0, 1.0),
        vec2<f32>(1.0, -1.0),
        vec2<f32>(1.0, 1.0)
    );
    
    let position = positions[vertex.index];
    
    var out: VertexOutput;
    out.clip_position = vec4<f32>(position, 0.0, 1.0);
    
    // Convert clip space directly to world space for 2D
    let view_pos = view.inverse_projection * vec4<f32>(position, 0.0, 1.0);
    let view_pos_normalized = view_pos.xy / view_pos.w;
    let world_pos_2d = (view.view * vec4<f32>(view_pos_normalized, 0.0, 1.0)).xy;
    out.world_position = world_pos_2d;
    
    return out;
}

struct FragmentOutput {
    @location(0) color: vec4<f32>,
};

@fragment
fn fragment(in: VertexOutput) -> FragmentOutput {
    var out: FragmentOutput;
    
    // Convert world position to grid coordinates
    let coord = in.world_position / grid_settings.grid_size;
    
    // Calculate grid lines using derivatives for anti-aliasing
    let derivative = fwidth(coord);
    let grid = abs(fract(coord - 0.5) - 0.5) / derivative;
    let line = min(grid.x, grid.y);
    
    // Axis lines (X and Y axes)
    let axis_derivative = fwidth(in.world_position);
    let grid_axis = abs(in.world_position) / axis_derivative;
    let axis_line = min(grid_axis.x, grid_axis.y);
    
    // Calculate alpha values for line types
    var alpha = vec2<f32>(1.0) - min(vec2<f32>(axis_line, line), vec2<f32>(1.0));
    alpha.y *= (1.0 - alpha.x) * grid_settings.line_col.a;
    
    let total_alpha = alpha.x + alpha.y;
    alpha /= max(total_alpha, 0.001); // Prevent division by zero
    alpha = clamp(alpha, vec2<f32>(0.0), vec2<f32>(1.0));
    
    // Choose axis color based on which axis is more prominent
    let axis_color = mix(grid_settings.x_axis_col, grid_settings.y_axis_col, step(grid_axis.x, grid_axis.y));
    
    let grid_color = vec4<f32>(
        axis_color * alpha.x + grid_settings.line_col.rgb * alpha.y,
        max(total_alpha, 0.0)
    );
    
    out.color = grid_color;
    return out;
}