3 ^ Grid
Grid with transform and exponential scale for proportional lines.
Shader code
shader_type canvas_item;
const vec3[4] COL_SIDE = { vec3(1.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(1.0, 0.0, 1.0), vec3(0.0, 1.0, 1.0) };
const float GRID_SIZE = 8.0;
const float FACTOR_BASE = 3.0;
uniform vec3 color_grid : source_color = vec3(1.0);
uniform vec3 color_grid_sub : source_color = vec3(0.25);
uniform vec3 color_light : source_color = vec3(0.7, 0.7, 0.5);
uniform bool floor_grid;
uniform bool floor_light;
uniform float grid_pri_step = 3.0;
uniform float grid_sub_step = 3.0;
uniform float light_size = 8.0;
uniform float light_zoom = 1.0;
uniform float line_width = 6.0;
uniform vec2 uv_offset;
uniform float uv_rotation;
uniform float uv_scale = 8.0;
varying float calc_grid_exponent;
varying vec2 calc_grid_pow;
varying float calc_light_exponent;
varying vec2 calc_light_pow;
varying float calc_line_width;
bool get_axis(vec2 pos_abs) {
return pos_abs.x < calc_line_width / 2.0 || pos_abs.y < calc_line_width / 2.0;
}
bool get_axis_reference_rect(vec2 pos, vec2 off) {
vec2 pos_abs = abs(pos);
vec2 off_abs = abs(off);
return sign(pos) == sign(off)
&& (pos_abs.x < off_abs.x && pos_abs.y < off_abs.y)
&& (pos_abs.x > off_abs.x - calc_line_width || pos_abs.y > off_abs.y - calc_line_width);
}
bool[4] get_grids(vec2 pos) {
float lw = calc_line_width / 2.0;
vec2 a = mod(pos + lw, grid_pri_step * calc_grid_pow[0]);
vec2 b = mod(pos + lw, grid_pri_step * calc_grid_pow[1]);
vec2 c = mod(pos + lw, grid_pri_step / grid_sub_step * calc_grid_pow[0]);
vec2 d = mod(pos + lw, grid_pri_step / grid_sub_step * calc_grid_pow[1]);
return {
a.x - lw < lw || a.y - lw < lw,
b.x - lw < lw || b.y - lw < lw,
c.x - lw < lw || c.y - lw < lw,
d.x - lw < lw || d.y - lw < lw
};
}
float get_light(vec2 pos) {
pos = pos * light_zoom / FACTOR_BASE;
vec2 a = floor(abs(mod(pos / calc_light_pow[0], light_size) - light_size / 2.0) + 0.5) / light_size;
vec2 b = floor(abs(mod(pos / calc_light_pow[1], light_size) - light_size / 2.0) + 0.5) / light_size;
return mix(mix(a.x, b.x, fract(calc_light_exponent)), mix(a.y, b.y, fract(calc_light_exponent)), 0.5);
}
float logn(float base, float argument) {
return log(argument) / log(base);
}
vec2 rotated(vec2 v, float phi) {
float cosi = cos(phi);
float sine = sin(phi);
return vec2(cosi * v.x + sine * v.y, cosi * v.y - sine * v.x);
}
float snap(float x, float y) {
return round(x / y) * y;
}
void vertex() {
// Called for every vertex the material is visible on.
calc_grid_exponent = logn(FACTOR_BASE, max(uv_scale, GRID_SIZE) / GRID_SIZE);
calc_grid_pow[0] = pow(FACTOR_BASE, floor(calc_grid_exponent));
calc_grid_pow[1] = calc_grid_pow[0] * FACTOR_BASE;
calc_light_exponent = logn(FACTOR_BASE, max(uv_scale, light_size) / (FACTOR_BASE * light_size));
calc_light_pow[0] = pow(FACTOR_BASE, floor(calc_light_exponent));
calc_light_pow[1] = calc_light_pow[0] * FACTOR_BASE;
calc_line_width = line_width / 1000.0 * uv_scale;
if (floor_grid) {
calc_grid_exponent = floor(calc_grid_exponent);
}
if (floor_light) {
calc_light_exponent = floor(calc_light_exponent);
}
}
void fragment() {
// Called for every pixel the material is visible on.
vec2 position = rotated(UV - REGION_RECT.zw / 2.0, uv_rotation) * uv_scale + uv_offset;
bool col_axis = get_axis(abs(position));
bool col_axis_ref = get_axis_reference_rect(position, uv_offset);
bool col_axis_ref0 = get_axis_reference_rect(position, -vec2(0.025 * uv_scale));
bool[4] col_grids = get_grids(position);
float col_light = get_light(position);
int off_side = int(mod(snap(atan(-position.y / abs(uv_offset.y), position.x / abs(uv_offset.x)), PI / 2.0) / TAU * 4.0, 4.0));
int pos_side = int(mod(snap(atan(-position.y, position.x), PI / 2.0) / TAU * 4.0, 4.0));
COLOR.rgb = col_axis ? COL_SIDE[pos_side]
: col_axis_ref ? COL_SIDE[off_side]
: col_axis_ref0 ? vec3(1.0)
: ((col_grids[0] ? color_grid : col_grids[2] ? color_grid_sub : vec3(0.0)) * (1.0 - fract(calc_grid_exponent))
+ (col_grids[1] ? color_grid : col_grids[3] ? color_grid_sub : vec3(0.0)) * fract(calc_grid_exponent)
+ col_light * color_light);
}
//void light() {
// // Called for every pixel for every light affecting the CanvasItem.
// // Uncomment to replace the default light processing function with this one.
//}
