From 743899be335f03bdc0598f1a54d71021591511d2 Mon Sep 17 00:00:00 2001 From: tedlipper Date: Mon, 9 Mar 2026 00:43:54 -0700 Subject: [PATCH] Improved outline preservation Did basically anti aliasing but for the sake of making the outlines more clear. It worked but I'm gonna continue to noodle on this solution in the future Also incidentally fixed a minor visual glitch with the projectile directions after bounce --- block/Assets/Shaders/PosterizerTest.gdshader | 1 + block/Assets/Shaders/ShaderTest.gdshader | 81 ++++++++++++-------- block/Scenes/Projectile_1.gd | 9 +-- block/Scenes/ShaderTest.tscn | 6 +- 4 files changed, 59 insertions(+), 38 deletions(-) diff --git a/block/Assets/Shaders/PosterizerTest.gdshader b/block/Assets/Shaders/PosterizerTest.gdshader index b3378eb..52de2c9 100644 --- a/block/Assets/Shaders/PosterizerTest.gdshader +++ b/block/Assets/Shaders/PosterizerTest.gdshader @@ -6,6 +6,7 @@ uniform sampler2D screen_texture : hint_screen_texture, filter_nearest; uniform float pixel_size = 256.0; // This now represents the "Height" resolution uniform float color_levels : hint_range(2.0, 256.0) = 2.0; + uniform float PXwidth = 640; uniform float PXheight = 360; diff --git a/block/Assets/Shaders/ShaderTest.gdshader b/block/Assets/Shaders/ShaderTest.gdshader index 0d8abc8..157a6cf 100644 --- a/block/Assets/Shaders/ShaderTest.gdshader +++ b/block/Assets/Shaders/ShaderTest.gdshader @@ -4,46 +4,67 @@ shader_type canvas_item; uniform sampler2D screen_texture : hint_screen_texture, filter_nearest; uniform sampler2D palette_texture : filter_nearest; uniform int palette_size = 16; -uniform float pixel_size = 256.0; // This now represents the "Height" resolution +uniform float pixel_size = 256.0; uniform float color_levels : hint_range(2.0, 256.0) = 2.0; +uniform float black_bias : hint_range(0.0, 1.0) = 1.0; // Lower = stronger preference for black +uniform float outline_sensitivity : hint_range(0.0, 1.0) = 0.25; // Higher = grabs more grey -uniform float PXwidth = 640; -uniform float PXheight = 360; +uniform vec2 target_resolution = vec2(640.0, 360.0); void fragment() { - float aspect_ratio = SCREEN_PIXEL_SIZE.y / SCREEN_PIXEL_SIZE.x; - vec2 uv = SCREEN_UV; - uv.x = round(uv.x * pixel_size * aspect_ratio) / (pixel_size * aspect_ratio); - uv.y = round(uv.y * pixel_size) / pixel_size; + vec2 uv = floor(SCREEN_UV * target_resolution) / target_resolution; + vec2 v_pixel_size = 1.0 / target_resolution; + vec2 offset = v_pixel_size * 0.5; + + // check center and 4 small offsets to see if black is nearby + vec3 col0 = texture(screen_texture, uv).rgb; + vec3 col1 = texture(screen_texture, uv + vec2(offset.x, 0.0)).rgb; + vec3 col2 = texture(screen_texture, uv - vec2(offset.x, 0.0)).rgb; + vec3 col3 = texture(screen_texture, uv + vec2(0.0, offset.y)).rgb; + vec3 col4 = texture(screen_texture, uv - vec2(0.0, offset.y)).rgb; + + // Calculate the darkest brightness among the 5 samples + float b0 = dot(col0, vec3(0.299, 0.587, 0.114)); + float b1 = dot(col1, vec3(0.299, 0.587, 0.114)); + float b2 = dot(col2, vec3(0.299, 0.587, 0.114)); + float b3 = dot(col3, vec3(0.299, 0.587, 0.114)); + float b4 = dot(col4, vec3(0.299, 0.587, 0.114)); - // 3. Sample and Posterize - vec4 rgba = texture(screen_texture, uv); + float min_brightness = min(b0, min(b1, min(b2, min(b3, b4)))); + vec3 final_rgb; - float best_dist = 10.0; - vec3 best_color = rgba.rgb; -///* - // test posteriser instead of the for loop: - float levels = 8.0; // Number of color steps per channel - rgba.rgb = floor(rgba.rgb * levels) / levels; - COLOR = vec4(rgba.rgb, 1.0); -//*/ + // 2. The "Outline Guard" + // If ANY sampled pixel in this area is dark, force it to black immediately + if (min_brightness < outline_sensitivity) { + final_rgb = vec3(0.0, 0.0, 0.0); + } else { + // 3. Normal Palette Snapping + vec3 rgba = col0; // Use center sample for normal colors + float best_dist = 10.0; + vec3 best_color = rgba; -//* - // Palette snapping logic - for (int i = 0; i < palette_size; i++) { - float x_coord = (float(i) + 0.5) / float(palette_size); - vec3 p_color = texture(palette_texture, vec2(x_coord, 0.5)).rgb; - - float dist = distance(rgba.rgb, p_color); - - if (dist < best_dist) { - best_dist = dist; - best_color = p_color; + for (int i = 0; i < palette_size; i++) { + float x_coord = (float(i) + 0.5) / float(palette_size); + vec3 p_color = texture(palette_texture, vec2(x_coord, 0.5)).rgb; + + float dist = distance(rgba, p_color); + + /* + // Apply bias in the loop as a secondary safety measure + if (length(p_color) < 0.1) { + dist *= black_bias; + } + //*/ + if (dist < best_dist) { + best_dist = dist; + best_color = p_color; + } } + final_rgb = best_color; } -//*/ - COLOR = vec4(best_color, 1.0); + + COLOR = vec4(final_rgb, 1.0); } void vertex() { diff --git a/block/Scenes/Projectile_1.gd b/block/Scenes/Projectile_1.gd index c629645..02c8efa 100644 --- a/block/Scenes/Projectile_1.gd +++ b/block/Scenes/Projectile_1.gd @@ -23,7 +23,7 @@ func _draw(): func _process(delta: float) -> void: position += direction * speed * delta #position += playerDirection * speed * delta - look_at(player.global_position) + #look_at(player.global_position) #look_at(direction)# @@ -31,9 +31,6 @@ func get_facing_direction(): # Get the direction vector based on the node's current rotation var direction_vector: Vector2 = Vector2.from_angle(rotation) return direction_vector - -func changeTrajectory(direction_vector: Vector2): - rotation = rad_to_deg(atan2(direction_vector.y, direction_vector.x)) func changeDirection(normal: Vector2): print("direction:", direction) @@ -41,9 +38,9 @@ func changeDirection(normal: Vector2): direction = normal #direction = newDirection #direction = direction.bounce(perp_line) - rotation = rad_to_deg(direction.angle()) + rotation = direction.angle() print("direction:", direction) func bounce(normal: Vector2): direction = direction.bounce(normal) - rotation = rad_to_deg(direction.angle()) + rotation = direction.angle() diff --git a/block/Scenes/ShaderTest.tscn b/block/Scenes/ShaderTest.tscn index 722891e..0b4c72d 100644 --- a/block/Scenes/ShaderTest.tscn +++ b/block/Scenes/ShaderTest.tscn @@ -11,8 +11,9 @@ shader_parameter/palette_texture = ExtResource("4_vet50") shader_parameter/palette_size = 16 shader_parameter/pixel_size = 256.0 shader_parameter/color_levels = 8.0 -shader_parameter/PXwidth = 640.0 -shader_parameter/PXheight = 360.0 +shader_parameter/black_bias = 0.6 +shader_parameter/outline_sensitivity = 0.25 +shader_parameter/target_resolution = Vector2(640, 360) [node name="ShaderTest" type="Node2D" unique_id=1126703629] @@ -25,6 +26,7 @@ texture = ExtResource("2_ipaa6") layer = 10 [node name="ColorRect" type="ColorRect" parent="CanvasLayer" unique_id=570744568] +texture_filter = 2 material = SubResource("ShaderMaterial_exucn") anchors_preset = 15 anchor_right = 1.0