TowerDefense/Assets/Shaders/transition.gdshader

168 lines
4.9 KiB
Text
Raw Normal View History

2025-08-21 16:06:02 +02:00
shader_type canvas_item;
uniform bool use_sprite_alpha = true;
uniform bool use_transition_texture = false;
uniform sampler2D transition_texture;
uniform int transition_type: hint_enum("Basic", "Mask", "Shape", "Clock") = 0;
group_uniforms positioning;
uniform vec2 position = vec2(0,0);
uniform bool invert = false;
uniform vec2 grid_size = vec2(1.0, 1.0);
uniform float rotation_angle = 0.0;
group_uniforms positioning.stagger;
uniform vec2 stagger = vec2(0.0, 0.0);
uniform ivec2 stagger_frequency = ivec2(2, 2);
uniform ivec2 flip_frequency = ivec2(1, 1);
group_uniforms basic_transition_controls;
uniform float basic_feather = 0.0;
group_uniforms mask_transition_controls;
uniform sampler2D mask_texture;
uniform bool use_mask_size = false;
uniform vec2 mask_size = vec2(100.0);
group_uniforms shape_transition_controls;
uniform int edges : hint_range(3, 64) = 6; // default hexagon
uniform float shape_feather : hint_range(0.0, 10.0) = 0.1;
group_uniforms clock_transition_controls;
uniform int sectors : hint_range(1, 128) = 1;
uniform float clock_feather : hint_range(0.0, 16.0) = 0.0;
group_uniforms animation;
uniform float progress = 0.0;
uniform vec2 progress_bias = vec2(0.0);
varying vec4 modulate;
vec2 use_actual_texture_size(vec2 uv, vec2 texture_size) {
uv -= 0.5;
vec2 uv_deriv = fwidth(uv);
float screen_ratio = uv_deriv.x / uv_deriv.y;
float texture_ratio = texture_size.x / texture_size.y;
float mixed_ratio = texture_ratio * screen_ratio;
if (screen_ratio > texture_ratio) {
uv.x /= mixed_ratio;
} else {
uv.y *= mixed_ratio;
}
return uv + 0.5;
}
vec2 get_stagger_offset(vec2 grid) {
vec2 cells = floor(grid);
float offset_row = mod(cells.y, float(stagger_frequency.x)) == 0.0 ? 0.5 : 0.0;
float offset_col = mod(cells.x, float(stagger_frequency.y)) == 0.0 ? 0.5 : 0.0;
return vec2(
offset_row * stagger.x,
offset_col * stagger.y
);
}
vec2 get_grid_flip(vec2 grid) {
vec2 cells = floor(grid);
float flip_row = mod(cells.y, float(flip_frequency.x)) == 0.0 ? 1.0 : -1.0;
float flip_col = mod(cells.x, float(flip_frequency.y)) == 0.0 ? 1.0 : -1.0;
return vec2(
flip_row * grid.x,
flip_col * grid.y
);
}
vec2 rotate(vec2 v, float angle) {
return mat2(
vec2(cos(angle), sin(angle)),
vec2(-sin(angle), cos(angle))
) * v;
}
vec2 get_edges(float center, float width) {
float half_width = width * 0.5;
float edge0 = center - half_width;
float edge1 = center + half_width + 1e-5;
return vec2(edge0, edge1);
}
float get_local_progress(vec2 grid) {
vec2 cell = floor(grid);
// Easier to control bias values
vec2 pretty_bias = progress_bias / 10.0;
float offset = dot(cell, pretty_bias);
return progress - offset;
}
void vertex() {
modulate = COLOR;
}
void fragment() {
vec2 grid = UV * grid_size;
vec2 offset_uv = grid + get_stagger_offset(grid);
vec2 grid_flipped_uv = get_grid_flip(offset_uv);
vec2 tiled_uv = fract(grid_flipped_uv);
vec2 uv = (tiled_uv - position) * 2.0;
uv = rotate(uv, radians(rotation_angle));
float local_progress = get_local_progress(grid);
COLOR = texture(TEXTURE, UV) * modulate;
float alpha = COLOR.a;
float transition_progress = 0.0;
if (transition_type == 1) {
vec2 mask_zoom_uv = uv / local_progress;
vec2 mask_zoom_uv_01 = mask_zoom_uv * 0.5 + 0.5;
mask_zoom_uv_01 = use_mask_size ? use_actual_texture_size(mask_zoom_uv_01, mask_size) : mask_zoom_uv_01;
transition_progress = texture(mask_texture, mask_zoom_uv_01).r;
} else if(transition_type == 2) {
float radius = length(uv);
float angle = atan(uv.y, uv.x);
float sector_angle = 2.0 * PI / float(edges);
float half_sector = sector_angle / 2.0;
// Define polygon sectors using the power of trigonometry
float d = cos(half_sector) / cos(mod(angle + half_sector, sector_angle) - half_sector);
vec2 smooth_edges = get_edges(local_progress, shape_feather);
transition_progress = smoothstep(smooth_edges.x, smooth_edges.y, radius / d);
} else if (transition_type == 3) {
float radius = length(uv);
float angle = atan(uv.y, uv.x);
float sector_angle = 2.0 * PI / float(sectors);
float half_sector = sector_angle / 2.0;
angle = mod(angle - half_sector, sector_angle);
float progress_angle = local_progress * 2.0 * PI / float(sectors);
float smooth_angle = smoothstep(0.0, clock_feather, progress_angle - angle);
transition_progress = smooth_angle;
} else {
vec2 smooth_edges = get_edges(local_progress, basic_feather);
float separation_x = smoothstep(smooth_edges.x, smooth_edges.y, abs(uv.x));
float separation_y = smoothstep(smooth_edges.x, smooth_edges.y, abs(uv.y));
transition_progress = max(separation_x, separation_y);
}
alpha = invert ? 1.0 - transition_progress : transition_progress;
alpha = use_sprite_alpha ? min(COLOR.a, alpha) : alpha;
vec4 transition_color = texture(transition_texture, UV);
if (use_transition_texture) {
vec4 chosen_color = mix(transition_color, COLOR, alpha);
COLOR = chosen_color;
} else {
COLOR.a = alpha;
}
}