Dotted grid 2d [Improved]

simple shader that draw dots at each cell intersections

at first the grid will not be visible, you need to specify the in-game resolution within the shader parameters in the editor tab (can be modified at runtime within your code if needed).

use the uniform vec2 offset in your code if you want the grid to be infinite.

what I mean by “improved”:

  • The in-game resolution is no more an issue
  • Implemented an anti-aliasing algorythm
  • Implemented a stochastic sampling algorythm

My old code had an issue where each dots would get deformed/disappear if the resolution was too small or when using the uniform vec2 offset at runtime to make the grid look infinite.

By reading articles and stackoverflow conversations on this subject, I came to the conclusion that anti-aliasing and supersampling where the way to solve this issue.

However, supersampling can be quite computationally expensive, so I opted for a less accurate but more optimised method : stochastic sampling.

Look at screenshot number 1 & 2 to see the difference.

 

ps: if you know more than I do about shaders please give me feedback.

Shader code
shader_type canvas_item;

uniform float cell_size = 16;
uniform float dot_size : hint_range(0.0, 0.5) = 0.25;
uniform vec4 background_color : source_color = vec4(0.1176, 0.1176, 0.1176, 1.0);
uniform vec4 dot_color : source_color = vec4(0.2156, 0.2156, 0.2156, 1.0);
uniform vec2 resolution; // Resolution of the screen or viewport
uniform vec2 offset; // Offset to move the grid at runtime!
uniform float anti_aliasing_factor = 0.01; // Adjust this value for more/less smoothness
uniform int stochastic_samples = 16; // Number of stochastic samples per pixel

// Pseudo-random number generator function
float random(vec2 st){
    return fract(sin(dot(st.xy, vec2(12.9898,78.233))) * 43758.5453123);
}

void fragment() {
    vec2 uv = FRAGCOORD.xy / resolution;
    vec4 finalColor = vec4(0.0);
    
    for (int i = 0; i < stochastic_samples; ++i) {
        // Generate random offset within the pixel
        vec2 randomOffset = vec2(
            random(vec2(float(i), 0.0)),
            random(vec2(0.0, float(i)))
        ) / resolution;
        
        // Apply offset and scale by cell_size
        vec2 scaled_pos = ((uv + randomOffset) * resolution + offset) / cell_size;
        
        // Find the nearest grid intersection in normalized space
        vec2 nearest_grid = round(scaled_pos) * cell_size;
        
        // Calculate the distance to the nearest grid intersection
        float dist = length(((uv + randomOffset) * resolution + offset) - nearest_grid);
        
        // Convert dot_size to an actual radius based on grid_size
        float radius = dot_size * cell_size * 0.5;
        
        // Anti-aliasing: Smooth transition near the edge of the dot
        float edge_smoothness = anti_aliasing_factor;
        float alpha = smoothstep(radius - edge_smoothness, radius + edge_smoothness, dist);
        
        // Mix dot_color and background_color based on alpha
        finalColor += mix(dot_color, background_color, alpha);
    }
    
    // Average the colors from all samples
    COLOR = finalColor / float(stochastic_samples);
}
Tags
2d, dot, grid
The shader code and all code snippets in this post are under CC0 license and can be used freely without the author's permission. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

Related shaders

Animated Dotted Outline

Dotted Circle

Animated Dotted Rectangle Outline

Subscribe
Notify of
guest

2 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
mujtaba-io
5 months ago

Thanks for sharing this shader. I used this shader for my side scrolling shooter game tutorial. The effect isn’t visible too much but adds some vibe.