Skip to content

Commit

Permalink
Multi pass rendering and updated sampling
Browse files Browse the repository at this point in the history
  • Loading branch information
cybereality committed Jan 20, 2022
1 parent 03e9f23 commit 7e72d6c
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 96 deletions.
46 changes: 1 addition & 45 deletions SuperScaling/SuperScaling.tres → SuperScaling/Averaging.tres
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ 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;
Expand All @@ -23,9 +22,6 @@ 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.25, 0.75);

// finds the absolute distance from two floats
float float_diff(float float_a, float float_b) {
return abs(float_a - float_b);
Expand Down Expand Up @@ -114,44 +110,6 @@ 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;
Expand All @@ -174,9 +132,7 @@ void vertex() {

// draw the new color on the screen
void fragment() {
vec4 dir_avg = directional_average();
vec4 super = super_sample(UV, FRAGCOORD, view_pixel_size);
vec4 result = mix(dir_avg, super, smoothness);
vec4 result = directional_average();
result.a = 1.0;
COLOR = result;
}
Expand Down
65 changes: 65 additions & 0 deletions SuperScaling/Super.tres
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
[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.28, 0.56);

// 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;
}"
131 changes: 80 additions & 51 deletions SuperScaling/SuperScaling.gd
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,21 @@
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 sampler_shader = load(get_script().resource_path.get_base_dir() + "/SuperScaling.tres")
var sampler_material
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
var game_node
var overlay
var averaging_overlay
var super_overlay
var viewport
var super_viewport
var viewport_size
var root_viewport
var native_resolution
Expand All @@ -30,10 +33,14 @@ 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)
get_parent().call_deferred("add_child", viewport)
super_viewport.call_deferred("add_child", viewport)
get_parent().call_deferred("add_child", super_viewport)
original_resolution = native_resolution
original_aspect_ratio = native_aspect_ratio
root_viewport = get_viewport()
Expand All @@ -42,10 +49,8 @@ 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:
Expand All @@ -63,27 +68,51 @@ 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():
overlay = ColorRect.new()
overlay.name = "SamplerOverlay"
sampler_material = ShaderMaterial.new()
sampler_material.shader = sampler_shader
overlay.material = sampler_material
add_child(overlay)
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)

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()
sampler_material.set_shader_param("viewport", view_texture)
averaging_material.set_shader_param("viewport", view_texture)
super_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 sampler_material:
sampler_material.set_shader_param("view_resolution", viewport_size)
if averaging_material:
averaging_material.set_shader_param("view_resolution", viewport_size)
if super_material:
super_material.set_shader_param("view_resolution", viewport_size)

func get_screen_size():
var window = OS.window_size
Expand All @@ -110,6 +139,8 @@ 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:
Expand All @@ -132,84 +163,82 @@ 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 overlay:
if averaging_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":
overlay.rect_size = Vector2(round(original_resolution.x), round(original_resolution.x / native_aspect_ratio))
averaging_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":
overlay.rect_size = Vector2(round(original_resolution.y * native_aspect_ratio), round(original_resolution.y))
averaging_overlay.rect_size = Vector2(round(original_resolution.y * native_aspect_ratio), round(original_resolution.y))
else:
overlay.rect_size = Vector2(round(original_resolution.x), round(original_resolution.y))
averaging_overlay.rect_size = Vector2(round(original_resolution.x), round(original_resolution.y))
elif usage == USAGE_3D:
overlay.rect_size = Vector2(round(native_resolution.x), round(native_resolution.y))
averaging_overlay.rect_size = Vector2(round(native_resolution.x), round(native_resolution.y))
if aspect_diff > 1.0 + epsilon:
overlay.rect_size.x = round(native_resolution.y * original_aspect_ratio)
averaging_overlay.rect_size.x = round(native_resolution.y * original_aspect_ratio)
elif aspect_diff < 1.0 - epsilon:
overlay.rect_size.y = round(native_resolution.x / original_aspect_ratio)
var overlay_size = overlay.rect_size
averaging_overlay.rect_size.y = round(native_resolution.x / original_aspect_ratio)
var overlay_size = averaging_overlay.rect_size
var screen_size = Vector2(0.0, 0.0)
if usage == USAGE_2D:
screen_size = original_resolution
elif usage == USAGE_3D:
screen_size = native_resolution
if stretch_setting == "disabled" or usage == USAGE_2D:
if aspect_setting == "keep":
overlay.rect_position.x = 0
overlay.rect_position.y = 0
averaging_overlay.rect_position.x = 0
averaging_overlay.rect_position.y = 0
elif aspect_setting == "keep_width" or aspect_setting == "keep_height":
overlay.rect_position.x = 0
overlay.rect_position.y = 0
averaging_overlay.rect_position.x = 0
averaging_overlay.rect_position.y = 0
if usage == USAGE_3D:
if aspect_diff > 1.0 + epsilon:
overlay.rect_position.x = round((screen_size.x * aspect_diff - overlay_size.x) * 0.5)
averaging_overlay.rect_position.x = round((screen_size.x * aspect_diff - overlay_size.x) * 0.5)
elif aspect_diff < 1.0 - epsilon:
overlay.rect_position.y = round((screen_size.y / aspect_diff - overlay_size.y) * 0.5)
averaging_overlay.rect_position.y = round((screen_size.y / aspect_diff - overlay_size.y) * 0.5)
elif aspect_setting == "expand":
if usage == USAGE_3D:
overlay.rect_size = screen_size
averaging_overlay.rect_size = screen_size
elif aspect_diff > 1.0 + epsilon:
overlay.rect_size = Vector2(round(screen_size.x * aspect_diff), round(screen_size.y))
averaging_overlay.rect_size = Vector2(round(screen_size.x * aspect_diff), round(screen_size.y))
elif aspect_diff < 1.0 - epsilon:
overlay.rect_size = Vector2(round(screen_size.x), round(screen_size.y / aspect_diff))
averaging_overlay.rect_size = Vector2(round(screen_size.x), round(screen_size.y / aspect_diff))
else:
overlay.rect_size = screen_size
averaging_overlay.rect_size = screen_size
elif aspect_setting == "ignore":
if usage == USAGE_3D:
overlay.rect_size = screen_size
averaging_overlay.rect_size = screen_size
elif stretch_setting == "viewport":
overlay.rect_size = native_resolution
averaging_overlay.rect_size = native_resolution
elif stretch_setting == "2d":
overlay.rect_size = original_resolution
overlay_size = overlay.rect_size
overlay.rect_position.x = 0
overlay.rect_position.y = 0
averaging_overlay.rect_size = original_resolution
overlay_size = averaging_overlay.rect_size
averaging_overlay.rect_position.x = 0
averaging_overlay.rect_position.y = 0
if aspect_setting == "expand":
if aspect_diff > 1.0 + epsilon:
overlay.rect_size = Vector2(round(original_resolution.y * native_aspect_ratio), round(original_resolution.y))
averaging_overlay.rect_size = Vector2(round(original_resolution.y * native_aspect_ratio), round(original_resolution.y))
elif aspect_diff < 1.0 - epsilon:
overlay.rect_size = Vector2(round(original_resolution.x), round(original_resolution.x / native_aspect_ratio))
averaging_overlay.rect_size = Vector2(round(original_resolution.x), round(original_resolution.x / native_aspect_ratio))
elif aspect_setting == "keep_width":
overlay.rect_position.x = 0.0
averaging_overlay.rect_position.x = 0.0
if aspect_diff < 1.0 - epsilon:
overlay.rect_position.y = round((overlay_size.y / aspect_diff - overlay_size.y) * 0.5)
averaging_overlay.rect_position.y = round((overlay_size.y / aspect_diff - overlay_size.y) * 0.5)
elif aspect_setting == "keep_height":
overlay.rect_position.y = 0.0
averaging_overlay.rect_position.y = 0.0
if aspect_diff > 1.0 + epsilon:
overlay.rect_position.x = round((overlay_size.x * aspect_diff - overlay_size.x) * 0.5)
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

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
Expand Down

0 comments on commit 7e72d6c

Please sign in to comment.