From 0d6e12a0c58cd839365e8bc03914a2ebd5e39a53 Mon Sep 17 00:00:00 2001 From: Andres Hernandez Date: Fri, 21 Jan 2022 02:15:37 -0800 Subject: [PATCH] Reverted to single pass and fixed clarity --- SuperScaling.zip | Bin 0 -> 6078 bytes SuperScaling/Super.tres | 65 --------- SuperScaling/SuperScaling.gd | 131 +++++++----------- .../{Averaging.tres => SuperScaling.tres} | 46 +++++- 4 files changed, 96 insertions(+), 146 deletions(-) create mode 100644 SuperScaling.zip delete mode 100644 SuperScaling/Super.tres rename SuperScaling/{Averaging.tres => SuperScaling.tres} (77%) diff --git a/SuperScaling.zip b/SuperScaling.zip new file mode 100644 index 0000000000000000000000000000000000000000..9c721baa261df8d2291d20715e2e18e9bf43dd97 GIT binary patch literal 6078 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 literal 0 HcmV?d00001 diff --git a/SuperScaling/Super.tres b/SuperScaling/Super.tres deleted file mode 100644 index ade0d00..0000000 --- a/SuperScaling/Super.tres +++ /dev/null @@ -1,65 +0,0 @@ -[gd_resource type="Shader" format=2] - -[resource] -code = "// [Godot Super Scaling] -// created by Andres Hernandez -shader_type canvas_item; -render_mode unshaded; - -// viewport to sample and its resolution -uniform sampler2D viewport; -uniform vec2 view_resolution; -varying vec2 view_pixel_size; - -// offset coordinates used for super sampling -const vec2 offset_uv = vec2(0.24, 0.38); - -// partial derivative on x-axis -vec2 deriv_x(vec2 pos, vec4 frag, vec2 pixel) { - vec2 offset = vec2(pixel.x, 0.0); - vec2 pos_plus = pos + offset; - vec2 pos_minus = pos - offset; - int coord = int(frag.x) / 2; - bool even = int(coord * 2) == int(frag.x); - return even ? (pos_plus - pos) : (pos - pos_minus); -} - -// partial derivative on y-axis -vec2 deriv_y(vec2 pos, vec4 frag, vec2 pixel) { - vec2 offset = vec2(0.0, pixel.y); - vec2 pos_plus = pos + offset; - vec2 pos_minus = pos - offset; - int coord = int(frag.y) / 2; - bool even = int(coord * 2) == int(frag.y); - return even ? (pos_plus - pos) : (pos - pos_minus); -} - -// take 4 samples in a rotated grid for super sampling -vec4 super_sample(vec2 base_uv, vec4 frag, vec2 pixel) { - vec2 dx = deriv_x(base_uv, frag, pixel); - vec2 dy = deriv_y(base_uv, frag, pixel); - vec2 uv = vec2(0.0); - vec4 color = vec4(0.0); - uv = base_uv + offset_uv.x * dx + offset_uv.y * dy; - color += textureLod(viewport, uv, 0.0); - uv = base_uv - offset_uv.x * dx - offset_uv.y * dy; - color += textureLod(viewport, uv, 0.0); - uv = base_uv + offset_uv.y * dx - offset_uv.x * dy; - color += textureLod(viewport, uv, 0.0); - uv = base_uv - offset_uv.y * dx + offset_uv.x * dy; - color += textureLod(viewport, uv, 0.0); - color *= 0.25; - return color; -} - -// precompute the sample direction texture coordinates -void vertex() { - view_pixel_size = 1.0 / view_resolution; -} - -// draw the new color on the screen -void fragment() { - vec4 result = super_sample(UV, FRAGCOORD, view_pixel_size); - result.a = 1.0; - COLOR = result; -}" diff --git a/SuperScaling/SuperScaling.gd b/SuperScaling/SuperScaling.gd index 51928a9..e8490dd 100644 --- a/SuperScaling/SuperScaling.gd +++ b/SuperScaling/SuperScaling.gd @@ -3,21 +3,18 @@ extends Node export (float, 0.1, 2.0) var scale_factor = 1.0 setget change_scale_factor +export (float, 0.0, 1.0) var smoothness = 0.5 setget change_smoothness export (bool) var enable_on_play = false export (NodePath) var game_world export (int, "3D", "2D") var usage = 0 export (int, "Disabled", "2X", "4X", "8X", "16X") var msaa = 0 setget change_msaa export (bool) var fxaa = false setget change_fxaa export (int, 1, 4096) var shadow_atlas = 4096 setget change_shadow_atlas -onready var averaging_shader = load(get_script().resource_path.get_base_dir() + "/Averaging.tres") -onready var super_shader = load(get_script().resource_path.get_base_dir() + "/Super.tres") -var averaging_material -var super_material +onready var sampler_shader = load(get_script().resource_path.get_base_dir() + "/SuperScaling.tres") +var sampler_material var game_node -var averaging_overlay -var super_overlay +var overlay var viewport -var super_viewport var viewport_size var root_viewport var native_resolution @@ -33,14 +30,10 @@ func _ready(): if game_node: get_parent().call_deferred("remove_child", game_node) get_screen_size() - create_sampler() - create_super() create_viewport() - create_super_viewport() set_shader_texture() viewport.call_deferred("add_child", game_node) - super_viewport.call_deferred("add_child", viewport) - get_parent().call_deferred("add_child", super_viewport) + get_parent().call_deferred("add_child", viewport) original_resolution = native_resolution original_aspect_ratio = native_aspect_ratio root_viewport = get_viewport() @@ -49,8 +42,10 @@ func _ready(): #warning-ignore:RETURN_VALUE_DISCARDED root_viewport.connect("size_changed", self, "on_window_resize") on_window_resize() + create_sampler() change_msaa(msaa) change_fxaa(fxaa) + change_smoothness(smoothness) set_process_input(false) set_process_unhandled_input(false) else: @@ -68,51 +63,27 @@ func create_viewport(): viewport.msaa = Viewport.MSAA_DISABLED viewport.shadow_atlas_size = shadow_atlas -func create_super_viewport(): - super_viewport = Viewport.new() - super_viewport.name = "SuperViewport" - super_viewport.size = native_resolution - super_viewport.usage = Viewport.USAGE_3D if usage == USAGE_3D else Viewport.USAGE_2D - super_viewport.render_target_clear_mode = Viewport.CLEAR_MODE_NEVER - super_viewport.render_target_update_mode = Viewport.UPDATE_ALWAYS - super_viewport.render_target_v_flip = true - super_viewport.size_override_stretch = true - super_viewport.msaa = Viewport.MSAA_DISABLED - super_viewport.shadow_atlas_size = shadow_atlas - func create_sampler(): - averaging_overlay = ColorRect.new() - averaging_overlay.name = "AveragingOverlay" - averaging_material = ShaderMaterial.new() - averaging_material.shader = averaging_shader - averaging_overlay.material = averaging_material - averaging_overlay.visible = false - add_child(averaging_overlay) - -func create_super(): - super_overlay = ColorRect.new() - super_overlay.name = "SuperOverlay" - super_material = ShaderMaterial.new() - super_material.shader = super_shader - super_overlay.material = super_material - add_child(super_overlay) + overlay = ColorRect.new() + overlay.name = "SamplerOverlay" + sampler_material = ShaderMaterial.new() + sampler_material.shader = sampler_shader + overlay.material = sampler_material + add_child(overlay) func set_shader_texture(): yield(VisualServer, "frame_post_draw") var view_texture = viewport.get_texture() view_texture.flags = 0 view_texture.viewport_path = viewport.get_path() - averaging_material.set_shader_param("viewport", view_texture) - super_material.set_shader_param("viewport", view_texture) + sampler_material.set_shader_param("viewport", view_texture) change_scale_factor(scale_factor) set_process_input(true) set_process_unhandled_input(true) func set_shader_resolution(): - if averaging_material: - averaging_material.set_shader_param("view_resolution", viewport_size) - if super_material: - super_material.set_shader_param("view_resolution", viewport_size) + if sampler_material: + sampler_material.set_shader_param("view_resolution", viewport_size) func get_screen_size(): var window = OS.window_size @@ -139,8 +110,6 @@ func set_viewport_size(): func resize_viewport(): if viewport: viewport.size = viewport_size - if super_viewport: - super_viewport.size = viewport_size func scale_viewport_canvas(): if viewport: @@ -163,27 +132,26 @@ func scale_viewport_canvas(): viewport.set_size_override(true, Vector2(round(original_resolution.x * aspect_diff), round(original_resolution.y))) elif aspect_diff < 1.0 - epsilon: viewport.set_size_override(true, Vector2(round(original_resolution.x), round(original_resolution.y / aspect_diff))) - super_viewport.set_size_override(true, viewport.size) func set_sampler_size(): - if averaging_overlay: + if overlay: var stretch_setting = get_stretch_setting() var aspect_setting = get_aspect_setting() var aspect_diff = native_aspect_ratio / original_aspect_ratio if usage == USAGE_2D: if aspect_diff < 1.0 - epsilon and aspect_setting == "keep_width": - averaging_overlay.rect_size = Vector2(round(original_resolution.x), round(original_resolution.x / native_aspect_ratio)) + overlay.rect_size = Vector2(round(original_resolution.x), round(original_resolution.x / native_aspect_ratio)) elif aspect_diff > 1.0 + epsilon and aspect_setting == "keep_height": - averaging_overlay.rect_size = Vector2(round(original_resolution.y * native_aspect_ratio), round(original_resolution.y)) + overlay.rect_size = Vector2(round(original_resolution.y * native_aspect_ratio), round(original_resolution.y)) else: - averaging_overlay.rect_size = Vector2(round(original_resolution.x), round(original_resolution.y)) + overlay.rect_size = Vector2(round(original_resolution.x), round(original_resolution.y)) elif usage == USAGE_3D: - averaging_overlay.rect_size = Vector2(round(native_resolution.x), round(native_resolution.y)) + overlay.rect_size = Vector2(round(native_resolution.x), round(native_resolution.y)) if aspect_diff > 1.0 + epsilon: - averaging_overlay.rect_size.x = round(native_resolution.y * original_aspect_ratio) + overlay.rect_size.x = round(native_resolution.y * original_aspect_ratio) elif aspect_diff < 1.0 - epsilon: - averaging_overlay.rect_size.y = round(native_resolution.x / original_aspect_ratio) - var overlay_size = averaging_overlay.rect_size + overlay.rect_size.y = round(native_resolution.x / original_aspect_ratio) + var overlay_size = overlay.rect_size var screen_size = Vector2(0.0, 0.0) if usage == USAGE_2D: screen_size = original_resolution @@ -191,54 +159,57 @@ func set_sampler_size(): screen_size = native_resolution if stretch_setting == "disabled" or usage == USAGE_2D: if aspect_setting == "keep": - averaging_overlay.rect_position.x = 0 - averaging_overlay.rect_position.y = 0 + overlay.rect_position.x = 0 + overlay.rect_position.y = 0 elif aspect_setting == "keep_width" or aspect_setting == "keep_height": - averaging_overlay.rect_position.x = 0 - averaging_overlay.rect_position.y = 0 + overlay.rect_position.x = 0 + overlay.rect_position.y = 0 if usage == USAGE_3D: if aspect_diff > 1.0 + epsilon: - averaging_overlay.rect_position.x = round((screen_size.x * aspect_diff - overlay_size.x) * 0.5) + overlay.rect_position.x = round((screen_size.x * aspect_diff - overlay_size.x) * 0.5) elif aspect_diff < 1.0 - epsilon: - averaging_overlay.rect_position.y = round((screen_size.y / aspect_diff - overlay_size.y) * 0.5) + overlay.rect_position.y = round((screen_size.y / aspect_diff - overlay_size.y) * 0.5) elif aspect_setting == "expand": if usage == USAGE_3D: - averaging_overlay.rect_size = screen_size + overlay.rect_size = screen_size elif aspect_diff > 1.0 + epsilon: - averaging_overlay.rect_size = Vector2(round(screen_size.x * aspect_diff), round(screen_size.y)) + overlay.rect_size = Vector2(round(screen_size.x * aspect_diff), round(screen_size.y)) elif aspect_diff < 1.0 - epsilon: - averaging_overlay.rect_size = Vector2(round(screen_size.x), round(screen_size.y / aspect_diff)) + overlay.rect_size = Vector2(round(screen_size.x), round(screen_size.y / aspect_diff)) else: - averaging_overlay.rect_size = screen_size + overlay.rect_size = screen_size elif aspect_setting == "ignore": if usage == USAGE_3D: - averaging_overlay.rect_size = screen_size + overlay.rect_size = screen_size elif stretch_setting == "viewport": - averaging_overlay.rect_size = native_resolution + overlay.rect_size = native_resolution elif stretch_setting == "2d": - averaging_overlay.rect_size = original_resolution - overlay_size = averaging_overlay.rect_size - averaging_overlay.rect_position.x = 0 - averaging_overlay.rect_position.y = 0 + overlay.rect_size = original_resolution + overlay_size = overlay.rect_size + overlay.rect_position.x = 0 + overlay.rect_position.y = 0 if aspect_setting == "expand": if aspect_diff > 1.0 + epsilon: - averaging_overlay.rect_size = Vector2(round(original_resolution.y * native_aspect_ratio), round(original_resolution.y)) + overlay.rect_size = Vector2(round(original_resolution.y * native_aspect_ratio), round(original_resolution.y)) elif aspect_diff < 1.0 - epsilon: - averaging_overlay.rect_size = Vector2(round(original_resolution.x), round(original_resolution.x / native_aspect_ratio)) + overlay.rect_size = Vector2(round(original_resolution.x), round(original_resolution.x / native_aspect_ratio)) elif aspect_setting == "keep_width": - averaging_overlay.rect_position.x = 0.0 + overlay.rect_position.x = 0.0 if aspect_diff < 1.0 - epsilon: - averaging_overlay.rect_position.y = round((overlay_size.y / aspect_diff - overlay_size.y) * 0.5) + overlay.rect_position.y = round((overlay_size.y / aspect_diff - overlay_size.y) * 0.5) elif aspect_setting == "keep_height": - averaging_overlay.rect_position.y = 0.0 + overlay.rect_position.y = 0.0 if aspect_diff > 1.0 + epsilon: - averaging_overlay.rect_position.x = round((overlay_size.x * aspect_diff - overlay_size.x) * 0.5) - super_overlay.rect_size = averaging_overlay.rect_size - super_overlay.rect_position = averaging_overlay.rect_position + overlay.rect_position.x = round((overlay_size.x * aspect_diff - overlay_size.x) * 0.5) func change_scale_factor(val): scale_factor = val on_window_resize() + +func change_smoothness(val): + smoothness = val + if sampler_material: + sampler_material.set_shader_param("smoothness", smoothness) func change_msaa(val): msaa = val diff --git a/SuperScaling/Averaging.tres b/SuperScaling/SuperScaling.tres similarity index 77% rename from SuperScaling/Averaging.tres rename to SuperScaling/SuperScaling.tres index 1ad689d..c1b0d8a 100644 --- a/SuperScaling/Averaging.tres +++ b/SuperScaling/SuperScaling.tres @@ -10,6 +10,7 @@ render_mode unshaded; uniform sampler2D viewport; uniform vec2 view_resolution; varying vec2 view_pixel_size; +uniform float smoothness; // texture coords for directional sampling varying vec2 center_pixel; @@ -22,6 +23,9 @@ varying vec2 north_west_pixel; varying vec2 south_east_pixel; varying vec2 south_west_pixel; +// offset coordinates used for super sampling +const vec2 offset_uv = vec2(0.36, 0.64); + // finds the absolute distance from two floats float float_diff(float float_a, float float_b) { return abs(float_a - float_b); @@ -110,6 +114,44 @@ vec4 directional_average() { return result; } +// partial derivative on x-axis +vec2 deriv_x(vec2 pos, vec4 frag, vec2 pixel) { + vec2 offset = vec2(pixel.x, 0.0); + vec2 pos_plus = pos + offset; + vec2 pos_minus = pos - offset; + int coord = int(frag.x) / 2; + bool even = int(coord * 2) == int(frag.x); + return even ? (pos_plus - pos) : (pos - pos_minus); +} + +// partial derivative on y-axis +vec2 deriv_y(vec2 pos, vec4 frag, vec2 pixel) { + vec2 offset = vec2(0.0, pixel.y); + vec2 pos_plus = pos + offset; + vec2 pos_minus = pos - offset; + int coord = int(frag.y) / 2; + bool even = int(coord * 2) == int(frag.y); + return even ? (pos_plus - pos) : (pos - pos_minus); +} + +// take 4 samples in a rotated grid for super sampling +vec4 super_sample(vec2 base_uv, vec4 frag, vec2 pixel) { + vec2 dx = deriv_x(base_uv, frag, pixel); + vec2 dy = deriv_y(base_uv, frag, pixel); + vec2 uv = vec2(0.0); + vec4 color = vec4(0.0); + uv = base_uv + offset_uv.x * dx + offset_uv.y * dy; + color += textureLod(viewport, uv, 0.0); + uv = base_uv - offset_uv.x * dx - offset_uv.y * dy; + color += textureLod(viewport, uv, 0.0); + uv = base_uv + offset_uv.y * dx - offset_uv.x * dy; + color += textureLod(viewport, uv, 0.0); + uv = base_uv - offset_uv.y * dx + offset_uv.x * dy; + color += textureLod(viewport, uv, 0.0); + color *= 0.25; + return color; +} + // precompute the sample direction texture coordinates void vertex() { view_pixel_size = 1.0 / view_resolution; @@ -132,7 +174,9 @@ void vertex() { // draw the new color on the screen void fragment() { - vec4 result = directional_average(); + vec4 dir_avg = directional_average(); + vec4 super = super_sample(UV, FRAGCOORD, view_pixel_size); + vec4 result = mix(dir_avg, super, smoothness); result.a = 1.0; COLOR = result; }