Complete overhaul, new implementations

- Overhauled file structure to be on addons for universality
- Streamlined compositor shader stages with custom classes and resources
- Added previous proven implementations (McGuire, Guertin)
- entirely new and improved jump flood implementation, more realistic, robust, and performant
This commit is contained in:
sphynx-owner
2024-08-10 15:20:51 +03:00
parent e1d14a7f74
commit 31fed9641a
93 changed files with 4130 additions and 718 deletions

View File

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2024 sphynx-owner
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,14 +0,0 @@
[remap]
importer="glsl"
type="RDShaderFile"
uid="uid://3v1b0hrdm7nw"
path="res://.godot/imported/jfp_backtracking_experimental.glsl-d67307f6899fed647164be410a7debc8.res"
[deps]
source_file="res://MyJumpFloodIteration/jfp_backtracking_experimental.glsl"
dest_files=["res://.godot/imported/jfp_backtracking_experimental.glsl-d67307f6899fed647164be410a7debc8.res"]
[params]

View File

@ -1,355 +0,0 @@
extends CompositorEffect
class_name MotionBlurSphynxJumpFlood
@export_group("Motion Blur", "motion_blur_")
# diminishing returns over 16
@export_range(4, 64) var motion_blur_samples: int = 8
# you really don't want this over 0.5, but you can if you want to try
@export_range(0, 0.5, 0.001, "or_greater") var motion_blur_intensity: float = 1
@export_range(0, 1) var motion_blur_center_fade: float = 0.0
@export var blur_shader_file : RDShaderFile = preload("res://addons/MyJumpFloodIteration/jump_flood_blur.glsl"):
set(value):
blur_shader_file = value
_init()
@export var overlay_shader_file : RDShaderFile = preload("res://addons/MyJumpFloodIteration/jump_flood_overlay.glsl"):
set(value):
overlay_shader_file = value
_init()
@export var construction_pass : RDShaderFile = preload("res://addons/MyJumpFloodIteration/jfp_backtracking_experimental.glsl"):
set(value):
construction_pass = value
_init()
## the portion of speed that is allowed for side bleed of velocities
## during the jfa dilation passes and before backtracking. Getting this a higher value
## would make it so that meshes at movement blur more reliably, but also bleed
## further perpendicularly to their velocity, thus wash elemets behind them out.
@export var perpen_error_threshold : float = 0.3
## an initial step size that can increase the dilation radius proportionally, at the
## sacrifice of some quality in the final resolution of the dilation.[br][br]
## the formula for the maximum radius of the dilation (in pixels) is: pow(2 + step_exponent_modifier, JFA_pass_count) * sample_step_multiplier
@export var sample_step_multiplier : float = 4
## by default, the jump flood makes samples along distances that start
## at 2 to the power of the pass count you want to perform, which is also
## the dilation radius you desire. You can change it to values higher than
## 2 with this variable, and reach higher dilation radius at the sacrifice of
## some accuracy in the dilation.
## the formula for the maximum radius of the dilation (in pixels) is: pow(2 + step_exponent_modifier, JFA_pass_count) * sample_step_multiplier
@export var step_exponent_modifier : float = 1
## how many steps along a range of 2 velocities from the
## dilation target velocity space do we go along to find a better fitting velocity sample
## higher samples meaning higher detail getting captured and blurred
@export var backtracking_sample_count : int = 8
## how sensitive the backtracking for velocities be
@export var backtracking_velocity_match_threshold : float = 0.9
## how sensitively the backtracking should treat velocities that are a different
## length along that velocity
@export var backtracking_velocity_match_parallel_sensitivity : float = 1
## how sensitively the backtracking should treat velcoities that have perpendicular
## offset to that velocity
@export var backtracking_velcoity_match_perpendicular_sensitivity : float = 0.05
## how closely does the depth of the backtracked sample has to match the original sample to be
## considered (in NDC space)
@export var backtracbing_depth_match_threshold : float = 0.001
## the number of passes performed by the jump flood algorithm based dilation,
## each pass added doubles the maximum radius of dilation available.[br][br]
## the formula for the maximum radius of the dilation (in pixels) is: pow(2 + step_exponent_modifier, JFA_pass_count) * sample_step_multiplier
@export var JFA_pass_count : int = 3
## wether this motion blur stays the same intensity below
## target_constant_framerate
@export var framerate_independent : bool = true
## Description: Removes clamping on motion blur scale to allow framerate independent motion
## blur to scale longer than realistically possible when render framerate is higher
## than target framerate.[br][br]
## [color=yellow]Warning:[/color] Turning this on would allow over-blurring of pixels, which
## produces inaccurate results, and would likely cause nausea in players over
## long exposure durations, use with caution and out of artistic intent
@export var uncapped_independence : bool = false
## if framerate_independent is enabled, the blur would simulate
## sutter speeds at that framerate, and up.
@export var target_constant_framerate : float = 30
## wether to display debug views for velocity and depth
## buffers
@export var draw_debug : bool = false
## currently 0 - 1, flip between velocity buffers
## and depth buffers debug views
@export var debug_page : int = 0
var rd: RenderingDevice
var linear_sampler: RID
var nearest_sampler : RID
var construct_shader : RID
var construct_pipeline : RID
var motion_blur_shader: RID
var motion_blur_pipeline: RID
var overlay_shader: RID
var overlay_pipeline: RID
var context: StringName = "MotionBlur"
var texture: StringName = "texture"
var buffer_a : StringName = "buffer_a"
var buffer_b : StringName = "buffer_b"
var past_color : StringName = "past_color"
var custom_velocity : StringName = "custom_velocity"
var freeze : bool = false
func _init():
#effect_callback_type = EFFECT_CALLBACK_TYPE_POST_TRANSPARENT
needs_motion_vectors = true
RenderingServer.call_on_render_thread(_initialize_compute)
func _notification(what):
if what == NOTIFICATION_PREDELETE:
if linear_sampler.is_valid():
rd.free_rid(linear_sampler)
if motion_blur_shader.is_valid():
rd.free_rid(motion_blur_shader)
if overlay_shader.is_valid():
rd.free_rid(overlay_shader)
func _initialize_compute():
rd = RenderingServer.get_rendering_device()
if !rd:
return
var sampler_state := RDSamplerState.new()
sampler_state.min_filter = RenderingDevice.SAMPLER_FILTER_LINEAR
sampler_state.mag_filter = RenderingDevice.SAMPLER_FILTER_LINEAR
sampler_state.repeat_u = RenderingDevice.SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE
sampler_state.repeat_v = RenderingDevice.SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE
linear_sampler = rd.sampler_create(sampler_state)
sampler_state.min_filter = RenderingDevice.SAMPLER_FILTER_NEAREST
sampler_state.mag_filter = RenderingDevice.SAMPLER_FILTER_NEAREST
sampler_state.repeat_u = RenderingDevice.SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE
sampler_state.repeat_v = RenderingDevice.SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE
nearest_sampler = rd.sampler_create(sampler_state)
var construct_shader_spirv : RDShaderSPIRV = construction_pass.get_spirv()
construct_shader = rd.shader_create_from_spirv(construct_shader_spirv)
construct_pipeline = rd.compute_pipeline_create(construct_shader)
var shader_spirv: RDShaderSPIRV = blur_shader_file.get_spirv()
motion_blur_shader = rd.shader_create_from_spirv(shader_spirv)
motion_blur_pipeline = rd.compute_pipeline_create(motion_blur_shader)
var overlay_shader_spirv: RDShaderSPIRV = overlay_shader_file.get_spirv()
overlay_shader = rd.shader_create_from_spirv(overlay_shader_spirv)
overlay_pipeline = rd.compute_pipeline_create(overlay_shader)
func get_image_uniform(image: RID, binding: int) -> RDUniform:
var uniform: RDUniform = RDUniform.new()
uniform.uniform_type = RenderingDevice.UNIFORM_TYPE_IMAGE
uniform.binding = binding
uniform.add_id(image)
return uniform
func get_sampler_uniform(image: RID, binding: int, linear : bool = true) -> RDUniform:
var uniform: RDUniform = RDUniform.new()
uniform.uniform_type = RenderingDevice.UNIFORM_TYPE_SAMPLER_WITH_TEXTURE
uniform.binding = binding
uniform.add_id(linear_sampler if linear else nearest_sampler)
uniform.add_id(image)
return uniform
var temp_motion_blur_intensity : float
var previous_time : float = 0
func _render_callback(p_effect_callback_type, p_render_data):
var time : float = float(Time.get_ticks_msec()) / 1000
var delta_time : float = time - previous_time
previous_time = time
temp_motion_blur_intensity = motion_blur_intensity
if framerate_independent:
var capped_frame_time : float = 1 / target_constant_framerate
if !uncapped_independence:
capped_frame_time = min(capped_frame_time, delta_time)
temp_motion_blur_intensity = motion_blur_intensity * capped_frame_time / delta_time
if rd:
var render_scene_buffers: RenderSceneBuffersRD = p_render_data.get_render_scene_buffers()
var render_scene_data: RenderSceneDataRD = p_render_data.get_render_scene_data()
if render_scene_buffers and render_scene_data:
var render_size: Vector2 = render_scene_buffers.get_internal_size()
if render_size.x == 0.0 or render_size.y == 0.0:
return
ensure_texture(texture, render_scene_buffers)
ensure_texture(buffer_a, render_scene_buffers, RenderingDevice.DATA_FORMAT_R16G16_SFLOAT)
ensure_texture(buffer_b, render_scene_buffers, RenderingDevice.DATA_FORMAT_R16G16_SFLOAT)
ensure_texture(past_color, render_scene_buffers)
ensure_texture(custom_velocity, render_scene_buffers)
rd.draw_command_begin_label("Motion Blur", Color(1.0, 1.0, 1.0, 1.0))
var last_iteration_index : int = JFA_pass_count - 1;
var max_dilation_radius : float = pow(2 + step_exponent_modifier, last_iteration_index) * sample_step_multiplier / motion_blur_intensity;
var push_constant: PackedFloat32Array = [
motion_blur_samples, temp_motion_blur_intensity,
motion_blur_center_fade, 1 if draw_debug else 0,
freeze,
Engine.get_frames_drawn() % 8,
last_iteration_index,
sample_step_multiplier,
step_exponent_modifier,
max_dilation_radius,
0,
0
]
var int_push_constant : PackedInt32Array = [
debug_page,
0,
0,
0
]
var byte_array = push_constant.to_byte_array()
byte_array.append_array(int_push_constant.to_byte_array())
var view_count = render_scene_buffers.get_view_count()
for view in range(view_count):
var color_image := render_scene_buffers.get_color_layer(view)
var depth_image := render_scene_buffers.get_depth_layer(view)
var texture_image := render_scene_buffers.get_texture_slice(context, texture, view, 0, 1, 1)
var buffer_a_image := render_scene_buffers.get_texture_slice(context, buffer_a, view, 0, 1, 1)
var buffer_b_image := render_scene_buffers.get_texture_slice(context, buffer_b, view, 0, 1, 1)
var past_color_image := render_scene_buffers.get_texture_slice(context, past_color, view, 0, 1, 1)
var custom_velocity_image := render_scene_buffers.get_texture_slice(context, custom_velocity, view, 0, 1, 1)
rd.draw_command_begin_label("Construct blur " + str(view), Color(1.0, 1.0, 1.0, 1.0))
var tex_uniform_set
var compute_list
var x_groups := floori((render_size.x - 1) / 16 + 1)
var y_groups := floori((render_size.y - 1) / 16 + 1)
tex_uniform_set = UniformSetCacheRD.get_cache(construct_shader, 0, [
get_sampler_uniform(depth_image, 0, false),
get_sampler_uniform(custom_velocity_image, 1, false),
get_image_uniform(buffer_a_image, 2),
get_image_uniform(buffer_b_image, 3),
get_sampler_uniform(buffer_a_image, 4, false),
get_sampler_uniform(buffer_b_image, 5, false)
])
compute_list = rd.compute_list_begin()
rd.compute_list_bind_compute_pipeline(compute_list, construct_pipeline)
rd.compute_list_bind_uniform_set(compute_list, tex_uniform_set, 0)
for i in JFA_pass_count:
var jf_push_constants : PackedInt32Array = [
i,
last_iteration_index,
backtracking_sample_count,
16
]
var step_size : float = round(pow(2 + step_exponent_modifier, last_iteration_index - i)) * sample_step_multiplier;
var jf_float_push_constants_test : PackedFloat32Array = [
perpen_error_threshold,
sample_step_multiplier,
temp_motion_blur_intensity,
backtracking_velocity_match_threshold,
backtracking_velocity_match_parallel_sensitivity,
backtracking_velcoity_match_perpendicular_sensitivity,
backtracbing_depth_match_threshold,
step_exponent_modifier,
step_size,
max_dilation_radius,
0,
0
]
var jf_byte_array = jf_push_constants.to_byte_array()
jf_byte_array.append_array(jf_float_push_constants_test.to_byte_array())
rd.compute_list_set_push_constant(compute_list, jf_byte_array, jf_byte_array.size())
rd.compute_list_dispatch(compute_list, x_groups, y_groups, 1)
rd.compute_list_end()
rd.draw_command_end_label()
rd.draw_command_begin_label("Compute blur " + str(view), Color(1.0, 1.0, 1.0, 1.0))
tex_uniform_set = UniformSetCacheRD.get_cache(motion_blur_shader, 0, [
get_sampler_uniform(color_image, 0, false),
get_sampler_uniform(depth_image, 1, false),
get_sampler_uniform(custom_velocity_image, 2, false),
get_sampler_uniform(buffer_b_image if last_iteration_index % 2 else buffer_a_image, 3, false),
get_image_uniform(texture_image, 4),
get_image_uniform(past_color_image, 5),
])
compute_list = rd.compute_list_begin()
rd.compute_list_bind_compute_pipeline(compute_list, motion_blur_pipeline)
rd.compute_list_bind_uniform_set(compute_list, tex_uniform_set, 0)
rd.compute_list_set_push_constant(compute_list, byte_array, byte_array.size())
rd.compute_list_dispatch(compute_list, x_groups, y_groups, 1)
rd.compute_list_end()
rd.draw_command_end_label()
rd.draw_command_begin_label("Overlay result " + str(view), Color(1.0, 1.0, 1.0, 1.0))
tex_uniform_set = UniformSetCacheRD.get_cache(overlay_shader, 0, [
get_sampler_uniform(texture_image, 0),
get_image_uniform(color_image, 1),
])
compute_list = rd.compute_list_begin()
rd.compute_list_bind_compute_pipeline(compute_list, overlay_pipeline)
rd.compute_list_bind_uniform_set(compute_list, tex_uniform_set, 0)
rd.compute_list_dispatch(compute_list, x_groups, y_groups, 1)
rd.compute_list_end()
rd.draw_command_end_label()
rd.draw_command_end_label()
func ensure_texture(texture_name : StringName, render_scene_buffers : RenderSceneBuffersRD, texture_format : RenderingDevice.DataFormat = RenderingDevice.DATA_FORMAT_R16G16B16A16_SFLOAT, high_accuracy : bool = false, render_size_multiplier : Vector2 = Vector2(1, 1)):
var render_size : Vector2 = Vector2(render_scene_buffers.get_internal_size()) * render_size_multiplier
if render_scene_buffers.has_texture(context, texture_name):
var tf: RDTextureFormat = render_scene_buffers.get_texture_format(context, texture_name)
if tf.width != render_size.x or tf.height != render_size.y:
render_scene_buffers.clear_context(context)
if !render_scene_buffers.has_texture(context, texture_name):
var usage_bits: int = RenderingDevice.TEXTURE_USAGE_SAMPLING_BIT | RenderingDevice.TEXTURE_USAGE_STORAGE_BIT
render_scene_buffers.create_texture(context, texture_name, texture_format, usage_bits, RenderingDevice.TEXTURE_SAMPLES_1, render_size, 1, 1, true)

View File

@ -1,14 +0,0 @@
[remap]
importer="glsl"
type="RDShaderFile"
uid="uid://wfmvke70qcpa"
path="res://.godot/imported/jump_flood_blur.glsl-df0c6b7cc65d8b0520871790f9075253.res"
[deps]
source_file="res://MyJumpFloodIteration/jump_flood_blur.glsl"
dest_files=["res://.godot/imported/jump_flood_blur.glsl-df0c6b7cc65d8b0520871790f9075253.res"]
[params]

View File

@ -1,14 +0,0 @@
[remap]
importer="glsl"
type="RDShaderFile"
uid="uid://bbnb4hw0aoqy1"
path="res://.godot/imported/jump_flood_overlay.glsl-764d3c488a9e9576eab825591e868325.res"
[deps]
source_file="res://MyJumpFloodIteration/jump_flood_overlay.glsl"
dest_files=["res://.godot/imported/jump_flood_overlay.glsl-764d3c488a9e9576eab825591e868325.res"]
[params]

View File

@ -1,158 +0,0 @@
extends CompositorEffect
class_name PreBlurProcessor
@export var pre_blur_processor_shader_file : RDShaderFile = preload("res://addons/PreBlurProcessing/pre_blur_processor.glsl"):
set(value):
pre_blur_processor_shader_file = value
_init()
@export var camera_rotation_component : BlurVelocityComponentResource = preload("res://addons/PreBlurProcessing/default_component.tres")
@export var camera_movement_component : BlurVelocityComponentResource = preload("res://addons/PreBlurProcessing/default_component.tres")
@export var object_movement_component : BlurVelocityComponentResource = preload("res://addons/PreBlurProcessing/default_component.tres")
var context: StringName = "MotionBlur"
var rd: RenderingDevice
var linear_sampler: RID
var nearest_sampler : RID
var construct_shader : RID
var construct_pipeline : RID
var pre_blur_processor_shader: RID
var pre_blur_processor_pipeline: RID
var custom_velocity : StringName = "custom_velocity"
func _init():
needs_motion_vectors = true
RenderingServer.call_on_render_thread(_initialize_compute)
func _notification(what):
if what == NOTIFICATION_PREDELETE:
if linear_sampler.is_valid():
rd.free_rid(linear_sampler)
if pre_blur_processor_shader.is_valid():
rd.free_rid(pre_blur_processor_shader)
func _initialize_compute():
rd = RenderingServer.get_rendering_device()
if !rd:
return
var sampler_state := RDSamplerState.new()
sampler_state.min_filter = RenderingDevice.SAMPLER_FILTER_LINEAR
sampler_state.mag_filter = RenderingDevice.SAMPLER_FILTER_LINEAR
sampler_state.repeat_u = RenderingDevice.SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE
sampler_state.repeat_v = RenderingDevice.SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE
linear_sampler = rd.sampler_create(sampler_state)
sampler_state.min_filter = RenderingDevice.SAMPLER_FILTER_NEAREST
sampler_state.mag_filter = RenderingDevice.SAMPLER_FILTER_NEAREST
sampler_state.repeat_u = RenderingDevice.SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE
sampler_state.repeat_v = RenderingDevice.SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE
nearest_sampler = rd.sampler_create(sampler_state)
var shader_spirv: RDShaderSPIRV = pre_blur_processor_shader_file.get_spirv()
pre_blur_processor_shader = rd.shader_create_from_spirv(shader_spirv)
pre_blur_processor_pipeline = rd.compute_pipeline_create(pre_blur_processor_shader)
func get_image_uniform(image: RID, binding: int) -> RDUniform:
var uniform: RDUniform = RDUniform.new()
uniform.uniform_type = RenderingDevice.UNIFORM_TYPE_IMAGE
uniform.binding = binding
uniform.add_id(image)
return uniform
func get_sampler_uniform(image: RID, binding: int, linear : bool = true) -> RDUniform:
var uniform: RDUniform = RDUniform.new()
uniform.uniform_type = RenderingDevice.UNIFORM_TYPE_SAMPLER_WITH_TEXTURE
uniform.binding = binding
uniform.add_id(linear_sampler if linear else nearest_sampler)
uniform.add_id(image)
return uniform
func _render_callback(p_effect_callback_type, p_render_data : RenderData):
if rd:
var render_scene_buffers: RenderSceneBuffersRD = p_render_data.get_render_scene_buffers()
var render_scene_data: RenderSceneDataRD = p_render_data.get_render_scene_data()
if render_scene_buffers and render_scene_data:
var render_size: Vector2 = render_scene_buffers.get_internal_size()
if render_size.x == 0.0 or render_size.y == 0.0:
return
ensure_texture(custom_velocity, render_scene_buffers)
rd.draw_command_begin_label("Pre Blur Processing", Color(1.0, 1.0, 1.0, 1.0))
var float_pre_blur_push_constants: PackedFloat32Array = [
camera_rotation_component.multiplier,
camera_movement_component.multiplier,
object_movement_component.multiplier,
camera_rotation_component.lower_threshold,
camera_movement_component.lower_threshold,
object_movement_component.lower_threshold,
camera_rotation_component.upper_threshold,
camera_movement_component.upper_threshold,
object_movement_component.upper_threshold,
1 if true else 0,
0,
0,
]
var int_pre_blur_push_constants : PackedInt32Array = [
]
var byte_array = float_pre_blur_push_constants.to_byte_array()
byte_array.append_array(int_pre_blur_push_constants.to_byte_array())
var view_count = render_scene_buffers.get_view_count()
for view in range(view_count):
var depth_image := render_scene_buffers.get_depth_layer(view)
var velocity_image := render_scene_buffers.get_velocity_layer(view)
var custom_velocity_image := render_scene_buffers.get_texture_slice(context, custom_velocity, view, 0, 1, 1)
var scene_data_buffer : RID = render_scene_data.get_uniform_buffer()
var scene_data_buffer_uniform := RDUniform.new()
scene_data_buffer_uniform.uniform_type = RenderingDevice.UNIFORM_TYPE_UNIFORM_BUFFER
scene_data_buffer_uniform.binding = 5
scene_data_buffer_uniform.add_id(scene_data_buffer)
var tex_uniform_set
var compute_list
var x_groups := floori((render_size.x - 1) / 16 + 1)
var y_groups := floori((render_size.y - 1) / 16 + 1)
rd.draw_command_begin_label("Process Velocity Buffer " + str(view), Color(1.0, 1.0, 1.0, 1.0))
tex_uniform_set = UniformSetCacheRD.get_cache(pre_blur_processor_shader, 0, [
get_sampler_uniform(depth_image, 0, false),
get_sampler_uniform(velocity_image, 1, false),
get_image_uniform(custom_velocity_image, 2),
scene_data_buffer_uniform,
])
compute_list = rd.compute_list_begin()
rd.compute_list_bind_compute_pipeline(compute_list, pre_blur_processor_pipeline)
rd.compute_list_bind_uniform_set(compute_list, tex_uniform_set, 0)
rd.compute_list_set_push_constant(compute_list, byte_array, byte_array.size())
rd.compute_list_dispatch(compute_list, x_groups, y_groups, 1)
rd.compute_list_end()
rd.draw_command_end_label()
rd.draw_command_end_label()
func ensure_texture(texture_name : StringName, render_scene_buffers : RenderSceneBuffersRD, high_accuracy : bool = false, render_size_multiplier : Vector2 = Vector2(1, 1)):
var render_size : Vector2 = Vector2(render_scene_buffers.get_internal_size()) * render_size_multiplier
if render_scene_buffers.has_texture(context, texture_name):
var tf: RDTextureFormat = render_scene_buffers.get_texture_format(context, texture_name)
if tf.width != render_size.x or tf.height != render_size.y:
render_scene_buffers.clear_context(context)
if !render_scene_buffers.has_texture(context, texture_name):
var usage_bits: int = RenderingDevice.TEXTURE_USAGE_SAMPLING_BIT | RenderingDevice.TEXTURE_USAGE_STORAGE_BIT
var texture_format = RenderingDevice.DATA_FORMAT_R32G32B32A32_SFLOAT if high_accuracy else RenderingDevice.DATA_FORMAT_R16G16B16A16_SFLOAT
render_scene_buffers.create_texture(context, texture_name, texture_format, usage_bits, RenderingDevice.TEXTURE_SAMPLES_1, render_size, 1, 1, true)

View File

@ -1,14 +0,0 @@
[remap]
importer="glsl"
type="RDShaderFile"
uid="uid://ccg27o4i1gfty"
path="res://.godot/imported/pre_blur_processor.glsl-15aad2fcd84f6b03da65e9fe7bb8e345.res"
[deps]
source_file="res://PreBlurProcessing/pre_blur_processor.glsl"
dest_files=["res://.godot/imported/pre_blur_processor.glsl-15aad2fcd84f6b03da65e9fe7bb8e345.res"]
[params]

View File

@ -0,0 +1,144 @@
extends CompositorEffect
class_name EnhancedCompositorEffect
var rd: RenderingDevice
var linear_sampler: RID
var nearest_sampler : RID
var context: StringName = "PostProcess"
var all_shader_stages : Dictionary
func _init():
RenderingServer.call_on_render_thread(_initialize_compute)
func _notification(what):
if what == NOTIFICATION_PREDELETE:
if !rd:
return
if linear_sampler.is_valid():
rd.free_rid(linear_sampler)
if nearest_sampler.is_valid():
rd.free_rid(nearest_sampler)
for shader_stage in all_shader_stages.keys():
if shader_stage.pipeline.is_valid():
rd.free_rid(shader_stage.pipeline)
if shader_stage.shader.is_valid():
rd.free_rid(shader_stage.shader)
func subscirbe_shader_stage(shader_stage : ShaderStageResource):
if all_shader_stages.has(shader_stage):
return
all_shader_stages[shader_stage] = 1
if rd:
generate_shader_stage(shader_stage)
func unsubscribe_shader_stage(shader_stage : ShaderStageResource):
if all_shader_stages.has(shader_stage):
all_shader_stages.erase(shader_stage)
if !rd:
return
if shader_stage.shader.is_valid():
rd.free_rid(shader_stage.shader)
if shader_stage.pipeline.is_valid():
rd.free_rid(shader_stage.pipeline)
func _initialize_compute():
rd = RenderingServer.get_rendering_device()
if !rd:
return
var sampler_state := RDSamplerState.new()
sampler_state.min_filter = RenderingDevice.SAMPLER_FILTER_LINEAR
sampler_state.mag_filter = RenderingDevice.SAMPLER_FILTER_LINEAR
sampler_state.repeat_u = RenderingDevice.SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE
sampler_state.repeat_v = RenderingDevice.SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE
linear_sampler = rd.sampler_create(sampler_state)
sampler_state.min_filter = RenderingDevice.SAMPLER_FILTER_NEAREST
sampler_state.mag_filter = RenderingDevice.SAMPLER_FILTER_NEAREST
sampler_state.repeat_u = RenderingDevice.SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE
sampler_state.repeat_v = RenderingDevice.SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE
nearest_sampler = rd.sampler_create(sampler_state)
for shader_stage in all_shader_stages.keys():
generate_shader_stage(shader_stage)
func generate_shader_stage(shader_stage : ShaderStageResource):
var shader_spirv : RDShaderSPIRV = shader_stage.shader_file.get_spirv()
shader_stage.shader = rd.shader_create_from_spirv(shader_spirv)
shader_stage.pipeline = rd.compute_pipeline_create(shader_stage.shader)
func _render_callback(p_effect_callback_type, p_render_data):
if !rd:
return
var render_scene_buffers: RenderSceneBuffersRD = p_render_data.get_render_scene_buffers()
var render_scene_data: RenderSceneDataRD = p_render_data.get_render_scene_data()
if !render_scene_buffers or !render_scene_data:
return
var render_size: Vector2i = render_scene_buffers.get_internal_size()
if render_size.x == 0 or render_size.y == 0:
return
_render_callback_2(render_size, render_scene_buffers, render_scene_data)
func _render_callback_2(render_size : Vector2i, render_scene_buffers : RenderSceneBuffersRD, render_scene_data : RenderSceneDataRD):
pass
func ensure_texture(texture_name : StringName, render_scene_buffers : RenderSceneBuffersRD, texture_format : RenderingDevice.DataFormat = RenderingDevice.DATA_FORMAT_R16G16B16A16_SFLOAT, render_size_multiplier : Vector2 = Vector2(1, 1)):
var render_size : Vector2i = Vector2(render_scene_buffers.get_internal_size()) * render_size_multiplier
if render_scene_buffers.has_texture(context, texture_name):
var tf: RDTextureFormat = render_scene_buffers.get_texture_format(context, texture_name)
if tf.width != render_size.x or tf.height != render_size.y:
render_scene_buffers.clear_context(context)
if !render_scene_buffers.has_texture(context, texture_name):
var usage_bits: int = RenderingDevice.TEXTURE_USAGE_SAMPLING_BIT | RenderingDevice.TEXTURE_USAGE_STORAGE_BIT
render_scene_buffers.create_texture(context, texture_name, texture_format, usage_bits, RenderingDevice.TEXTURE_SAMPLES_1, render_size, 1, 1, true)
func get_image_uniform(image: RID, binding: int) -> RDUniform:
var uniform: RDUniform = RDUniform.new()
uniform.uniform_type = RenderingDevice.UNIFORM_TYPE_IMAGE
uniform.binding = binding
uniform.add_id(image)
return uniform
func get_sampler_uniform(image: RID, binding: int, linear : bool = true) -> RDUniform:
var uniform: RDUniform = RDUniform.new()
uniform.uniform_type = RenderingDevice.UNIFORM_TYPE_SAMPLER_WITH_TEXTURE
uniform.binding = binding
uniform.add_id(linear_sampler if linear else nearest_sampler)
uniform.add_id(image)
return uniform
func dispatch_stage(stage : ShaderStageResource, uniforms : Array[RDUniform], push_constants : PackedByteArray, dispatch_size : Vector3i, label : String = "DefaultLabel", view : int = 0, color : Color = Color(1, 1, 1, 1)):
rd.draw_command_begin_label(label + " " + str(view), color)
var tex_uniform_set = UniformSetCacheRD.get_cache(stage.shader, 0, uniforms)
var compute_list = rd.compute_list_begin()
rd.compute_list_bind_compute_pipeline(compute_list, stage.pipeline)
rd.compute_list_bind_uniform_set(compute_list, tex_uniform_set, 0)
if !push_constants.is_empty():
rd.compute_list_set_push_constant(compute_list, push_constants, push_constants.size())
rd.compute_list_dispatch(compute_list, dispatch_size.x, dispatch_size.y, dispatch_size.z)
rd.compute_list_end()
rd.draw_command_end_label()

View File

@ -0,0 +1,9 @@
extends EnhancedCompositorEffect
class_name MotionBlurCompositorEffect
func _init():
set_deferred("context", "MotionBlur")
super()
func _get_max_dilation_range() -> float:
return 0

View File

@ -0,0 +1,7 @@
extends Resource
class_name ShaderStageResource
@export var shader_file : RDShaderFile
var shader : RID
var pipeline : RID

View File

@ -0,0 +1,93 @@
#[compute]
#version 450
#define FLT_MAX 3.402823466e+38
#define FLT_MIN 1.175494351e-38
#define DBL_MAX 1.7976931348623158e+308
#define DBL_MIN 2.2250738585072014e-308
layout(rgba16f, set = 0, binding = 0) uniform image2D past_color_image;
layout(rgba16f, set = 0, binding = 1) uniform image2D output_color_image;
layout(set = 0, binding = 2) uniform sampler2D color_sampler;
layout(set = 0, binding = 3) uniform sampler2D debug_sampler_1;
layout(set = 0, binding = 4) uniform sampler2D debug_sampler_2;
layout(set = 0, binding = 5) uniform sampler2D debug_sampler_3;
layout(set = 0, binding = 6) uniform sampler2D debug_sampler_4;
layout(set = 0, binding = 7) uniform sampler2D debug_sampler_5;
layout(set = 0, binding = 8) uniform sampler2D debug_sampler_6;
layout(set = 0, binding = 9) uniform sampler2D debug_sampler_7;
layout(set = 0, binding = 10) uniform sampler2D debug_sampler_8;
layout(push_constant, std430) uniform Params
{
float nan_fl_1;
float nan_fl_2;
float nan_fl_3;
float nan_fl_4;
int freeze;
int draw_debug;
int debug_page;
int nan3;
} params;
layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
void main()
{
ivec2 render_size = ivec2(textureSize(color_sampler, 0));
ivec2 uvi = ivec2(gl_GlobalInvocationID.xy);
if ((uvi.x >= render_size.x) || (uvi.y >= render_size.y))
{
return;
}
// show past image for freeze frame
if(params.freeze > 0)
{
imageStore(output_color_image, uvi, imageLoad(past_color_image, uvi));
return;
}
// must be on pixel center for whole values (tested)
vec2 uvn = vec2(uvi + vec2(0.5)) / render_size;
vec4 source = textureLod(color_sampler, uvn, 0.0);
if (params.draw_debug == 0)
{
imageStore(output_color_image, uvi, source);
imageStore(past_color_image, uvi, source);
return;
}
vec4 tl_col;
vec4 tr_col;
vec4 bl_col;
vec4 br_col;
if(params.debug_page == 0)
{
tl_col = textureLod(debug_sampler_1, uvn, 0.0);
tr_col = textureLod(debug_sampler_2, uvn, 0.0);
bl_col = textureLod(debug_sampler_3, uvn, 0.0);
br_col = textureLod(debug_sampler_4, uvn, 0.0);
}
if(params.debug_page == 1)
{
tl_col = textureLod(debug_sampler_5, uvn, 0.0);
tr_col = textureLod(debug_sampler_6, uvn, 0.0);
bl_col = textureLod(debug_sampler_7, uvn, 0.0);
br_col = textureLod(debug_sampler_8, uvn, 0.0);
}
imageStore(output_color_image, uvi / 2, tl_col);
imageStore(output_color_image, uvi / 2 + ivec2(vec2(0.5, 0.5) * render_size), br_col);
imageStore(output_color_image, uvi / 2 + ivec2(vec2(0.0, 0.5) * render_size), bl_col);
imageStore(output_color_image, uvi / 2 + ivec2(vec2(0.5, 0.0) * render_size), tr_col);
imageStore(past_color_image, uvi / 2, tl_col);
imageStore(past_color_image, uvi / 2 + ivec2(vec2(0.5, 0.5) * render_size), br_col);
imageStore(past_color_image, uvi / 2 + ivec2(vec2(0.0, 0.5) * render_size), bl_col);
imageStore(past_color_image, uvi / 2 + ivec2(vec2(0.5, 0.0) * render_size), tr_col);
}

View File

@ -0,0 +1,14 @@
[remap]
importer="glsl"
type="RDShaderFile"
uid="uid://dyxn6g5gvoge7"
path="res://.godot/imported/debug_overlay.glsl-5ad15477a64c7f484bc494103ad163b6.res"
[deps]
source_file="res://addons/SphynxMotionBlurToolkit/Debug/ShaderFiles/debug_overlay.glsl"
dest_files=["res://.godot/imported/debug_overlay.glsl-5ad15477a64c7f484bc494103ad163b6.res"]
[params]

View File

@ -0,0 +1,8 @@
[gd_resource type="Resource" script_class="ShaderStageResource" load_steps=3 format=3 uid="uid://o2bivm33b0v4"]
[ext_resource type="Script" path="res://addons/SphynxMotionBlurToolkit/BaseClasses/shader_pass_resource.gd" id="1_rqnmr"]
[ext_resource type="RDShaderFile" uid="uid://dyxn6g5gvoge7" path="res://addons/SphynxMotionBlurToolkit/Debug/ShaderFiles/debug_overlay.glsl" id="2_qgd1y"]
[resource]
script = ExtResource("1_rqnmr")
shader_file = ExtResource("2_qgd1y")

View File

@ -0,0 +1,107 @@
extends EnhancedCompositorEffect
class_name DebugCompositorEffect
@export var overlay_stage : ShaderStageResource = preload("res://addons/SphynxMotionBlurToolkit/Debug/debug_overlay_shader_stage.tres"):
set(value):
unsubscribe_shader_stage(overlay_stage)
overlay_stage = value
subscirbe_shader_stage(value)
## wether to display debug views for velocity and depth
## buffers
@export var draw_debug : bool = false
## currently 0 - 1, flip between velocity buffers
## and depth buffers debug views
@export var debug_page : int = 0
@export var debug_1 : String = "debug_1"
@export var debug_2 : String = "debug_2"
@export var debug_3 : String = "debug_3"
@export var debug_4 : String = "debug_4"
@export var debug_5 : String = "debug_5"
@export var debug_6 : String = "debug_6"
@export var debug_7 : String = "debug_7"
@export var debug_8 : String = "debug_8"
var past_color : StringName = "past_color"
var freeze : bool = false
func _init():
set_deferred("context", "MotionBlur")
super()
func _render_callback_2(render_size : Vector2i, render_scene_buffers : RenderSceneBuffersRD, render_scene_data : RenderSceneDataRD):
ensure_texture(past_color, render_scene_buffers)
ensure_texture(debug_1, render_scene_buffers)
ensure_texture(debug_2, render_scene_buffers)
ensure_texture(debug_3, render_scene_buffers)
ensure_texture(debug_4, render_scene_buffers)
ensure_texture(debug_5, render_scene_buffers)
ensure_texture(debug_6, render_scene_buffers)
ensure_texture(debug_7, render_scene_buffers)
ensure_texture(debug_8, render_scene_buffers)
rd.draw_command_begin_label("Debug", Color(1.0, 1.0, 1.0, 1.0))
if Input.is_action_just_pressed("freeze"):
freeze = !freeze
if Input.is_action_just_pressed("Z"):
draw_debug = !draw_debug
if Input.is_action_just_pressed("C"):
debug_page = 1 if debug_page == 0 else 0
var push_constant: PackedFloat32Array = [
0,
0,
0,
0,
]
var int_push_constant : PackedInt32Array = [
freeze,
draw_debug,
debug_page,
0
]
var byte_array = push_constant.to_byte_array()
byte_array.append_array(int_push_constant.to_byte_array())
var view_count = render_scene_buffers.get_view_count()
for view in range(view_count):
var color_image := render_scene_buffers.get_color_layer(view)
var past_color_image := render_scene_buffers.get_texture_slice(context, past_color, view, 0, 1, 1)
var debug_1_image := render_scene_buffers.get_texture_slice(context, debug_1, view, 0, 1, 1)
var debug_2_image := render_scene_buffers.get_texture_slice(context, debug_2, view, 0, 1, 1)
var debug_3_image := render_scene_buffers.get_texture_slice(context, debug_3, view, 0, 1, 1)
var debug_4_image := render_scene_buffers.get_texture_slice(context, debug_4, view, 0, 1, 1)
var debug_5_image := render_scene_buffers.get_texture_slice(context, debug_5, view, 0, 1, 1)
var debug_6_image := render_scene_buffers.get_texture_slice(context, debug_6, view, 0, 1, 1)
var debug_7_image := render_scene_buffers.get_texture_slice(context, debug_7, view, 0, 1, 1)
var debug_8_image := render_scene_buffers.get_texture_slice(context, debug_8, view, 0, 1, 1)
var x_groups := floori((render_size.x - 1) / 16 + 1)
var y_groups := floori((render_size.y - 1) / 16 + 1)
dispatch_stage(overlay_stage,
[
get_image_uniform(past_color_image, 0),
get_image_uniform(color_image, 1),
get_sampler_uniform(color_image, 2),
get_sampler_uniform(debug_1_image, 3),
get_sampler_uniform(debug_2_image, 4),
get_sampler_uniform(debug_3_image, 5),
get_sampler_uniform(debug_4_image, 6),
get_sampler_uniform(debug_5_image, 7),
get_sampler_uniform(debug_6_image, 8),
get_sampler_uniform(debug_7_image, 9),
get_sampler_uniform(debug_8_image, 10),
],
byte_array,
Vector3i(x_groups, y_groups, 1),
"Debug Overlay",
view)
rd.draw_command_end_label()

View File

@ -0,0 +1,156 @@
#[compute]
#version 450
#define FLT_MAX 3.402823466e+38
#define FLT_MIN 1.175494351e-38
layout(set = 0, binding = 0) uniform sampler2D color_sampler;
layout(set = 0, binding = 1) uniform sampler2D depth_sampler;
layout(set = 0, binding = 2) uniform sampler2D velocity_sampler;
layout(set = 0, binding = 3) uniform sampler2D neighbor_max;
layout(set = 0, binding = 4) uniform sampler2D tile_variance;
layout(rgba16f, set = 0, binding = 5) uniform writeonly image2D output_color;
layout(rgba16f, set = 0, binding = 6) uniform image2D debug_1_image;
layout(rgba16f, set = 0, binding = 7) uniform image2D debug_2_image;
layout(push_constant, std430) uniform Params
{
float minimum_user_threshold;
float importance_bias;
float maximum_jitter_value;
float nan8;
int tile_size;
int sample_count;
int frame;
int nan4;
} params;
layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
// McGuire's functions https://docs.google.com/document/d/1IIlAKTj-O01hcXEdGxTErQbCHO9iBmRx6oFUy_Jm0fI/edit
// ----------------------------------------------------------
float soft_depth_compare(float depth_X, float depth_Y, float sze)
{
return clamp(1 - (depth_X - depth_Y) / sze, 0, 1);
}
float cone(float T, float v)
{
return clamp(1 - abs(T) / v, 0, 1);
}
float cylinder(float T, float v)
{
return 1.0 - smoothstep(0.95 * v, 1.05 * v, abs(T));
}
// ----------------------------------------------------------
// Guertin's functions https://research.nvidia.com/sites/default/files/pubs/2013-11_A-Fast-and/Guertin2013MotionBlur-small.pdf
// ----------------------------------------------------------
float z_compare(float a, float b)
{
return clamp(1. - (a - b) / min(a, b), 0, 1);
}
// ----------------------------------------------------------
// from https://www.shadertoy.com/view/ftKfzc
// ----------------------------------------------------------
float interleaved_gradient_noise(vec2 uv, int FrameId){
uv += float(FrameId) * (vec2(47, 17) * 0.695);
vec3 magic = vec3( 0.06711056, 0.00583715, 52.9829189 );
return fract(magic.z * fract(dot(uv, magic.xy)));
}
// ----------------------------------------------------------
vec2 sample_random_offset(vec2 uv, float j)
{
return vec2(0);
}
void main()
{
ivec2 render_size = ivec2(textureSize(color_sampler, 0));
ivec2 tile_render_size = ivec2(textureSize(neighbor_max, 0));
ivec2 uvi = ivec2(gl_GlobalInvocationID.xy);
if ((uvi.x >= render_size.x) || (uvi.y >= render_size.y))
{
return;
}
vec2 x = (vec2(uvi) + vec2(0.5)) / vec2(render_size);
float j = interleaved_gradient_noise(uvi, params.frame) * 2. - 1.;
vec2 vn = textureLod(neighbor_max, x, 0.0).xy * render_size / 2;
float vn_length = max(0.5, length(vn));
vec4 base_color = textureLod(color_sampler, x, 0.0);
if(vn_length <= 0.5)
{
imageStore(output_color, uvi, base_color);
imageStore(debug_1_image, uvi, base_color);
imageStore(debug_2_image, uvi, vec4(vn / render_size * 2, 0, 1));
return;
}
vec2 wn = normalize(vn);
vec2 vx = textureLod(velocity_sampler, x, 0.0).xy * render_size / 2;
float vx_length = max(0.5, length(vx));
vec2 wp = vec2(-wn.y, wn.x);
if(dot(wp, vx) < 0)
{
wp = -wp;
}
vec2 wc = normalize(mix(wp, normalize(vx), (vx_length - 0.5) / params.minimum_user_threshold));
float zx = -0.05 / textureLod(depth_sampler, x, 0.0).x;
float weight = params.sample_count / (params.importance_bias * vx_length);
vec4 sum = base_color * weight;
for(int i = 0; i < params.sample_count; i++)
{
float t = mix(-1.0, 1.0, (i + j * params.maximum_jitter_value + 1.0) / (params.sample_count + 1.0));
vec2 d = ((i % 2) > 0) ? vx : vn;
float T = t * vn_length;
vec2 y = x + t * d / render_size;
vec2 vy = textureLod(velocity_sampler, y, 0.0).xy * render_size / 2;
float vy_length = max(0.5, length(vy));
float zy = -0.05 / textureLod(depth_sampler, y, 0.0).x;
float f = z_compare(zx, zy);
float b = z_compare(zy, zx);
float wa = dot(wc, d);
float wb = dot(normalize(vy), d);
float ay = f * cone(T, 1. / vy_length) * max(FLT_MIN, abs(wb))
+ b * cone(T, 1. / vx_length) * max(FLT_MIN, abs(wa))
+ cylinder(T, min(vx_length, vy_length)) * 2 * max(FLT_MIN, max(abs(wa), abs(wb)));
weight += abs(ay);
sum += ay * textureLod(color_sampler, y, 0.0);
}
sum /= weight;
imageStore(output_color, uvi, sum);
imageStore(debug_1_image, uvi, sum);
imageStore(debug_2_image, uvi, vec4(vn / render_size * 2, 0, 1));
}

View File

@ -0,0 +1,14 @@
[remap]
importer="glsl"
type="RDShaderFile"
uid="uid://cbdyfuhewqag8"
path="res://.godot/imported/guertin_blur.glsl-bc647b2d965e982b702f0e036903e801.res"
[deps]
source_file="res://addons/SphynxMotionBlurToolkit/Guertin/ShaderFiles/guertin_blur.glsl"
dest_files=["res://.godot/imported/guertin_blur.glsl-bc647b2d965e982b702f0e036903e801.res"]
[params]

View File

@ -0,0 +1,184 @@
#[compute]
#version 450
#define FLT_MAX 3.402823466e+38
#define FLT_MIN 1.175494351e-38
#define M_PI 3.1415926535897932384626433832795
layout(set = 0, binding = 0) uniform sampler2D color_sampler;
layout(set = 0, binding = 1) uniform sampler2D depth_sampler;
layout(set = 0, binding = 2) uniform sampler2D velocity_sampler;
layout(set = 0, binding = 3) uniform sampler2D neighbor_max;
layout(set = 0, binding = 4) uniform sampler2D tile_variance;
layout(rgba16f, set = 0, binding = 5) uniform writeonly image2D output_color;
layout(rgba16f, set = 0, binding = 6) uniform image2D past_color_image;
layout(rgba16f, set = 0, binding = 6) uniform image2D debug_1_image;
layout(rgba16f, set = 0, binding = 7) uniform image2D debug_2_image;
layout(rgba16f, set = 0, binding = 8) uniform image2D debug_3_image;
layout(rgba16f, set = 0, binding = 9) uniform image2D debug_4_image;
layout(push_constant, std430) uniform Params
{
float minimum_user_threshold;
float importance_bias;
float maximum_jitter_value;
float nan8;
int tile_size;
int sample_count;
int frame;
int nan4;
} params;
layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
// McGuire's functions https://docs.google.com/document/d/1IIlAKTj-O01hcXEdGxTErQbCHO9iBmRx6oFUy_Jm0fI/edit
// ----------------------------------------------------------
float soft_depth_compare(float depth_X, float depth_Y, float sze)
{
return clamp(1 - (depth_X - depth_Y) / sze, 0, 1);
}
float cone(float T, float v)
{
return clamp(1 - T / v, 0, 1);
}
float cylinder(float T, float v)
{
return 1.0 - smoothstep(0.95 * v, 1.05 * v, T);
}
// ----------------------------------------------------------
// Guertin's functions https://research.nvidia.com/sites/default/files/pubs/2013-11_A-Fast-and/Guertin2013MotionBlur-small.pdf
// ----------------------------------------------------------
float z_compare(float a, float b, float sze)
{
return clamp(1. - sze * (a - b) / min(a, b), 0, 1);
}
// ----------------------------------------------------------
// from https://www.shadertoy.com/view/ftKfzc
// ----------------------------------------------------------
float interleaved_gradient_noise(vec2 uv){
uv += float(params.frame) * (vec2(47, 17) * 0.695);
vec3 magic = vec3( 0.06711056, 0.00583715, 52.9829189 );
return fract(magic.z * fract(dot(uv, magic.xy)));
}
// ----------------------------------------------------------
// from https://github.com/bradparks/KinoMotion__unity_motion_blur/tree/master
// ----------------------------------------------------------
vec2 safenorm(vec2 v)
{
float l = max(length(v), 1e-6);
return v / l * int(1 >= 0.5);
}
vec2 jitter_tile(vec2 uvi)
{
float rx, ry;
float angle = interleaved_gradient_noise(uvi + vec2(2, 0)) * M_PI * 2;
rx = cos(angle);
ry = sin(angle);
return vec2(rx, ry) / textureSize(neighbor_max, 0) / 4;
}
// ----------------------------------------------------------
void main()
{
ivec2 render_size = ivec2(textureSize(color_sampler, 0));
ivec2 tile_render_size = ivec2(textureSize(neighbor_max, 0));
ivec2 uvi = ivec2(gl_GlobalInvocationID.xy);
if ((uvi.x >= render_size.x) || (uvi.y >= render_size.y))
{
return;
}
vec2 x = (vec2(uvi) + vec2(0.5)) / vec2(render_size);
float j = interleaved_gradient_noise(uvi) * 2. - 1.;
vec2 vn = textureLod(neighbor_max, x + jitter_tile(uvi), 0.0).xy * render_size / 2.;
float vn_length = length(vn);
vec4 base_color = textureLod(color_sampler, x, 0.0);
if(vn_length < 0.5)
{
imageStore(output_color, uvi, base_color);
imageStore(debug_1_image, uvi, base_color);
imageStore(debug_2_image, uvi, vec4(vn / render_size * 2, 0, 1));
imageStore(debug_3_image, uvi, vec4(0));
imageStore(debug_4_image, uvi, vec4(0));
return;
}
vec2 wn = safenorm(vn);
vec2 vx = textureLod(velocity_sampler, x, 0.0).xy * render_size / 2.;
float vx_length = max(0.5, length(vx));
vec2 wx = safenorm(vx);
vec2 wp = vec2(-wn.y, wn.x);
if(dot(wp, vx) < 0)
{
wp = -wp;
}
vec2 wc = safenorm(mix(wp, wx, clamp((vx_length - 0.5) / params.minimum_user_threshold, 0, 1)));
float zx = -0.05 / max(FLT_MIN, textureLod(depth_sampler, x, 0.0).x);
float total_weight = params.sample_count / (params.importance_bias * vx_length);
vec4 sum = base_color * total_weight;
for(int i = 0; i < params.sample_count; i++)
{
float t = mix(-1.0, 1.0, (i + j * params.maximum_jitter_value + 1.0) / (params.sample_count + 1.0));
vec2 d = ((i % 2) > 0) ? vx : vn;
vec2 wd = safenorm(d);
float T = abs(t * vn_length);
vec2 y = x + t * d / render_size;
float wa = dot(wc, wd);
vec2 vy = textureLod(velocity_sampler, y, 0.0).xy * render_size / 2;
float vy_length = max(0.5, length(vy));
float zy = -0.05 / max(FLT_MIN, textureLod(depth_sampler, y, 0.0).x);
float f = z_compare(zy, zx, 15);
float b = z_compare(zx, zy, 15);
float wb = abs(dot(vy / vy_length, wd));
float weight = 0.0;
weight += f * cone(T, vy_length) * wb;
weight += b * cone(T, vx_length) * wa;
weight += cylinder(T, min(vy_length, vx_length)) * 2. * max(wa, wb);
total_weight += weight;
sum += weight * textureLod(color_sampler, y, 0.0);
}
sum /= total_weight;
imageStore(output_color, uvi, sum);
imageStore(debug_1_image, uvi, sum);
imageStore(debug_2_image, uvi, vec4(vn / render_size * 2, 0, 1));
imageStore(debug_3_image, uvi, vec4(0));
imageStore(debug_4_image, uvi, vec4(0));
}

View File

@ -0,0 +1,14 @@
[remap]
importer="glsl"
type="RDShaderFile"
uid="uid://m6rlgfu6i0b3"
path="res://.godot/imported/guertin_kino_blur.glsl-71e9932045a7522115793d60f179d67e.res"
[deps]
source_file="res://addons/SphynxMotionBlurToolkit/Guertin/ShaderFiles/guertin_kino_blur.glsl"
dest_files=["res://.godot/imported/guertin_kino_blur.glsl-71e9932045a7522115793d60f179d67e.res"]
[params]

View File

@ -0,0 +1,72 @@
#[compute]
#version 450
#define FLT_MAX 3.402823466e+38
#define FLT_MIN 1.175494351e-38
layout(set = 0, binding = 0) uniform sampler2D tile_max;
layout(rgba16f, set = 0, binding = 1) uniform writeonly image2D neighbor_max;
layout(push_constant, std430) uniform Params
{
float nan5;
float nan6;
float nan7;
float nan8;
int nan1;
int nan2;
int nan3;
int nan4;
} params;
layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
void main()
{
ivec2 render_size = ivec2(textureSize(tile_max, 0));
ivec2 uvi = ivec2(gl_GlobalInvocationID.xy);
if ((uvi.x >= render_size.x) || (uvi.y >= render_size.y))
{
return;
}
vec2 uvn = (vec2(uvi) + vec2(0.5)) / render_size;
vec2 max_neighbor_velocity = vec2(0);
float max_neighbor_velocity_length = 0;
for(int i = -1; i < 2; i++)
{
for(int j = -1; j < 2; j++)
{
vec2 current_offset = vec2(1) / vec2(render_size) * vec2(i, j);
vec2 current_uv = uvn + current_offset;
if(current_uv.x < 0 || current_uv.x > 1 || current_uv.y < 0 || current_uv.y > 1)
{
continue;
}
bool is_diagonal = (abs(i) + abs(j) == 2);
vec2 current_neighbor_velocity = textureLod(tile_max, current_uv, 0.0).xy;
bool facing_center = dot(current_neighbor_velocity, current_offset) > 0;
if(is_diagonal && !facing_center)
{
continue;
}
float current_neighbor_velocity_length = dot(current_neighbor_velocity, current_neighbor_velocity);
if(current_neighbor_velocity_length > max_neighbor_velocity_length)
{
max_neighbor_velocity_length = current_neighbor_velocity_length;
max_neighbor_velocity = current_neighbor_velocity;
}
}
}
imageStore(neighbor_max, uvi, vec4(max_neighbor_velocity, 0, 1));
}

View File

@ -0,0 +1,14 @@
[remap]
importer="glsl"
type="RDShaderFile"
uid="uid://bn88jkvr17x4j"
path="res://.godot/imported/guertin_neighbor_max.glsl-91e836516679e0c51b67df5b480ef0af.res"
[deps]
source_file="res://addons/SphynxMotionBlurToolkit/Guertin/ShaderFiles/guertin_neighbor_max.glsl"
dest_files=["res://.godot/imported/guertin_neighbor_max.glsl-91e836516679e0c51b67df5b480ef0af.res"]
[params]

View File

@ -0,0 +1,18 @@
#[compute]
#version 450
layout(set = 0, binding = 0) uniform sampler2D blur_sampler;
layout(rgba16f, set = 0, binding = 1) uniform image2D color_image;
layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
void main()
{
ivec2 render_size = ivec2(textureSize(blur_sampler, 0));
ivec2 output_size = imageSize(color_image);
ivec2 uv = ivec2(gl_GlobalInvocationID.xy);
if ((uv.x >= output_size.x) || (uv.y >= output_size.y))
{
return;
}
imageStore(color_image, uv, textureLod(blur_sampler, (vec2(uv) + 0.5) / output_size, 0.0));
}

View File

@ -0,0 +1,14 @@
[remap]
importer="glsl"
type="RDShaderFile"
uid="uid://i6rnwhmss334"
path="res://.godot/imported/guertin_overlay.glsl-506c18362b63cb0a2477b4a4fbfea046.res"
[deps]
source_file="res://addons/SphynxMotionBlurToolkit/Guertin/ShaderFiles/guertin_overlay.glsl"
dest_files=["res://.godot/imported/guertin_overlay.glsl-506c18362b63cb0a2477b4a4fbfea046.res"]
[params]

View File

@ -0,0 +1,55 @@
#[compute]
#version 450
#define FLT_MAX 3.402823466e+38
#define FLT_MIN 1.175494351e-38
layout(set = 0, binding = 0) uniform sampler2D velocity_sampler;
layout(set = 0, binding = 1) uniform sampler2D depth_sampler;
layout(rgba16f, set = 0, binding = 2) uniform writeonly image2D tile_max_x;
layout(push_constant, std430) uniform Params
{
float nan5;
float nan6;
float nan7;
float nan8;
int tile_size;
int nan2;
int nan3;
int nan4;
} params;
layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
void main()
{
ivec2 render_size = ivec2(textureSize(velocity_sampler, 0));
ivec2 output_size = imageSize(tile_max_x);
ivec2 uvi = ivec2(gl_GlobalInvocationID.xy);
ivec2 global_uvi = uvi * ivec2(params.tile_size, 1);
if ((uvi.x >= output_size.x) || (uvi.y >= output_size.y) || (global_uvi.x >= render_size.x) || (global_uvi.y >= render_size.y))
{
return;
}
vec2 uvn = (vec2(global_uvi) + vec2(0.5)) / render_size;
vec4 max_velocity = vec4(0);
float max_velocity_length = -1;
for(int i = 0; i < params.tile_size; i++)
{
vec2 current_uv = uvn + vec2(float(i) / render_size.x, 0);
vec3 velocity_sample = textureLod(velocity_sampler, current_uv, 0.0).xyz;
float current_velocity_length = dot(velocity_sample.xy, velocity_sample.xy);
if(current_velocity_length > max_velocity_length)
{
max_velocity_length = current_velocity_length;
max_velocity = vec4(velocity_sample, textureLod(depth_sampler, current_uv, 0.0).x);
}
}
imageStore(tile_max_x, uvi, max_velocity);
}

View File

@ -0,0 +1,14 @@
[remap]
importer="glsl"
type="RDShaderFile"
uid="uid://d0s5upcgm7r6l"
path="res://.godot/imported/guertin_tile_max_x.glsl-7ca561425618287b0f2821fd8c232f09.res"
[deps]
source_file="res://addons/SphynxMotionBlurToolkit/Guertin/ShaderFiles/guertin_tile_max_x.glsl"
dest_files=["res://.godot/imported/guertin_tile_max_x.glsl-7ca561425618287b0f2821fd8c232f09.res"]
[params]

View File

@ -0,0 +1,54 @@
#[compute]
#version 450
#define FLT_MAX 3.402823466e+38
#define FLT_MIN 1.175494351e-38
layout(set = 0, binding = 0) uniform sampler2D tile_max_x;
layout(rgba16f, set = 0, binding = 1) uniform writeonly image2D tile_max;
layout(push_constant, std430) uniform Params
{
float nan5;
float nan6;
float nan7;
float nan8;
int tile_size;
int nan2;
int nan3;
int nan4;
} params;
layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
void main()
{
ivec2 render_size = ivec2(textureSize(tile_max_x, 0));
ivec2 output_size = imageSize(tile_max);
ivec2 uvi = ivec2(gl_GlobalInvocationID.xy);
ivec2 global_uvi = uvi * ivec2(1, params.tile_size);
if ((uvi.x >= output_size.x) || (uvi.y >= output_size.y) || (global_uvi.x >= render_size.x) || (global_uvi.y >= render_size.y))
{
return;
}
vec2 uvn = (vec2(global_uvi) + vec2(0.5)) / render_size;
vec4 max_velocity = vec4(0);
float max_velocity_length = -1;
for(int i = 0; i < params.tile_size; i++)
{
vec2 current_uv = uvn + vec2(0, float(i) / render_size.y);
vec4 velocity_sample = textureLod(tile_max_x, current_uv, 0.0);
float current_velocity_length = dot(velocity_sample.xy, velocity_sample.xy);
if(current_velocity_length > max_velocity_length)
{
max_velocity_length = current_velocity_length;
max_velocity = velocity_sample;
}
}
imageStore(tile_max, uvi, max_velocity);
}

View File

@ -0,0 +1,14 @@
[remap]
importer="glsl"
type="RDShaderFile"
uid="uid://ceetvitdbio4l"
path="res://.godot/imported/guertin_tile_max_y.glsl-60f045725ff6917c4bd911cf3710a444.res"
[deps]
source_file="res://addons/SphynxMotionBlurToolkit/Guertin/ShaderFiles/guertin_tile_max_y.glsl"
dest_files=["res://.godot/imported/guertin_tile_max_y.glsl-60f045725ff6917c4bd911cf3710a444.res"]
[params]

View File

@ -0,0 +1,68 @@
#[compute]
#version 450
#define FLT_MAX 3.402823466e+38
#define FLT_MIN 1.175494351e-38
layout(set = 0, binding = 0) uniform sampler2D tile_max;
layout(rgba16f, set = 0, binding = 1) uniform writeonly image2D tile_variance;
layout(push_constant, std430) uniform Params
{
float nan5;
float nan6;
float nan7;
float nan8;
int nan1;
int nan2;
int nan3;
int nan4;
} params;
layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
void main()
{
ivec2 render_size = ivec2(textureSize(tile_max, 0));
ivec2 uvi = ivec2(gl_GlobalInvocationID.xy);
if ((uvi.x >= render_size.x) || (uvi.y >= render_size.y))
{
return;
}
vec2 uvn = (vec2(uvi) + vec2(0.5)) / render_size;
float variance = 0;
vec2 current_velocity = abs(normalize(textureLod(tile_max, uvn, 0.0).xy));
float tile_count = 0;
for(int i = -1; i < 2; i++)
{
for(int j = -1; j < 2; j++)
{
vec2 current_offset = vec2(1) / vec2(render_size) * vec2(i, j);
vec2 current_uv = uvn + current_offset;
if(current_uv.x < 0 || current_uv.x > 1 || current_uv.y < 0 || current_uv.y > 1)
{
continue;
}
if(i == j && i == 0)
{
continue;
}
tile_count += 1;
vec2 current_neighbor_velocity = abs(normalize(textureLod(tile_max, current_uv, 0.0).xy));
variance += dot(current_velocity, current_neighbor_velocity);
}
}
variance /= tile_count;
imageStore(tile_variance, uvi, vec4(1 - variance));
}

View File

@ -0,0 +1,14 @@
[remap]
importer="glsl"
type="RDShaderFile"
uid="uid://by6mslkv0palh"
path="res://.godot/imported/guertin_tile_variance.glsl-2fb44423dc25efae19822b8cfbe32a55.res"
[deps]
source_file="res://addons/SphynxMotionBlurToolkit/Guertin/ShaderFiles/guertin_tile_variance.glsl"
dest_files=["res://.godot/imported/guertin_tile_variance.glsl-2fb44423dc25efae19822b8cfbe32a55.res"]
[params]

View File

@ -0,0 +1,8 @@
[gd_resource type="Resource" script_class="ShaderStageResource" load_steps=3 format=3 uid="uid://dre56ajymywpr"]
[ext_resource type="Script" path="res://addons/SphynxMotionBlurToolkit/BaseClasses/shader_pass_resource.gd" id="1_loemu"]
[ext_resource type="RDShaderFile" uid="uid://m6rlgfu6i0b3" path="res://addons/SphynxMotionBlurToolkit/Guertin/ShaderFiles/guertin_kino_blur.glsl" id="2_uo41r"]
[resource]
script = ExtResource("1_loemu")
shader_file = ExtResource("2_uo41r")

View File

@ -0,0 +1,262 @@
extends MotionBlurCompositorEffect
class_name GuertinMotionBlur
@export_group("Motion Blur", "motion_blur_")
# diminishing returns over 16
@export_range(4, 64) var motion_blur_samples: int = 25
# you really don't want this over 0.5, but you can if you want to try
@export_range(0, 0.5, 0.001, "or_greater") var motion_blur_intensity: float = 1
@export_range(0, 1) var motion_blur_center_fade: float = 0.0
@export var blur_stage : ShaderStageResource = preload("res://addons/SphynxMotionBlurToolkit/Guertin/guertin_blur_stage.tres"):
set(value):
unsubscribe_shader_stage(blur_stage)
blur_stage = value
subscirbe_shader_stage(value)
@export var overlay_stage : ShaderStageResource = preload("res://addons/SphynxMotionBlurToolkit/Guertin/guertin_overlay_stage.tres"):
set(value):
unsubscribe_shader_stage(overlay_stage)
overlay_stage = value
subscirbe_shader_stage(value)
@export var tile_max_x_stage : ShaderStageResource = preload("res://addons/SphynxMotionBlurToolkit/Guertin/guertin_tile_max_x_stage.tres"):
set(value):
unsubscribe_shader_stage(tile_max_x_stage)
tile_max_x_stage = value
subscirbe_shader_stage(value)
@export var tile_max_y_stage : ShaderStageResource = preload("res://addons/SphynxMotionBlurToolkit/Guertin/guertin_tile_max_y_stage.tres"):
set(value):
unsubscribe_shader_stage(tile_max_y_stage)
tile_max_y_stage = value
subscirbe_shader_stage(value)
@export var neighbor_max_stage : ShaderStageResource = preload("res://addons/SphynxMotionBlurToolkit/Guertin/guertin_neighbor_max_stage.tres"):
set(value):
unsubscribe_shader_stage(neighbor_max_stage)
neighbor_max_stage = value
subscirbe_shader_stage(value)
@export var tile_variance_stage : ShaderStageResource = preload("res://addons/SphynxMotionBlurToolkit/Guertin/guertin_tile_variance_stage.tres"):
set(value):
unsubscribe_shader_stage(tile_variance_stage)
tile_variance_stage = value
subscirbe_shader_stage(value)
@export var tile_size : int = 40
@export var linear_falloff_slope : float = 1
@export var importance_bias : float = 40
@export var maximum_jitter_value : float = 0.95
@export var minimum_user_threshold : float = 1.5
var output_color: StringName = "output_color"
var tile_max_x : StringName = "tile_max_x"
var tile_max : StringName = "tile_max"
var neighbor_max : StringName = "neighbor_max"
var tile_variance : StringName = "tile_variance"
var custom_velocity : StringName = "custom_velocity"
var debug_1 : StringName = "debug_1"
var debug_2 : StringName = "debug_2"
var debug_3 : StringName = "debug_3"
var debug_4 : StringName = "debug_4"
var freeze : bool = false
func _get_max_dilation_range() -> float:
return tile_size;
func _render_callback_2(render_size : Vector2i, render_scene_buffers : RenderSceneBuffersRD, render_scene_data : RenderSceneDataRD):
ensure_texture(tile_max_x, render_scene_buffers, RenderingDevice.DATA_FORMAT_R16G16B16A16_SFLOAT, Vector2(1. / tile_size, 1.))
ensure_texture(tile_max, render_scene_buffers, RenderingDevice.DATA_FORMAT_R16G16B16A16_SFLOAT, Vector2(1. / tile_size, 1. / tile_size))
ensure_texture(neighbor_max, render_scene_buffers, RenderingDevice.DATA_FORMAT_R16G16B16A16_SFLOAT, Vector2(1. / tile_size, 1. / tile_size))
ensure_texture(tile_variance, render_scene_buffers, RenderingDevice.DATA_FORMAT_R16G16B16A16_SFLOAT, Vector2(1. / tile_size, 1. / tile_size))
ensure_texture(custom_velocity, render_scene_buffers)
ensure_texture(output_color, render_scene_buffers)
ensure_texture(debug_1, render_scene_buffers)
ensure_texture(debug_2, render_scene_buffers)
ensure_texture(debug_3, render_scene_buffers)
ensure_texture(debug_4, render_scene_buffers)
rd.draw_command_begin_label("Motion Blur", Color(1.0, 1.0, 1.0, 1.0))
var tile_max_x_push_constants: PackedFloat32Array = [
0,
0,
0,
0
]
var int_tile_max_x_push_constants : PackedInt32Array = [
tile_size,
0,
0,
0
]
var tile_max_x_push_constants_byte_array = tile_max_x_push_constants.to_byte_array()
tile_max_x_push_constants_byte_array.append_array(int_tile_max_x_push_constants.to_byte_array())
var tile_max_y_push_constants: PackedFloat32Array = [
0,
0,
0,
0
]
var int_tile_max_y_push_constants : PackedInt32Array = [
tile_size,
0,
0,
0
]
var tile_max_y_push_constants_byte_array = tile_max_y_push_constants.to_byte_array()
tile_max_y_push_constants_byte_array.append_array(int_tile_max_y_push_constants.to_byte_array())
var neighbor_max_push_constants: PackedFloat32Array = [
0,
0,
0,
0
]
var int_neighbor_max_push_constants : PackedInt32Array = [
0,
0,
0,
0
]
var neighbor_max_push_constants_byte_array = neighbor_max_push_constants.to_byte_array()
neighbor_max_push_constants_byte_array.append_array(int_neighbor_max_push_constants.to_byte_array())
var tile_variance_push_constants: PackedFloat32Array = [
0,
0,
0,
0
]
var int_tile_variance_push_constants : PackedInt32Array = [
0,
0,
0,
0
]
var tile_variance_push_constants_byte_array = tile_variance_push_constants.to_byte_array()
tile_variance_push_constants_byte_array.append_array(int_tile_variance_push_constants.to_byte_array())
var blur_push_constants: PackedFloat32Array = [
minimum_user_threshold,
importance_bias,
maximum_jitter_value,
0,
]
var int_blur_push_constants : PackedInt32Array = [
tile_size,
motion_blur_samples,
Engine.get_frames_drawn() % 8,
0
]
var blur_push_constants_byte_array = blur_push_constants.to_byte_array()
blur_push_constants_byte_array.append_array(int_blur_push_constants.to_byte_array())
var view_count = render_scene_buffers.get_view_count()
for view in range(view_count):
var color_image := render_scene_buffers.get_color_layer(view)
var depth_image := render_scene_buffers.get_depth_layer(view)
var output_color_image := render_scene_buffers.get_texture_slice(context, output_color, view, 0, 1, 1)
var tile_max_x_image := render_scene_buffers.get_texture_slice(context, tile_max_x, view, 0, 1, 1)
var tile_max_image := render_scene_buffers.get_texture_slice(context, tile_max, view, 0, 1, 1)
var neighbor_max_image := render_scene_buffers.get_texture_slice(context, neighbor_max, view, 0, 1, 1)
var tile_variance_image := render_scene_buffers.get_texture_slice(context, tile_variance, view, 0, 1, 1)
var custom_velocity_image := render_scene_buffers.get_texture_slice(context, custom_velocity, view, 0, 1, 1)
var debug_1_image := render_scene_buffers.get_texture_slice(context, debug_1, view, 0, 1, 1)
var debug_2_image := render_scene_buffers.get_texture_slice(context, debug_2, view, 0, 1, 1)
var debug_3_image := render_scene_buffers.get_texture_slice(context, debug_3, view, 0, 1, 1)
var debug_4_image := render_scene_buffers.get_texture_slice(context, debug_4, view, 0, 1, 1)
var x_groups := floori((render_size.x / tile_size - 1) / 16 + 1)
var y_groups := floori((render_size.y - 1) / 16 + 1)
dispatch_stage(tile_max_x_stage,
[
get_sampler_uniform(custom_velocity_image, 0, false),
get_sampler_uniform(depth_image, 1, false),
get_image_uniform(tile_max_x_image, 2)
],
tile_max_x_push_constants_byte_array,
Vector3i(x_groups, y_groups, 1),
"TileMaxX",
view)
x_groups = floori((render_size.x / tile_size - 1) / 16 + 1)
y_groups = floori((render_size.y / tile_size - 1) / 16 + 1)
dispatch_stage(tile_max_y_stage,
[
get_sampler_uniform(tile_max_x_image, 0, false),
get_image_uniform(tile_max_image, 1)
],
tile_max_y_push_constants_byte_array,
Vector3i(x_groups, y_groups, 1),
"TileMaxY",
view)
dispatch_stage(neighbor_max_stage,
[
get_sampler_uniform(tile_max_image, 0, false),
get_image_uniform(neighbor_max_image, 1)
],
neighbor_max_push_constants_byte_array,
Vector3i(x_groups, y_groups, 1),
"NeighborMax",
view)
dispatch_stage(tile_variance_stage,
[
get_sampler_uniform(tile_max_image, 0, false),
get_image_uniform(tile_variance_image, 1)
],
tile_variance_push_constants_byte_array,
Vector3i(x_groups, y_groups, 1),
"TileVariance",
view)
x_groups = floori((render_size.x - 1) / 16 + 1)
y_groups = floori((render_size.y - 1) / 16 + 1)
dispatch_stage(blur_stage,
[
get_sampler_uniform(color_image, 0, false),
get_sampler_uniform(depth_image, 1, false),
get_sampler_uniform(custom_velocity_image, 2, false),
get_sampler_uniform(neighbor_max_image, 3, false),
get_sampler_uniform(tile_variance_image, 4, true),
get_image_uniform(output_color_image, 5),
get_image_uniform(debug_1_image, 6),
get_image_uniform(debug_2_image, 7),
get_image_uniform(debug_3_image, 8),
get_image_uniform(debug_4_image, 9)
],
blur_push_constants_byte_array,
Vector3i(x_groups, y_groups, 1),
"Blur",
view)
dispatch_stage(overlay_stage,
[
get_sampler_uniform(output_color_image, 0, false),
get_image_uniform(color_image, 1)
],
[],
Vector3i(x_groups, y_groups, 1),
"Overlay result",
view)
rd.draw_command_end_label()

View File

@ -0,0 +1,8 @@
[gd_resource type="Resource" script_class="ShaderStageResource" load_steps=3 format=3 uid="uid://cvb65hfs2lrxo"]
[ext_resource type="Script" path="res://addons/SphynxMotionBlurToolkit/BaseClasses/shader_pass_resource.gd" id="1_i1bu0"]
[ext_resource type="RDShaderFile" uid="uid://bn88jkvr17x4j" path="res://addons/SphynxMotionBlurToolkit/Guertin/ShaderFiles/guertin_neighbor_max.glsl" id="2_jp4do"]
[resource]
script = ExtResource("1_i1bu0")
shader_file = ExtResource("2_jp4do")

View File

@ -0,0 +1,8 @@
[gd_resource type="Resource" script_class="ShaderStageResource" load_steps=3 format=3 uid="uid://bidsfymvdyhek"]
[ext_resource type="Script" path="res://addons/SphynxMotionBlurToolkit/BaseClasses/shader_pass_resource.gd" id="1_2uett"]
[ext_resource type="RDShaderFile" uid="uid://i6rnwhmss334" path="res://addons/SphynxMotionBlurToolkit/Guertin/ShaderFiles/guertin_overlay.glsl" id="2_evkw4"]
[resource]
script = ExtResource("1_2uett")
shader_file = ExtResource("2_evkw4")

View File

@ -0,0 +1,8 @@
[gd_resource type="Resource" script_class="ShaderStageResource" load_steps=3 format=3 uid="uid://dipvwksvqb3dm"]
[ext_resource type="Script" path="res://addons/SphynxMotionBlurToolkit/BaseClasses/shader_pass_resource.gd" id="1_bxcqf"]
[ext_resource type="RDShaderFile" uid="uid://d0s5upcgm7r6l" path="res://addons/SphynxMotionBlurToolkit/Guertin/ShaderFiles/guertin_tile_max_x.glsl" id="2_q6kae"]
[resource]
script = ExtResource("1_bxcqf")
shader_file = ExtResource("2_q6kae")

View File

@ -0,0 +1,8 @@
[gd_resource type="Resource" script_class="ShaderStageResource" load_steps=3 format=3 uid="uid://bxfg45ubc2pv7"]
[ext_resource type="Script" path="res://addons/SphynxMotionBlurToolkit/BaseClasses/shader_pass_resource.gd" id="1_gy5dj"]
[ext_resource type="RDShaderFile" uid="uid://ceetvitdbio4l" path="res://addons/SphynxMotionBlurToolkit/Guertin/ShaderFiles/guertin_tile_max_y.glsl" id="2_grpec"]
[resource]
script = ExtResource("1_gy5dj")
shader_file = ExtResource("2_grpec")

View File

@ -0,0 +1,8 @@
[gd_resource type="Resource" script_class="ShaderStageResource" load_steps=3 format=3 uid="uid://bqehecsdgt70s"]
[ext_resource type="Script" path="res://addons/SphynxMotionBlurToolkit/BaseClasses/shader_pass_resource.gd" id="1_kkpwt"]
[ext_resource type="RDShaderFile" uid="uid://by6mslkv0palh" path="res://addons/SphynxMotionBlurToolkit/Guertin/ShaderFiles/guertin_tile_variance.glsl" id="2_r5u5d"]
[resource]
script = ExtResource("1_kkpwt")
shader_file = ExtResource("2_r5u5d")

View File

@ -0,0 +1,56 @@
#[compute]
#version 450
#define FLT_MAX 3.402823466e+38
#define FLT_MIN 1.175494351e-38
layout(set = 0, binding = 0) uniform sampler2D velocity_sampler;
layout(set = 0, binding = 1) uniform sampler2D depth_sampler;
layout(rgba16f, set = 0, binding = 2) uniform writeonly image2D tile_max_x;
layout(push_constant, std430) uniform Params
{
float nan5;
float nan6;
float nan7;
float nan8;
int tile_size;
int nan2;
int nan3;
int nan4;
} params;
layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
void main()
{
ivec2 render_size = ivec2(textureSize(velocity_sampler, 0));
ivec2 output_size = imageSize(tile_max_x);
ivec2 uvi = ivec2(gl_GlobalInvocationID.xy);
int tile_size = render_size.x / output_size.x;
ivec2 global_uvi = uvi * ivec2(tile_size, 1);
if ((uvi.x >= output_size.x) || (uvi.y >= output_size.y) || (global_uvi.x >= render_size.x) || (global_uvi.y >= render_size.y))
{
return;
}
vec2 uvn = (vec2(global_uvi) + vec2(0.5)) / render_size;
vec4 max_velocity = vec4(0);
float max_velocity_length = -1;
for(int i = 0; i < tile_size; i++)
{
vec2 current_uv = uvn + vec2(float(i) / render_size.x, 0);
vec3 velocity_sample = textureLod(velocity_sampler, current_uv, 0.0).xyz;
float current_velocity_length = dot(velocity_sample.xy, velocity_sample.xy);
if(current_velocity_length > max_velocity_length)
{
max_velocity_length = current_velocity_length;
max_velocity = vec4(velocity_sample, textureLod(depth_sampler, current_uv, 0.0).x);
}
}
imageStore(tile_max_x, uvi, max_velocity);
}

View File

@ -0,0 +1,14 @@
[remap]
importer="glsl"
type="RDShaderFile"
uid="uid://djp3da364fk2l"
path="res://.godot/imported/jf_guertin_tile_max_x.glsl-acb187dfb7304d498ecdfb75a54c725d.res"
[deps]
source_file="res://addons/SphynxMotionBlurToolkit/JumpFlood/ShaderFiles/jf_guertin_tile_max_x.glsl"
dest_files=["res://.godot/imported/jf_guertin_tile_max_x.glsl-acb187dfb7304d498ecdfb75a54c725d.res"]
[params]

View File

@ -0,0 +1,55 @@
#[compute]
#version 450
#define FLT_MAX 3.402823466e+38
#define FLT_MIN 1.175494351e-38
layout(set = 0, binding = 0) uniform sampler2D tile_max_x;
layout(rgba16f, set = 0, binding = 1) uniform writeonly image2D tile_max;
layout(push_constant, std430) uniform Params
{
float nan5;
float nan6;
float nan7;
float nan8;
int tile_size;
int nan2;
int nan3;
int nan4;
} params;
layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
void main()
{
ivec2 render_size = ivec2(textureSize(tile_max_x, 0));
ivec2 output_size = imageSize(tile_max);
ivec2 uvi = ivec2(gl_GlobalInvocationID.xy);
int tile_size = render_size.y / output_size.y;
ivec2 global_uvi = uvi * ivec2(1, tile_size);
if ((uvi.x >= output_size.x) || (uvi.y >= output_size.y) || (global_uvi.x >= render_size.x) || (global_uvi.y >= render_size.y))
{
return;
}
vec2 uvn = (vec2(global_uvi) + vec2(0.5)) / render_size;
vec4 max_velocity = vec4(0);
float max_velocity_length = -1;
for(int i = 0; i < tile_size; i++)
{
vec2 current_uv = uvn + vec2(0, float(i) / render_size.y);
vec4 velocity_sample = textureLod(tile_max_x, current_uv, 0.0);
float current_velocity_length = dot(velocity_sample.xy, velocity_sample.xy);
if(current_velocity_length > max_velocity_length)
{
max_velocity_length = current_velocity_length;
max_velocity = velocity_sample;
}
}
imageStore(tile_max, uvi, max_velocity);
}

View File

@ -0,0 +1,14 @@
[remap]
importer="glsl"
type="RDShaderFile"
uid="uid://cqlltc8f21wre"
path="res://.godot/imported/jf_guertin_tile_max_y.glsl-8b893536de27f9161f4a8be7b8c5058f.res"
[deps]
source_file="res://addons/SphynxMotionBlurToolkit/JumpFlood/ShaderFiles/jf_guertin_tile_max_y.glsl"
dest_files=["res://.godot/imported/jf_guertin_tile_max_y.glsl-8b893536de27f9161f4a8be7b8c5058f.res"]
[params]

View File

@ -0,0 +1,68 @@
#[compute]
#version 450
#define FLT_MAX 3.402823466e+38
#define FLT_MIN 1.175494351e-38
layout(set = 0, binding = 0) uniform sampler2D tile_max;
layout(set = 0, binding = 1) uniform sampler2D tile_max_map;
layout(rgba16f, set = 0, binding = 2) uniform writeonly image2D neighbor_max;
layout(push_constant, std430) uniform Params
{
float nan5;
float nan6;
float nan7;
float nan8;
int nan1;
int nan2;
int nan3;
int nan4;
} params;
layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
void main()
{
ivec2 render_size = ivec2(textureSize(tile_max, 0));
ivec2 uvi = ivec2(gl_GlobalInvocationID.xy);
if ((uvi.x >= render_size.x) || (uvi.y >= render_size.y))
{
return;
}
vec2 uvn = (vec2(uvi) + vec2(0.5)) / render_size;
vec2 max_neighbor_velocity = vec2(0);
float max_neighbor_velocity_length = -1;
for(int i = -1; i < 2; i++)
{
for(int j = -1; j < 2; j++)
{
vec2 current_offset = vec2(1) / vec2(render_size) * vec2(i, j);
vec2 current_uv = uvn + current_offset;
if(current_uv.x < 0 || current_uv.x > 1 || current_uv.y < 0 || current_uv.y > 1)
{
continue;
}
bool is_diagonal = (abs(i) + abs(j) == 2);
vec2 current_neighbor_sample = textureLod(tile_max_map, current_uv, 0.0).xy;
vec2 current_neighbor_velocity = textureLod(tile_max, current_neighbor_sample, 0.0).xy;
float current_neighbor_velocity_length = dot(current_neighbor_velocity, current_neighbor_velocity);
if(current_neighbor_velocity_length > max_neighbor_velocity_length)
{
max_neighbor_velocity_length = current_neighbor_velocity_length;
max_neighbor_velocity = current_neighbor_sample;
}
}
}
imageStore(neighbor_max, uvi, vec4(max_neighbor_velocity, 0, 1));
}

View File

@ -0,0 +1,14 @@
[remap]
importer="glsl"
type="RDShaderFile"
uid="uid://cfk5chwlcyay4"
path="res://.godot/imported/jf_neighbor_max.glsl-d9e677fd383d0688a8ad642473870160.res"
[deps]
source_file="res://addons/SphynxMotionBlurToolkit/JumpFlood/ShaderFiles/jf_neighbor_max.glsl"
dest_files=["res://.godot/imported/jf_neighbor_max.glsl-d9e677fd383d0688a8ad642473870160.res"]
[params]

View File

@ -6,8 +6,8 @@
layout(set = 0, binding = 0) uniform sampler2D depth_sampler;
layout(set = 0, binding = 1) uniform sampler2D velocity_sampler;
layout(rg16f, set = 0, binding = 2) uniform writeonly image2D buffer_a;
layout(rg16f, set = 0, binding = 3) uniform writeonly image2D buffer_b;
layout(rgba16f, set = 0, binding = 2) uniform writeonly image2D buffer_a;
layout(rgba16f, set = 0, binding = 3) uniform writeonly image2D buffer_b;
layout(set = 0, binding = 4) uniform sampler2D buffer_a_sampler;
layout(set = 0, binding = 5) uniform sampler2D buffer_b_sampler;
@ -46,59 +46,50 @@ const vec2 check_step_kernel[kernel_size] = {
vec2(-1, -1),
};
vec4 get_value(bool a, vec2 uv, ivec2 render_size)
void get_value(bool a,inout vec2 uv)
{
if (any(notEqual(uv, clamp(uv, vec2(0.0), vec2(1.0)))))
{
return vec4(-1, -1, 0, 1);
}
if(a)
{
return textureLod(buffer_a_sampler, uv, 0.0);
uv = textureLod(buffer_a_sampler, uv, 0.0).xy;
}
else
{
uv = textureLod(buffer_b_sampler, uv, 0.0).xy;
}
return textureLod(buffer_b_sampler, uv, 0.0);
}
void set_value(bool a, ivec2 uvi, vec4 value, ivec2 render_size)
void set_value(bool a, ivec2 uvi, vec4 value)
{
if (any(notEqual(uvi, clamp(uvi, ivec2(0), render_size))))
{
return;
}
if(a)
{
imageStore(buffer_a, uvi, value);
return;
}
imageStore(buffer_b, uvi, value);
else
{
imageStore(buffer_b, uvi, value);
}
}
// Motion similarity
// ----------------------------------------------------------
float get_motion_difference(vec2 V, vec2 V2, float parallel_sensitivity, float perpendicular_sensitivity)
float get_motion_difference(vec2 V, vec2 V2)
{
vec2 VO = V - V2;
// parallel offset
float parallel = abs(dot(VO, V) / max(FLT_MIN, dot(V, V)));
// perpendicular offset
float perpendicular = abs(dot(VO, vec2(V.y, -V.x)) / max(FLT_MIN, dot(V, V)));
// weighted difference
float difference = parallel * parallel_sensitivity + perpendicular * perpendicular_sensitivity;
return clamp(difference, 0, 1);
return clamp(dot(V - V2, V) / dot(V, V), 0, 1);
// vec2 VO = V - V2;
// float parallel = dot(VO, V) / dot(V, V);
// return clamp(parallel, 0, 1);
}
// ----------------------------------------------------------
vec4 sample_fitness(vec2 uv_offset, vec4 uv_sample, vec2 render_size)
void sample_fitness(vec2 uv_offset, vec4 uv_sample, vec2 render_size, inout vec4 curren_sample_fitness)
{
vec2 sample_velocity = -uv_sample.xy;
// if velocity is 0, we never reach it (steps never smaller than 1)
if (dot(sample_velocity, sample_velocity) <= FLT_MIN || uv_sample.w == 0)
{
return vec4(FLT_MAX, FLT_MAX, FLT_MAX, 0);
curren_sample_fitness = vec4(FLT_MAX, FLT_MAX, FLT_MAX, 0);
return;
}
// velocity space distance (projected pixel offset onto velocity vector)
@ -114,7 +105,7 @@ vec4 sample_fitness(vec2 uv_offset, vec4 uv_sample, vec2 render_size)
// arbitrary perpendicular limit (lower means tighter dilation, but less reliable)
float within_perpen_error_range = step(side_offset, params.perpen_error_thresh * params.motion_blur_intensity);
// store relevant data for use in conditions
return vec4(absolute_velocity_space_distance, velocity_space_distance, uv_sample.w + uv_sample.z * velocity_space_distance, within_velocity_range * within_perpen_error_range);
curren_sample_fitness = vec4(absolute_velocity_space_distance, velocity_space_distance, uv_sample.w + uv_sample.z * velocity_space_distance, within_velocity_range * within_perpen_error_range);
}
float is_sample_better(vec4 a, vec4 b)
@ -139,52 +130,64 @@ vec4 get_backtracked_sample(vec2 uvn, vec2 chosen_uv, vec3 chosen_velocity, vec4
float best_depth = best_sample_fitness.z;
// set temp variable to keet track of better matches
float smallest_velocity_difference = params.velocity_match_threshold;
float smallest_velocity_difference = 0.99;//params.velocity_match_threshold;
// minimum amount of valid velocities to compare before decision
int initial_steps_to_compare = 2;
int steps_to_compare = initial_steps_to_compare;
float velocity_multiplier;
vec2 check_uv;
vec3 velocity_test;
float depth_test;
float velocity_difference;
float current_depth;
for(int i = -params.backtracking_sample_count; i < params.backtracking_sample_count + 1; i++)
{
float velocity_multiplier = general_velocity_multiplier * (1 + float(i) / float(params.backtracking_sample_count));
velocity_multiplier = general_velocity_multiplier * (1 + float(i) / float(params.backtracking_sample_count));
if(velocity_multiplier > params.motion_blur_intensity || velocity_multiplier < 0)
{
continue;
}
vec2 check_uv = uvn - chosen_velocity.xy * velocity_multiplier;
check_uv = uvn - chosen_velocity.xy * velocity_multiplier;
if(any(notEqual(check_uv, clamp(check_uv, vec2(0.0), vec2(1.0)))))
{
continue;
}
// get potential velocity and depth matches
vec3 velocity_test = textureLod(velocity_sampler, check_uv, 0.0).xyz;
velocity_test = textureLod(velocity_sampler, check_uv, 0.0).xyz;
float depth_test = textureLod(depth_sampler, check_uv, 0.0).x;
depth_test = textureLod(depth_sampler, check_uv, 0.0).x;
float velocity_difference = get_motion_difference(chosen_velocity.xy, velocity_test.xy, params.parallel_sensitivity, params.perpendicular_sensitivity);
velocity_difference = get_motion_difference(chosen_velocity.xy, velocity_test.xy);
float current_depth = depth_test + chosen_velocity.z * velocity_multiplier;
current_depth = depth_test + chosen_velocity.z * velocity_multiplier;
// if checked sample matches depth and velocity, it is valid for backtracking
if((abs(current_depth - best_sample_fitness.z) < params.depth_match_threshold) && (velocity_difference <= smallest_velocity_difference))
if((abs(current_depth - best_sample_fitness.z) < 0.002) && (velocity_difference <= smallest_velocity_difference))
{
best_uv = check_uv;
best_multiplier = velocity_multiplier;
best_depth = current_depth;
if(steps_to_compare == 0)
{
return vec4(best_uv, best_depth, best_multiplier);
return vec4(best_uv, best_depth, 0);
}
steps_to_compare--;
}
// if a sample was found and we lost footing after, go with that found sample right away
else if(initial_steps_to_compare > steps_to_compare)
{
return vec4(best_uv, best_depth, best_multiplier);
return vec4(best_uv, best_depth, 0);
}
}
@ -205,38 +208,44 @@ void main()
vec2 uv_step = vec2(round(params.step_size)) / render_size;
vec4 best_sample_fitness = vec4(FLT_MAX, FLT_MAX, FLT_MAX, 0);
vec4 best_sample_fitness = vec4(FLT_MAX, FLT_MAX, FLT_MAX, 0.);
vec2 chosen_uv = uvn;
vec3 chosen_velocity = vec3(0);
vec3 chosen_velocity = vec3(0.);
bool set_a = !bool(step(0.5, float(params.iteration_index % 2)));
vec2 step_offset;
vec2 check_uv;
vec4 uv_sample;
vec4 current_sample_fitness;
for(int i = 0; i < kernel_size; i++)
{
vec2 step_offset = check_step_kernel[i] * uv_step;
vec2 check_uv = uvn + step_offset;
step_offset = check_step_kernel[i] * uv_step;
check_uv = uvn + step_offset;
if(any(notEqual(check_uv, clamp(check_uv, vec2(0.0), vec2(1.0)))))
{
continue;
}
if(params.iteration_index > 0)
if(params.iteration_index > 0.)
{
vec4 buffer_load = get_value(!set_a, check_uv, render_size);
check_uv = buffer_load.xy;
get_value(!set_a, check_uv);
step_offset = check_uv - uvn;
}
vec4 uv_sample = vec4(textureLod(velocity_sampler, check_uv, 0.0).xyz, textureLod(depth_sampler, check_uv, 0.0).x);
uv_sample = vec4(textureLod(velocity_sampler, check_uv, 0.0).xyz, textureLod(depth_sampler, check_uv, 0.0).x);
vec4 current_sample_fitness = sample_fitness(step_offset, uv_sample, render_size);
sample_fitness(step_offset, uv_sample, render_size, current_sample_fitness);
if (is_sample_better(current_sample_fitness, best_sample_fitness) > 0.5)
if (mix(1. - step(best_sample_fitness.x * current_sample_fitness.w, current_sample_fitness.x * best_sample_fitness.w), step(best_sample_fitness.z, current_sample_fitness.z), step(0.5, best_sample_fitness.w) * step(0.5, current_sample_fitness.w)) > 0.5)//is_sample_better(current_sample_fitness, best_sample_fitness) > 0.5)
{
best_sample_fitness = current_sample_fitness;
chosen_uv = check_uv;
@ -246,7 +255,7 @@ void main()
if(params.iteration_index < params.last_iteration_index)
{
set_value(set_a, uvi, vec4(chosen_uv, 0, 0), render_size);
set_value(set_a, uvi, vec4(chosen_uv, 0, 0));
return;
}
@ -257,11 +266,11 @@ void main()
if(best_sample_fitness.w == 0 || depth > backtracked_sample.z)
{
set_value(set_a, uvi, vec4(uvn, 0, 0), render_size);
set_value(set_a, uvi, vec4(uvn, 0, 0));
return;
}
set_value(set_a, uvi, backtracked_sample, render_size);
set_value(set_a, uvi, backtracked_sample);
return;
}

View File

@ -0,0 +1,14 @@
[remap]
importer="glsl"
type="RDShaderFile"
uid="uid://rkkajixdjosk"
path="res://.godot/imported/jfp_backtracking_experimental.glsl-a7a47621c3999d6edb8c655271f824d5.res"
[deps]
source_file="res://addons/SphynxMotionBlurToolkit/JumpFlood/ShaderFiles/jfp_backtracking_experimental.glsl"
dest_files=["res://.godot/imported/jfp_backtracking_experimental.glsl-a7a47621c3999d6edb8c655271f824d5.res"]
[params]

View File

@ -0,0 +1,192 @@
#[compute]
#version 450
#define FLT_MAX 3.402823466e+38
#define FLT_MIN 1.175494351e-38
layout(set = 0, binding = 0) uniform sampler2D tile_max_sampler;
layout(rgba16f, set = 0, binding = 1) uniform writeonly image2D buffer_a;
layout(rgba16f, set = 0, binding = 2) uniform writeonly image2D buffer_b;
layout(set = 0, binding = 3) uniform sampler2D buffer_a_sampler;
layout(set = 0, binding = 4) uniform sampler2D buffer_b_sampler;
layout(push_constant, std430) uniform Params
{
int iteration_index;
int last_iteration_index;
int nan1;
int nan2;
float perpen_error_thresh;
float sample_step_multiplier;
float motion_blur_intensity;
float nan_fl_5;
float nan_fl_4;
float nan_fl_3;
float nan_fl_6;
float step_exponent_modifier;
float step_size;
float max_dilation_radius;
float nan_fl_1;
float nan_fl_2;
} params;
layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
const int kernel_size = 8;
const vec2 check_step_kernel[kernel_size] = {
vec2(-1, 0),
vec2(1, 0),
vec2(0, -1),
vec2(0, 1),
vec2(-1, 1),
vec2(1, -1),
vec2(1, 1),
vec2(-1, -1),
};
vec2 get_value(bool a, vec2 uv)
{
if(a)
{
return textureLod(buffer_a_sampler, uv, 0.0).xy;
}
else
{
return textureLod(buffer_b_sampler, uv, 0.0).xy;
}
}
//vec4 get_value(bool a, ivec2 uvi)
//{
// if(a)
// {
// return imageLoad(buffer_a, uvi);
// }
// else
// {
// return imageLoad(buffer_b, uvi);
// }
//}
void set_value(bool a, ivec2 uvi, vec4 value)
{
if(a)
{
imageStore(buffer_a, uvi, value);
}
else
{
imageStore(buffer_b, uvi, value);
}
}
// Motion similarity
// ----------------------------------------------------------
float get_motion_difference(vec2 V, vec2 V2)
{
return clamp(dot(V - V2, V) / dot(V, V), 0, 1);
// vec2 VO = V - V2;
// float parallel = dot(VO, V) / dot(V, V);
// return clamp(parallel, 0, 1);
}
// ----------------------------------------------------------
void sample_fitness(vec2 uv_offset, vec4 uv_sample, vec2 render_size, inout vec4 current_sample_fitness)
{
vec2 sample_velocity = -uv_sample.xy;
// if velocity is 0, we never reach it (steps never smaller than 1)
if (dot(sample_velocity, sample_velocity) <= FLT_MIN || uv_sample.w == 0)
{
current_sample_fitness = vec4(FLT_MAX, FLT_MAX, FLT_MAX, -1);
return;
}
// velocity space distance (projected pixel offset onto velocity vector)
float velocity_space_distance = dot(sample_velocity, uv_offset) / dot(sample_velocity, sample_velocity);
// the velcity space distance to gravitate the JFA to (found more relieable than doing a 0 - 1 range)
float mid_point = params.motion_blur_intensity / 2;
// centralize the velocity space distance around that mid point
float absolute_velocity_space_distance = abs(velocity_space_distance - mid_point);
// if that distance is half the original, its within range (we centered around a mid point)
float within_velocity_range = step(absolute_velocity_space_distance, mid_point);
// perpendicular offset
float side_offset = abs(dot(vec2(uv_offset.y, -uv_offset.x), sample_velocity)) / dot(sample_velocity, sample_velocity);
// arbitrary perpendicular limit (lower means tighter dilation, but less reliable)
float within_perpen_error_range = step(side_offset, params.perpen_error_thresh * params.motion_blur_intensity);
// store relevant data for use in conditions
current_sample_fitness = vec4(absolute_velocity_space_distance, velocity_space_distance, uv_sample.w + uv_sample.z * velocity_space_distance, within_velocity_range * within_perpen_error_range);
}
float is_sample_better(vec4 a, vec4 b)
{
// see explanation at end of code
return mix(1. - step(b.x * a.w, a.x * b.w), step(b.z, a.z), step(0.5, b.w) * step(0.5, a.w));//1. - step(a.x * a.w, b.x * b.w);//(a.x > b.x) ? 1 : 0;//1. - step(b.x * a.w, a.x * b.w);//
}
void main()
{
ivec2 render_size = ivec2(textureSize(tile_max_sampler, 0));
ivec2 uvi = ivec2(gl_GlobalInvocationID.xy);
if ((uvi.x >= render_size.x) || (uvi.y >= render_size.y))
{
return;
}
// must be on pixel center for whole values
vec2 uvn = (vec2(uvi) + vec2(0.5)) / render_size;
vec2 uv_step = vec2(round(params.step_size)) / render_size;
vec4 best_sample_fitness = vec4(FLT_MAX, FLT_MAX, FLT_MAX, 0);
vec2 chosen_uv = uvn;
bool set_a = !bool(step(0.5, float(params.iteration_index % 2)));
vec2 step_offset;
vec2 check_uv;
vec4 uv_sample;
vec4 current_sample_fitness;
for(int i = 0; i < kernel_size; i++)
{
step_offset = check_step_kernel[i] * uv_step;
check_uv = uvn + step_offset;
if(any(notEqual(check_uv, clamp(check_uv, vec2(0.0), vec2(1.0)))))
{
continue;
}
if(params.iteration_index > 0)
{
check_uv = get_value(!set_a, check_uv).xy;
step_offset = check_uv - uvn;
}
uv_sample = textureLod(tile_max_sampler, check_uv, 0.0);
sample_fitness(step_offset, uv_sample, render_size, current_sample_fitness);
if (is_sample_better(current_sample_fitness, best_sample_fitness) > 0.5)
{
best_sample_fitness = current_sample_fitness;
chosen_uv = check_uv;
}
}
set_value(set_a, uvi, vec4(chosen_uv, 0, 0));
}
//
// if((a.w == b.w) && (a.w == 1))
// {
// return a.z < b.z ? 0. : 1.;
// }
//
// return a.x * b.w < b.x * a.w ? 1. : 0.;

View File

@ -0,0 +1,14 @@
[remap]
importer="glsl"
type="RDShaderFile"
uid="uid://c4dywnp7k8rph"
path="res://.godot/imported/jfp_simple.glsl-96987ba8c42947c7e648d28f42a73f7a.res"
[deps]
source_file="res://addons/SphynxMotionBlurToolkit/JumpFlood/ShaderFiles/jfp_simple.glsl"
dest_files=["res://.godot/imported/jfp_simple.glsl-96987ba8c42947c7e648d28f42a73f7a.res"]
[params]

View File

@ -11,23 +11,26 @@ layout(set = 0, binding = 1) uniform sampler2D depth_sampler;
layout(set = 0, binding = 2) uniform sampler2D vector_sampler;
layout(set = 0, binding = 3) uniform sampler2D velocity_map;
layout(rgba16f, set = 0, binding = 4) uniform writeonly image2D output_image;
layout(rgba16f, set = 0, binding = 5) uniform image2D past_color_image;
layout(rgba16f, set = 0, binding = 5) uniform writeonly image2D debug_1_image;
layout(rgba16f, set = 0, binding = 6) uniform writeonly image2D debug_2_image;
layout(rgba16f, set = 0, binding = 7) uniform writeonly image2D debug_3_image;
layout(rgba16f, set = 0, binding = 8) uniform writeonly image2D debug_4_image;
layout(rgba16f, set = 0, binding = 9) uniform writeonly image2D debug_5_image;
layout(rgba16f, set = 0, binding = 10) uniform writeonly image2D debug_6_image;
layout(rgba16f, set = 0, binding = 11) uniform writeonly image2D debug_7_image;
layout(rgba16f, set = 0, binding = 12) uniform writeonly image2D debug_8_image;
layout(push_constant, std430) uniform Params
{
float motion_blur_samples;
float motion_blur_intensity;
float motion_blur_center_fade;
float debug;
float freeze;
float frame;
float last_iteration_index;
float sample_step_multiplier;
float step_exponent_modifier;
float max_dilation_radius;
float nan_fl_3;
float nan_fl_4;
int debug_page;
int nan0;
int nan1;
int nan2;
int nan3;
@ -72,12 +75,7 @@ void main()
{
return;
}
// show past image for freeze frame
if(params.freeze > 0)
{
imageStore(output_image, uvi, imageLoad(past_color_image, uvi));
return;
}
// must be on pixel center for whole values (tested)
vec2 uvn = vec2(uvi + vec2(0.5)) / render_size;
@ -89,10 +87,9 @@ void main()
vec3 naive_velocity = -textureLod(vector_sampler, uvn, 0.0).xyz;
// if velocity is 0 and we dont show debug, return right away.
if ((dot(dominant_velocity, dominant_velocity) == 0 || params.motion_blur_intensity == 0) && params.debug == 0)
if ((dot(dominant_velocity, dominant_velocity) == 0 || params.motion_blur_intensity == 0))
{
imageStore(output_image, uvi, base_color);
imageStore(past_color_image, uvi, base_color);
return;
}
// offset along velocity to blend between sample steps
@ -115,40 +112,82 @@ void main()
vec3 naive_offset = naive_step_sample * noise_offset;
vec3 dominant_back_offset = -step_sample * (1. - noise_offset);
vec4 col = base_color * total_weight;
float naive_depth = textureLod(depth_sampler, uvn, 0.0).x;
float backstepping_coef = clamp(length(dominant_velocity) / 0.05, 0, 1);
vec2 dominant_uvo;
vec2 naive_uvo;
vec3 current_dominant_offset;
float current_naive_depth;
float foreground;
vec3 current_dominant_velocity;
float motion_difference;
float sample_weight;
float dominant_naive_mix;
vec2 sample_uv;
for (int i = 1; i < params.motion_blur_samples; i++)
{
dominant_offset += step_sample;
naive_offset += naive_step_sample;
vec2 dominant_uvo = uvn + dominant_offset.xy;
dominant_uvo = uvn + dominant_offset.xy;
vec2 naive_uvo = uvn + naive_offset.xy;
naive_uvo = uvn + naive_offset.xy;
current_dominant_offset = dominant_offset;
if (any(notEqual(dominant_uvo, clamp(dominant_uvo, vec2(0.0), vec2(1.0)))))
current_naive_depth = textureLod(depth_sampler, dominant_uvo, 0.0).x;
// is current depth closer than origin of dilation (stepped into a foreground object)
foreground = step(naive_depth + current_dominant_offset.z, current_naive_depth - 0.0001);
velocity_map_step_sample = textureLod(velocity_map, dominant_uvo, 0.0);
current_dominant_velocity = -textureLod(vector_sampler, velocity_map_step_sample.xy, 0.0).xyz;
motion_difference = get_motion_difference(dominant_velocity.xy, current_dominant_velocity.xy, 0.1);
sample_weight = 1;
if (any(notEqual(dominant_uvo, clamp(dominant_uvo, vec2(0.0), vec2(1.0)))) || foreground * motion_difference > 0.5)
{
break;
dominant_uvo = uvn + dominant_back_offset.xy;
current_dominant_offset = dominant_back_offset;
dominant_back_offset -= step_sample;
sample_weight = 0.5;//backstepping_coef;
}
velocity_map_step_sample = textureLod(velocity_map, dominant_uvo, 0.0);
vec3 current_dominant_velocity = -textureLod(vector_sampler, velocity_map_step_sample.xy, 0.0).xyz;
float current_naive_depth = textureLod(depth_sampler, dominant_uvo, 0.0).x;
// is current velocity different than dilated velocity
float motion_difference = get_motion_difference(dominant_velocity.xy, current_dominant_velocity.xy, 0.1);
// is current depth closer than origin of dilation (object in the foreground)
float foreground = step(naive_depth + dominant_offset.z, current_naive_depth - 0.0001);
current_dominant_velocity = -textureLod(vector_sampler, velocity_map_step_sample.xy, 0.0).xyz;
// is current velocity different than dilated velocity
current_naive_depth = textureLod(depth_sampler, dominant_uvo, 0.0).x;
// is current depth closer than origin of dilation (stepped into a foreground object)
foreground = step(naive_depth + current_dominant_offset.z, current_naive_depth - 0.002);
motion_difference = get_motion_difference(dominant_velocity.xy, current_dominant_velocity.xy, 0.1);
// if we are sampling a foreground object and its velocity is different, discard this sample (prevent ghosting)
float sample_weight = 1 - (foreground * motion_difference);
sample_weight *= 1 - (foreground * motion_difference);
float dominant_naive_mix = 1. - step(0.9, motion_difference);
dominant_naive_mix = 1. - step(0.9, motion_difference);
vec2 sample_uv = mix(naive_uvo, dominant_uvo, dominant_naive_mix);
sample_uv = mix(naive_uvo, dominant_uvo, dominant_naive_mix);
total_weight += sample_weight;
@ -157,42 +196,5 @@ void main()
col /= total_weight;
if (params.debug == 0)
{
imageStore(output_image, uvi, col);
imageStore(past_color_image, uvi, col);
return;
}
vec4 tl_col;
vec4 tr_col;
vec4 bl_col;
vec4 br_col;
if(params.debug_page == 0)
{
tl_col = vec4((textureLod(vector_sampler, uvn, 0.0).xyz) * vec3(10, 10, 10000), 1);
tr_col = vec4(abs(dominant_velocity.xy) * 10, 0, 1);
bl_col = vec4(abs(velocity_map_sample.xyw - vec3(uvn, 0)) * vec3(10, 10, 1), 1);
br_col = col;
}
if(params.debug_page == 1)
{
tl_col = vec4(naive_depth * 10);
tr_col = textureLod(color_sampler, velocity_map_sample.xy, 0.0);//
//bl_col = vec4(dominant_depth * 10);
br_col = col;
}
imageStore(output_image, uvi / 2, tl_col);
imageStore(output_image, uvi / 2 + ivec2(vec2(0.5, 0.5) * render_size), br_col);
imageStore(output_image, uvi / 2 + ivec2(vec2(0.0, 0.5) * render_size), bl_col);
imageStore(output_image, uvi / 2 + ivec2(vec2(0.5, 0.0) * render_size), tr_col);
imageStore(past_color_image, uvi / 2, tl_col);
imageStore(past_color_image, uvi / 2 + ivec2(vec2(0.5, 0.5) * render_size), br_col);
imageStore(past_color_image, uvi / 2 + ivec2(vec2(0.0, 0.5) * render_size), bl_col);
imageStore(past_color_image, uvi / 2 + ivec2(vec2(0.5, 0.0) * render_size), tr_col);
imageStore(output_image, uvi, col);
}

View File

@ -0,0 +1,14 @@
[remap]
importer="glsl"
type="RDShaderFile"
uid="uid://c57nhlyxb4m1t"
path="res://.godot/imported/jump_flood_blur.glsl-11f088c8cddfb4c62f32dfa84c694ded.res"
[deps]
source_file="res://addons/SphynxMotionBlurToolkit/JumpFlood/ShaderFiles/jump_flood_blur.glsl"
dest_files=["res://.godot/imported/jump_flood_blur.glsl-11f088c8cddfb4c62f32dfa84c694ded.res"]
[params]

View File

@ -0,0 +1,235 @@
#[compute]
#version 450
#define FLT_MAX 3.402823466e+38
#define FLT_MIN 1.175494351e-38
#define M_PI 3.1415926535897932384626433832795
layout(set = 0, binding = 0) uniform sampler2D color_sampler;
layout(set = 0, binding = 1) uniform sampler2D depth_sampler;
layout(set = 0, binding = 2) uniform sampler2D vector_sampler;
layout(set = 0, binding = 3) uniform sampler2D velocity_map;
layout(rgba16f, set = 0, binding = 4) uniform writeonly image2D output_image;
layout(rgba16f, set = 0, binding = 5) uniform writeonly image2D debug_1_image;
layout(rgba16f, set = 0, binding = 6) uniform writeonly image2D debug_2_image;
layout(rgba16f, set = 0, binding = 7) uniform writeonly image2D debug_3_image;
layout(rgba16f, set = 0, binding = 8) uniform writeonly image2D debug_4_image;
layout(rgba16f, set = 0, binding = 9) uniform writeonly image2D debug_5_image;
layout(rgba16f, set = 0, binding = 10) uniform writeonly image2D debug_6_image;
layout(rgba16f, set = 0, binding = 11) uniform writeonly image2D debug_7_image;
layout(rgba16f, set = 0, binding = 12) uniform writeonly image2D debug_8_image;
layout(set = 0, binding = 13) uniform sampler2D tile_max;
layout(push_constant, std430) uniform Params
{
float motion_blur_samples;
float motion_blur_intensity;
float motion_blur_center_fade;
float frame;
float last_iteration_index;
float sample_step_multiplier;
float step_exponent_modifier;
float max_dilation_radius;
int nan0;
int nan1;
int nan2;
int nan3;
} params;
layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
// McGuire's functions https://docs.google.com/document/d/1IIlAKTj-O01hcXEdGxTErQbCHO9iBmRx6oFUy_Jm0fI/edit
// ----------------------------------------------------------
float soft_depth_compare(float depth_X, float depth_Y, float sze)
{
return clamp(1 - (depth_X - depth_Y) / sze, 0, 1);
}
float cone(float T, float v)
{
return clamp(1 - T / v, 0, 1);
}
float cylinder(float T, float v)
{
return 1.0 - smoothstep(0.95 * v, 1.05 * v, T);
}
// ----------------------------------------------------------
// Guertin's functions https://research.nvidia.com/sites/default/files/pubs/2013-11_A-Fast-and/Guertin2013MotionBlur-small.pdf
// ----------------------------------------------------------
float z_compare(float a, float b, float sze)
{
return clamp(1. - sze * (a - b) / min(a, b), 0, 1);
}
// ----------------------------------------------------------
// from https://www.shadertoy.com/view/ftKfzc
// ----------------------------------------------------------
float interleaved_gradient_noise(vec2 uv){
uv += float(params.frame) * (vec2(47, 17) * 0.695);
vec3 magic = vec3( 0.06711056, 0.00583715, 52.9829189 );
return fract(magic.z * fract(dot(uv, magic.xy)));
}
// ----------------------------------------------------------
// from https://github.com/bradparks/KinoMotion__unity_motion_blur/tree/master
// ----------------------------------------------------------
vec2 safenorm(vec2 v)
{
float l = max(length(v), 1e-6);
return v / l * int(1 >= 0.5);
}
vec2 jitter_tile(vec2 uvi)
{
float rx, ry;
float angle = interleaved_gradient_noise(uvi + vec2(2, 0)) * M_PI * 2;
rx = cos(angle);
ry = sin(angle);
return vec2(rx, ry) / textureSize(tile_max, 0) / 4;
}
// ----------------------------------------------------------
float get_motion_difference(vec2 V, vec2 V2, float power)
{
vec2 VO = V - V2;
float difference = dot(VO, V) / max(FLT_MIN, dot(V, V));
return pow(clamp(difference, 0, 1), power);
}
vec2 sample_random_offset(vec2 uv, float j)
{
return vec2(0);
}
void main()
{
ivec2 render_size = ivec2(textureSize(color_sampler, 0));
ivec2 uvi = ivec2(gl_GlobalInvocationID.xy);
if ((uvi.x >= render_size.x) || (uvi.y >= render_size.y))
{
return;
}
vec2 x = (vec2(uvi) + vec2(0.5)) / vec2(render_size);
vec2 velocity_map_sample = textureLod(velocity_map, x + jitter_tile(uvi), 0.0).xy;
vec3 vnz = textureLod(tile_max, velocity_map_sample, 0.0).xyz * vec3(render_size, 1);// * 2;
vec2 vn = vnz.xy;
float vn_length = max(0.5, length(vn));
vec2 wn = safenorm(vn);
vec4 col_x = textureLod(color_sampler, x, 0.0);
vec3 vxz = textureLod(vector_sampler, x, 0.0).xyz * vec3(render_size, 1);// * 2;
vec2 vx = vxz.xy;
if(vn_length <= 0.5)
{
imageStore(output_image, uvi, col_x);
imageStore(debug_1_image, uvi, col_x);
imageStore(debug_2_image, uvi, abs(vec4(vn / render_size * 10, vnz.z * 100, 1)));
imageStore(debug_3_image, uvi, abs(vec4(velocity_map_sample - x, 0, 1)));
imageStore(debug_4_image, uvi, abs(vec4(vx / render_size * 10, vxz.z * 100, 1)));
imageStore(debug_5_image, uvi, 10 * abs(textureLod(tile_max, x, 0.0)));
imageStore(debug_6_image, uvi, 10 * abs(textureLod(tile_max, textureLod(velocity_map, x, 0.0).xy, 0.0)));
imageStore(debug_7_image, uvi, 10 * abs(textureLod(velocity_map, x, 0.0)));
imageStore(debug_8_image, uvi, abs(textureLod(velocity_map, x, 0.0) / 10));
return;
}
float zx = -0.05 / max(FLT_MIN, textureLod(depth_sampler, x, 0.0).x);
float vx_length = max(0.5, length(vx));
vec2 wx = safenorm(vx);
vec2 wp = vec2(-wn.y, wn.x);
if(dot(wp, vx) < 0)
{
wp = -wp;
}
vec2 wc = safenorm(mix(wp, wx, clamp((vx_length - 0.5) / 1.5, 0, 1)));
float weight = 1;//params.motion_blur_samples / (100 * vx_length);
vec4 sum = col_x * weight;
float j = interleaved_gradient_noise(uvi) - 0.5;
int vnvx = 2;//int(vn_length / (10 + vx_length)) + 2;
for(int i = 0; i < params.motion_blur_samples; i++)
{
if(i == (params.motion_blur_samples - 1) / 2)
{
continue;
}
float t = mix(-1., 0.0, (i + j + 1.0) / (params.motion_blur_samples + 1.0));
float T = abs(t * vn_length);
float Tx = abs((t + 0.5) * vn_length);
bool sample_main_v = !(((i - 1) % vnvx) == 0);
vec2 d = vn;//sample_main_v ? vn : vx;
float dz = vnz.z;//sample_main_v ? vnz.z : vxz.z;
vec2 wd = safenorm(d);
vec2 y = x + (d / render_size) * t;
vec2 vy = textureLod(vector_sampler, y, 0.0).xy * render_size;// * 2;
float vy_length = max(0.5, length(vy));
float zy = -0.05 / max(FLT_MIN, textureLod(depth_sampler, y, 0.0).x - dz * t);
float f = z_compare(zy, zx, 15);
float b = z_compare(zx, zy, 15);
float wa = abs(max(0, dot(vy / vy_length, wd)));
float wb = abs((dot(wc, wd)));
float cone_x = cone(T, vx_length); // how much of the velocity reaches the current position
float cone_y = cone(T, vy_length); // how much of the velocity reaches the current position
float ay = clamp(max(step(FLT_MIN, f * wa * cone_y), step(FLT_MIN, b * wb * cone_x)), 0, 1);// * wb;// + cylinder(T, vy_length) * cylinder(T, vx_length) * 2;//cylinder(T, min(vy_length, vx_length)) * 2. * max(wa, wb);//
vec4 col_y = textureLod(color_sampler, y, 0.0);
vec4 final_color = mix(col_x, col_y, ay);
float final_weight = mix(1, 1, ay);
weight += final_weight;//ay;
sum += final_color * final_weight;// * ay;
}
sum /= weight;
imageStore(output_image, uvi, sum);
imageStore(debug_1_image, uvi, sum);
imageStore(debug_2_image, uvi, abs(vec4(vn / render_size * 10, vnz.z * 100, 1)));
imageStore(debug_3_image, uvi, abs(vec4(velocity_map_sample - x, 0, 1)));
imageStore(debug_4_image, uvi, abs(vec4(vx / render_size * 10, vxz.z * 100, 1)));
imageStore(debug_5_image, uvi, 10 * abs(textureLod(tile_max, x, 0.0)));
imageStore(debug_6_image, uvi, 10 * abs(textureLod(tile_max, textureLod(velocity_map, x, 0.0).xy, 0.0)));
imageStore(debug_7_image, uvi, 10 * abs(textureLod(velocity_map, x, 0.0)));
imageStore(debug_8_image, uvi, abs(textureLod(velocity_map, x, 0.0) / 10));
}

View File

@ -0,0 +1,14 @@
[remap]
importer="glsl"
type="RDShaderFile"
uid="uid://dc6r26wwdjceq"
path="res://.godot/imported/jump_flood_mcguire_blur.glsl-01a8aea5f4a3ebff22641db3a49ace6c.res"
[deps]
source_file="res://addons/SphynxMotionBlurToolkit/JumpFlood/ShaderFiles/jump_flood_mcguire_blur.glsl"
dest_files=["res://.godot/imported/jump_flood_mcguire_blur.glsl-01a8aea5f4a3ebff22641db3a49ace6c.res"]
[params]

View File

@ -0,0 +1,274 @@
#[compute]
#version 450
#define FLT_MAX 3.402823466e+38
#define FLT_MIN 1.175494351e-38
#define M_PI 3.1415926535897932384626433832795
layout(set = 0, binding = 0) uniform sampler2D color_sampler;
layout(set = 0, binding = 1) uniform sampler2D depth_sampler;
layout(set = 0, binding = 2) uniform sampler2D vector_sampler;
layout(set = 0, binding = 3) uniform sampler2D velocity_map;
layout(rgba16f, set = 0, binding = 4) uniform writeonly image2D output_image;
layout(rgba16f, set = 0, binding = 5) uniform writeonly image2D debug_1_image;
layout(rgba16f, set = 0, binding = 6) uniform writeonly image2D debug_2_image;
layout(rgba16f, set = 0, binding = 7) uniform writeonly image2D debug_3_image;
layout(rgba16f, set = 0, binding = 8) uniform writeonly image2D debug_4_image;
layout(rgba16f, set = 0, binding = 9) uniform writeonly image2D debug_5_image;
layout(rgba16f, set = 0, binding = 10) uniform writeonly image2D debug_6_image;
layout(rgba16f, set = 0, binding = 11) uniform writeonly image2D debug_7_image;
layout(rgba16f, set = 0, binding = 12) uniform writeonly image2D debug_8_image;
layout(set = 0, binding = 13) uniform sampler2D tile_max;
layout(push_constant, std430) uniform Params
{
float motion_blur_samples;
float motion_blur_intensity;
float motion_blur_center_fade;
float frame;
float last_iteration_index;
float sample_step_multiplier;
float step_exponent_modifier;
float max_dilation_radius;
int nan0;
int nan1;
int nan2;
int nan3;
} params;
layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
// McGuire's functions https://docs.google.com/document/d/1IIlAKTj-O01hcXEdGxTErQbCHO9iBmRx6oFUy_Jm0fI/edit
// ----------------------------------------------------------
float soft_depth_compare(float depth_X, float depth_Y, float sze)
{
return clamp(1 - (depth_X - depth_Y) / sze, 0, 1);
}
float cone(float T, float v)
{
return clamp(1 - T / v, 0, 1);
}
float cylinder(float T, float v)
{
return 1.0 - smoothstep(0.95 * v, 1.05 * v, T);
}
// ----------------------------------------------------------
// Guertin's functions https://research.nvidia.com/sites/default/files/pubs/2013-11_A-Fast-and/Guertin2013MotionBlur-small.pdf
// ----------------------------------------------------------
float z_compare(float a, float b, float sze)
{
return clamp(1. - sze * (a - b) / min(a, b), 0, 1);
}
// ----------------------------------------------------------
// from https://www.shadertoy.com/view/ftKfzc
// ----------------------------------------------------------
float interleaved_gradient_noise(vec2 uv){
uv += float(params.frame) * (vec2(47, 17) * 0.695);
vec3 magic = vec3( 0.06711056, 0.00583715, 52.9829189 );
return fract(magic.z * fract(dot(uv, magic.xy)));
}
// ----------------------------------------------------------
// from https://github.com/bradparks/KinoMotion__unity_motion_blur/tree/master
// ----------------------------------------------------------
vec2 safenorm(vec2 v)
{
float l = max(length(v), 1e-6);
return v / l * int(1 >= 0.5);
}
vec2 jitter_tile(vec2 uvi)
{
float rx, ry;
float angle = interleaved_gradient_noise(uvi + vec2(2, 0)) * M_PI * 2;
rx = cos(angle);
ry = sin(angle);
return vec2(rx, ry) / textureSize(tile_max, 0) / 4;
}
// ----------------------------------------------------------
float get_motion_difference(vec2 V, vec2 V2, float power)
{
vec2 VO = V - V2;
float difference = dot(VO, V) / max(FLT_MIN, dot(V, V));
return pow(clamp(difference, 0, 1), power);
}
vec2 sample_random_offset(vec2 uv, float j)
{
return vec2(0);
}
void main()
{
ivec2 render_size = ivec2(textureSize(color_sampler, 0));
ivec2 uvi = ivec2(gl_GlobalInvocationID.xy);
if ((uvi.x >= render_size.x) || (uvi.y >= render_size.y))
{
return;
}
vec2 x = (vec2(uvi) + vec2(0.5)) / vec2(render_size);
vec2 velocity_map_sample = textureLod(velocity_map, x + jitter_tile(uvi), 0.0).xy;
vec3 vnz = textureLod(tile_max, velocity_map_sample, 0.0).xyz * vec3(render_size, 1);// * 2;
vec2 vn = vnz.xy;
float vn_length = max(0.5, length(vn));
vec2 wn = safenorm(vn);
vec4 col_x = textureLod(color_sampler, x, 0.0);
vec3 vxz = textureLod(vector_sampler, x, 0.0).xyz * vec3(render_size, 1);// * 2;
vec2 vx = vxz.xy;
if(vn_length <= 0.5)
{
imageStore(output_image, uvi, col_x);
imageStore(debug_1_image, uvi, col_x);
imageStore(debug_2_image, uvi, abs(vec4(vn / render_size * 10, vnz.z * 100, 1)));
imageStore(debug_3_image, uvi, abs(vec4(velocity_map_sample - x, 0, 1)));
imageStore(debug_4_image, uvi, abs(vec4(vx / render_size * 10, vxz.z * 100, 1)));
imageStore(debug_5_image, uvi, 10 * abs(textureLod(tile_max, x, 0.0)));
imageStore(debug_6_image, uvi, 10 * abs(textureLod(tile_max, textureLod(velocity_map, x, 0.0).xy, 0.0)));
imageStore(debug_7_image, uvi, 10 * abs(textureLod(velocity_map, x, 0.0)));
imageStore(debug_8_image, uvi, abs(textureLod(velocity_map, x, 0.0) / 10));
return;
}
float zx = -0.05 / max(FLT_MIN, textureLod(depth_sampler, x, 0.0).x);
float vx_length = max(0.5, length(vx));
vec2 wx = safenorm(vx);
vec2 wp = vec2(-wn.y, wn.x);
if(dot(wp, vx) < 0)
{
wp = -wp;
}
vec2 wc = safenorm(mix(wp, wx, clamp((vx_length - 0.5) / 1.5, 0, 1)));
float weight = 0;// params.motion_blur_samples / (40 * vx_length);
vec4 sum = col_x * weight;
float j = interleaved_gradient_noise(uvi) - 0.5;
int vnvx = 2;//int(vn_length / (10 + vx_length)) + 2;
float total_back_weight = 1e-10;
vec4 back_sum = col_x * total_back_weight;
for(int i = 0; i < params.motion_blur_samples; i++)
{
float t = mix(-1., 0.0, (i + j + 1.0) / (params.motion_blur_samples + 1.0));
float T = abs(t * vn_length);
float Tx = abs((t + 0.5) * vn_length);
bool sample_main_v = !(((i - 1) % vnvx) == 0);
vec2 d = vn;//sample_main_v ? vn : vx;
vec2 nai_d = vx;
vec2 nai_wd = safenorm(nai_d);
float nai_dz = vxz.z;
float dz = vnz.z;//sample_main_v ? vnz.z : vxz.z;
vec2 wd = safenorm(d);
vec2 y = x + (d / render_size) * t;
vec2 nai_y = x + (nai_d / render_size) * t;
float nai_y_length = max(0.5, length(nai_y));
vec2 vy = textureLod(vector_sampler, y, 0.0).xy * render_size;// * 2;
float vy_length = max(0.5, length(vy));
vec2 nai_vy = textureLod(vector_sampler, nai_y, 0.0).xy * render_size;
float nai_vy_length = max(0.5, length(nai_vy));
float zy = -0.05 / max(FLT_MIN, textureLod(depth_sampler, y, 0.0).x - dz * t);
float nai_zy = -0.05 / max(FLT_MIN, textureLod(depth_sampler, nai_y, 0.0).x - nai_dz * t);
float f = z_compare(zy, zx, 15);
float b = z_compare(zx, zy, 15);
float wa = abs(max(0, dot(vy / vy_length, wd)));
float wb = abs((dot(wc, wd)));
float cone_x = cone(T, vx_length);
float cone_y = cone(T, vy_length);
float nai_f = z_compare(nai_zy, zx, 15);
float nai_b = z_compare(zx, nai_zy, 15);
float nai_wa = abs(max(0, dot(nai_vy / nai_vy_length, nai_wd)));
float nai_wb = abs((dot(wc, nai_wd)));
float nai_cone_y = cone(T, nai_vy_length);
float ay = max(f * wa * step(FLT_MIN, cone_y), b * wb * cone_x);
float nai_ay = nai_b;
vec4 col_y = textureLod(color_sampler, y, 0.0);
vec4 nai_col_y = textureLod(color_sampler, nai_y, 0.0);
vec4 col_back = nai_col_y;
float back_weight = mix(0, 1, nai_ay);
total_back_weight += back_weight;
back_sum += col_back * back_weight;
weight += ay;
sum += col_y * ay;
}
back_sum *= (params.motion_blur_samples - weight) / total_back_weight;
sum /= params.motion_blur_samples;
back_sum /= params.motion_blur_samples;
imageStore(output_image, uvi, sum + back_sum);
imageStore(debug_1_image, uvi, sum + back_sum);
imageStore(debug_2_image, uvi, abs(vec4(vn / render_size * 10, vnz.z * 100, 1)));
imageStore(debug_3_image, uvi, abs(vec4(velocity_map_sample - x, 0, 1)));
imageStore(debug_4_image, uvi, abs(vec4(vx / render_size * 10, vxz.z * 100, 1)));
imageStore(debug_5_image, uvi, 10 * abs(textureLod(tile_max, x, 0.0)));
imageStore(debug_6_image, uvi, 10 * abs(textureLod(tile_max, textureLod(velocity_map, x, 0.0).xy, 0.0)));
imageStore(debug_7_image, uvi, 10 * abs(textureLod(velocity_map, x, 0.0)));
imageStore(debug_8_image, uvi, abs(textureLod(velocity_map, x, 0.0) / 10));
}

View File

@ -0,0 +1,14 @@
[remap]
importer="glsl"
type="RDShaderFile"
uid="uid://bdm5t4l1y3ts7"
path="res://.godot/imported/jump_flood_new_blur.glsl-ebfb8c41097767aad8ea133e2ff78878.res"
[deps]
source_file="res://addons/SphynxMotionBlurToolkit/JumpFlood/ShaderFiles/jump_flood_new_blur.glsl"
dest_files=["res://.godot/imported/jump_flood_new_blur.glsl-ebfb8c41097767aad8ea133e2ff78878.res"]
[params]

View File

@ -0,0 +1,14 @@
[remap]
importer="glsl"
type="RDShaderFile"
uid="uid://dig08kpnfakuf"
path="res://.godot/imported/jump_flood_overlay.glsl-fc28b3ae9a688e5da04536a5cdb7b76e.res"
[deps]
source_file="res://addons/SphynxMotionBlurToolkit/JumpFlood/ShaderFiles/jump_flood_overlay.glsl"
dest_files=["res://.godot/imported/jump_flood_overlay.glsl-fc28b3ae9a688e5da04536a5cdb7b76e.res"]
[params]

View File

@ -0,0 +1,8 @@
[gd_resource type="Resource" script_class="ShaderStageResource" load_steps=3 format=3 uid="uid://bj3exhmsfcx4w"]
[ext_resource type="Script" path="res://addons/SphynxMotionBlurToolkit/BaseClasses/shader_pass_resource.gd" id="1_v4e3u"]
[ext_resource type="RDShaderFile" uid="uid://c4dywnp7k8rph" path="res://addons/SphynxMotionBlurToolkit/JumpFlood/ShaderFiles/jfp_simple.glsl" id="2_msxel"]
[resource]
script = ExtResource("1_v4e3u")
shader_file = ExtResource("2_msxel")

View File

@ -0,0 +1,8 @@
[gd_resource type="Resource" script_class="ShaderStageResource" load_steps=3 format=3 uid="uid://nhb123qs0ja8"]
[ext_resource type="Script" path="res://addons/SphynxMotionBlurToolkit/BaseClasses/shader_pass_resource.gd" id="1_fyqxe"]
[ext_resource type="RDShaderFile" uid="uid://c57nhlyxb4m1t" path="res://addons/SphynxMotionBlurToolkit/JumpFlood/ShaderFiles/jump_flood_blur.glsl" id="2_c1vs2"]
[resource]
script = ExtResource("1_fyqxe")
shader_file = ExtResource("2_c1vs2")

View File

@ -0,0 +1,8 @@
[gd_resource type="Resource" script_class="ShaderStageResource" load_steps=3 format=3 uid="uid://clwi2fnp1nm3r"]
[ext_resource type="Script" path="res://addons/SphynxMotionBlurToolkit/BaseClasses/shader_pass_resource.gd" id="1_eeyf1"]
[ext_resource type="RDShaderFile" uid="uid://rkkajixdjosk" path="res://addons/SphynxMotionBlurToolkit/JumpFlood/ShaderFiles/jfp_backtracking_experimental.glsl" id="2_o6bvw"]
[resource]
script = ExtResource("1_eeyf1")
shader_file = ExtResource("2_o6bvw")

View File

@ -0,0 +1,270 @@
extends MotionBlurCompositorEffect
class_name SphynxOldJumpFloodMotionBlur
@export_group("Motion Blur", "motion_blur_")
# diminishing returns over 16
@export_range(4, 64) var motion_blur_samples: int = 8
# you really don't want this over 0.5, but you can if you want to try
@export_range(0, 0.5, 0.001, "or_greater") var motion_blur_intensity: float = 1
@export_range(0, 1) var motion_blur_center_fade: float = 0.0
@export var blur_stage : ShaderStageResource = preload("res://addons/SphynxMotionBlurToolkit/JumpFlood/jump_flood_blur_stage.tres"):
set(value):
unsubscribe_shader_stage(blur_stage)
blur_stage = value
subscirbe_shader_stage(value)
@export var overlay_stage : ShaderStageResource = preload("res://addons/SphynxMotionBlurToolkit/JumpFlood/jump_flood_overlay_stage.tres"):
set(value):
unsubscribe_shader_stage(overlay_stage)
overlay_stage = value
subscirbe_shader_stage(value)
@export var construct_stage : ShaderStageResource = preload("res://addons/SphynxMotionBlurToolkit/JumpFlood/jump_flood_construction_stage.tres"):
set(value):
unsubscribe_shader_stage(construct_stage)
construct_stage = value
subscirbe_shader_stage(value)
## the portion of speed that is allowed for side bleed of velocities
## during the jfa dilation passes and before backtracking. Getting this a higher value
## would make it so that meshes at movement blur more reliably, but also bleed
## further perpendicularly to their velocity, thus wash elemets behind them out.
@export var perpen_error_threshold : float = 0.5
## an initial step size that can increase the dilation radius proportionally, at the
## sacrifice of some quality in the final resolution of the dilation.[br][br]
## the formula for the maximum radius of the dilation (in pixels) is: pow(2 + step_exponent_modifier, JFA_pass_count) * sample_step_multiplier
@export var sample_step_multiplier : float = 16
## by default, the jump flood makes samples along distances that start
## at 2 to the power of the pass count you want to perform, which is also
## the dilation radius you desire. You can change it to values higher than
## 2 with this variable, and reach higher dilation radius at the sacrifice of
## some accuracy in the dilation.
## the formula for the maximum radius of the dilation (in pixels) is: pow(2 + step_exponent_modifier, JFA_pass_count) * sample_step_multiplier
@export var step_exponent_modifier : float = 1
## how many steps along a range of 2 velocities from the
## dilation target velocity space do we go along to find a better fitting velocity sample
## higher samples meaning higher detail getting captured and blurred
@export var backtracking_sample_count : int = 8
## how sensitive the backtracking for velocities be
@export var backtracking_velocity_match_threshold : float = 0.9
## how sensitively the backtracking should treat velocities that are a different
## length along that velocity
@export var backtracking_velocity_match_parallel_sensitivity : float = 1
## how sensitively the backtracking should treat velcoities that have perpendicular
## offset to that velocity
@export var backtracking_velcoity_match_perpendicular_sensitivity : float = 0.05
## how closely does the depth of the backtracked sample has to match the original sample to be
## considered (in NDC space)
@export var backtracbing_depth_match_threshold : float = 0.001
## the number of passes performed by the jump flood algorithm based dilation,
## each pass added doubles the maximum radius of dilation available.[br][br]
## the formula for the maximum radius of the dilation (in pixels) is: pow(2 + step_exponent_modifier, JFA_pass_count) * sample_step_multiplier
@export var JFA_pass_count : int = 3
## wether this motion blur stays the same intensity below
## target_constant_framerate
@export var framerate_independent : bool = true
## Description: Removes clamping on motion blur scale to allow framerate independent motion
## blur to scale longer than realistically possible when render framerate is higher
## than target framerate.[br][br]
## [color=yellow]Warning:[/color] Turning this on would allow over-blurring of pixels, which
## produces inaccurate results, and would likely cause nausea in players over
## long exposure durations, use with caution and out of artistic intent
@export var uncapped_independence : bool = false
## if framerate_independent is enabled, the blur would simulate
## sutter speeds at that framerate, and up.
@export var target_constant_framerate : float = 30
var texture: StringName = "texture"
var buffer_a : StringName = "buffer_a"
var buffer_b : StringName = "buffer_b"
var custom_velocity : StringName = "custom_velocity"
@export var debug_1 : String = "debug_1"
@export var debug_2 : String = "debug_2"
@export var debug_3 : String = "debug_3"
@export var debug_4 : String = "debug_4"
@export var debug_5 : String = "debug_5"
@export var debug_6 : String = "debug_6"
@export var debug_7 : String = "debug_7"
@export var debug_8 : String = "debug_8"
var temp_motion_blur_intensity : float
var previous_time : float = 0
func _render_callback_2(render_size : Vector2i, render_scene_buffers : RenderSceneBuffersRD, render_scene_data : RenderSceneDataRD):
var time : float = float(Time.get_ticks_msec()) / 1000
var delta_time : float = time - previous_time
previous_time = time
temp_motion_blur_intensity = motion_blur_intensity
if framerate_independent:
var capped_frame_time : float = 1 / target_constant_framerate
if !uncapped_independence:
capped_frame_time = min(capped_frame_time, delta_time)
temp_motion_blur_intensity = motion_blur_intensity * capped_frame_time / delta_time
ensure_texture(texture, render_scene_buffers)
ensure_texture(buffer_a, render_scene_buffers)#, RenderingDevice.DATA_FORMAT_R16G16_SFLOAT)
ensure_texture(buffer_b, render_scene_buffers)#, RenderingDevice.DATA_FORMAT_R16G16_SFLOAT)
ensure_texture(custom_velocity, render_scene_buffers)
ensure_texture(debug_1, render_scene_buffers)
ensure_texture(debug_2, render_scene_buffers)
ensure_texture(debug_3, render_scene_buffers)
ensure_texture(debug_4, render_scene_buffers)
ensure_texture(debug_5, render_scene_buffers)
ensure_texture(debug_6, render_scene_buffers)
ensure_texture(debug_7, render_scene_buffers)
ensure_texture(debug_8, render_scene_buffers)
rd.draw_command_begin_label("Motion Blur", Color(1.0, 1.0, 1.0, 1.0))
var last_iteration_index : int = JFA_pass_count - 1;
var max_dilation_radius : float = pow(2 + step_exponent_modifier, last_iteration_index) * sample_step_multiplier / motion_blur_intensity;
var push_constant: PackedFloat32Array = [
motion_blur_samples,
temp_motion_blur_intensity,
motion_blur_center_fade,
Engine.get_frames_drawn() % 8,
last_iteration_index,
sample_step_multiplier,
step_exponent_modifier,
max_dilation_radius,
]
var int_push_constant : PackedInt32Array = [
0,
0,
0,
0
]
var byte_array = push_constant.to_byte_array()
byte_array.append_array(int_push_constant.to_byte_array())
var view_count = render_scene_buffers.get_view_count()
for view in range(view_count):
var color_image := render_scene_buffers.get_color_layer(view)
var depth_image := render_scene_buffers.get_depth_layer(view)
var texture_image := render_scene_buffers.get_texture_slice(context, texture, view, 0, 1, 1)
var buffer_a_image := render_scene_buffers.get_texture_slice(context, buffer_a, view, 0, 1, 1)
var buffer_b_image := render_scene_buffers.get_texture_slice(context, buffer_b, view, 0, 1, 1)
var custom_velocity_image := render_scene_buffers.get_texture_slice(context, custom_velocity, view, 0, 1, 1)
var debug_1_image := render_scene_buffers.get_texture_slice(context, debug_1, view, 0, 1, 1)
var debug_2_image := render_scene_buffers.get_texture_slice(context, debug_2, view, 0, 1, 1)
var debug_3_image := render_scene_buffers.get_texture_slice(context, debug_3, view, 0, 1, 1)
var debug_4_image := render_scene_buffers.get_texture_slice(context, debug_4, view, 0, 1, 1)
var debug_5_image := render_scene_buffers.get_texture_slice(context, debug_5, view, 0, 1, 1)
var debug_6_image := render_scene_buffers.get_texture_slice(context, debug_6, view, 0, 1, 1)
var debug_7_image := render_scene_buffers.get_texture_slice(context, debug_7, view, 0, 1, 1)
var debug_8_image := render_scene_buffers.get_texture_slice(context, debug_8, view, 0, 1, 1)
rd.draw_command_begin_label("Construct blur " + str(view), Color(1.0, 1.0, 1.0, 1.0))
var tex_uniform_set
var compute_list
var x_groups := floori((render_size.x - 1) / 16 + 1)
var y_groups := floori((render_size.y - 1) / 16 + 1)
tex_uniform_set = UniformSetCacheRD.get_cache(construct_stage.shader, 0, [
get_sampler_uniform(depth_image, 0, false),
get_sampler_uniform(custom_velocity_image, 1, false),
get_image_uniform(buffer_a_image, 2),
get_image_uniform(buffer_b_image, 3),
get_sampler_uniform(buffer_a_image, 4, false),
get_sampler_uniform(buffer_b_image, 5, false)
])
compute_list = rd.compute_list_begin()
rd.compute_list_bind_compute_pipeline(compute_list, construct_stage.pipeline)
rd.compute_list_bind_uniform_set(compute_list, tex_uniform_set, 0)
for i in JFA_pass_count:
var jf_push_constants : PackedInt32Array = [
i,
last_iteration_index,
backtracking_sample_count,
16
]
var step_size : float = round(pow(2 + step_exponent_modifier, last_iteration_index - i)) * sample_step_multiplier;
var jf_float_push_constants_test : PackedFloat32Array = [
perpen_error_threshold,
sample_step_multiplier,
temp_motion_blur_intensity,
backtracking_velocity_match_threshold,
backtracking_velocity_match_parallel_sensitivity,
backtracking_velcoity_match_perpendicular_sensitivity,
backtracbing_depth_match_threshold,
step_exponent_modifier,
step_size,
max_dilation_radius,
0,
0
]
var jf_byte_array = jf_push_constants.to_byte_array()
jf_byte_array.append_array(jf_float_push_constants_test.to_byte_array())
rd.compute_list_set_push_constant(compute_list, jf_byte_array, jf_byte_array.size())
rd.compute_list_dispatch(compute_list, x_groups, y_groups, 1)
rd.compute_list_end()
rd.draw_command_end_label()
dispatch_stage(blur_stage,
[
get_sampler_uniform(color_image, 0, false),
get_sampler_uniform(depth_image, 1, false),
get_sampler_uniform(custom_velocity_image, 2, false),
get_sampler_uniform(buffer_b_image if last_iteration_index % 2 else buffer_a_image, 3, false),
get_image_uniform(texture_image, 4),
get_image_uniform(debug_1_image, 5),
get_image_uniform(debug_2_image, 6),
get_image_uniform(debug_3_image, 7),
get_image_uniform(debug_4_image, 8),
get_image_uniform(debug_5_image, 9),
get_image_uniform(debug_6_image, 10),
get_image_uniform(debug_7_image, 11),
get_image_uniform(debug_8_image, 12),
],
byte_array,
Vector3i(x_groups, y_groups, 1),
"Compute Blur",
view)
dispatch_stage(overlay_stage,
[
get_sampler_uniform(texture_image, 0),
get_image_uniform(color_image, 1)
],
[],
Vector3i(x_groups, y_groups, 1),
"Overlay Result",
view)
rd.draw_command_end_label()

View File

@ -0,0 +1,8 @@
[gd_resource type="Resource" script_class="ShaderStageResource" load_steps=3 format=3 uid="uid://co5k7plgmxepi"]
[ext_resource type="Script" path="res://addons/SphynxMotionBlurToolkit/BaseClasses/shader_pass_resource.gd" id="1_8et3l"]
[ext_resource type="RDShaderFile" uid="uid://cfk5chwlcyay4" path="res://addons/SphynxMotionBlurToolkit/JumpFlood/ShaderFiles/jf_neighbor_max.glsl" id="2_fub7x"]
[resource]
script = ExtResource("1_8et3l")
shader_file = ExtResource("2_fub7x")

View File

@ -0,0 +1,8 @@
[gd_resource type="Resource" script_class="ShaderStageResource" load_steps=3 format=3 uid="uid://dc5fr84ue3dn5"]
[ext_resource type="Script" path="res://addons/SphynxMotionBlurToolkit/BaseClasses/shader_pass_resource.gd" id="1_6wgo2"]
[ext_resource type="RDShaderFile" uid="uid://dig08kpnfakuf" path="res://addons/SphynxMotionBlurToolkit/JumpFlood/ShaderFiles/jump_flood_overlay.glsl" id="2_ljukb"]
[resource]
script = ExtResource("1_6wgo2")
shader_file = ExtResource("2_ljukb")

View File

@ -0,0 +1,8 @@
[gd_resource type="Resource" script_class="ShaderStageResource" load_steps=3 format=3 uid="uid://c10aboaly701b"]
[ext_resource type="Script" path="res://addons/SphynxMotionBlurToolkit/BaseClasses/shader_pass_resource.gd" id="1_5367c"]
[ext_resource type="RDShaderFile" uid="uid://djp3da364fk2l" path="res://addons/SphynxMotionBlurToolkit/JumpFlood/ShaderFiles/jf_guertin_tile_max_x.glsl" id="2_1b71e"]
[resource]
script = ExtResource("1_5367c")
shader_file = ExtResource("2_1b71e")

View File

@ -0,0 +1,8 @@
[gd_resource type="Resource" script_class="ShaderStageResource" load_steps=3 format=3 uid="uid://cymk87e4nyxva"]
[ext_resource type="Script" path="res://addons/SphynxMotionBlurToolkit/BaseClasses/shader_pass_resource.gd" id="1_5vg08"]
[ext_resource type="RDShaderFile" uid="uid://cqlltc8f21wre" path="res://addons/SphynxMotionBlurToolkit/JumpFlood/ShaderFiles/jf_guertin_tile_max_y.glsl" id="2_iusae"]
[resource]
script = ExtResource("1_5vg08")
shader_file = ExtResource("2_iusae")

View File

@ -0,0 +1,8 @@
[gd_resource type="Resource" script_class="ShaderStageResource" load_steps=3 format=3 uid="uid://bk5yd5plopwi2"]
[ext_resource type="Script" path="res://addons/SphynxMotionBlurToolkit/BaseClasses/shader_pass_resource.gd" id="1_ljx3c"]
[ext_resource type="RDShaderFile" uid="uid://bdm5t4l1y3ts7" path="res://addons/SphynxMotionBlurToolkit/JumpFlood/ShaderFiles/jump_flood_new_blur.glsl" id="2_ase62"]
[resource]
script = ExtResource("1_ljx3c")
shader_file = ExtResource("2_ase62")

View File

@ -0,0 +1,353 @@
extends MotionBlurCompositorEffect
class_name SphynxSimpleJumpFloodMotionBlur
@export_group("Motion Blur", "motion_blur_")
# diminishing returns over 16
@export_range(4, 64) var motion_blur_samples: int = 16
# you really don't want this over 0.5, but you can if you want to try
@export_range(0, 0.5, 0.001, "or_greater") var motion_blur_intensity: float = 1
@export_range(0, 1) var motion_blur_center_fade: float = 0.0
@export var tile_max_x_stage : ShaderStageResource = preload("res://addons/SphynxMotionBlurToolkit/JumpFlood/jump_flood_tile_max_x_stage.tres"):
set(value):
unsubscribe_shader_stage(tile_max_x_stage)
tile_max_x_stage = value
subscirbe_shader_stage(value)
@export var tile_max_y_stage : ShaderStageResource = preload("res://addons/SphynxMotionBlurToolkit/JumpFlood/jump_flood_tile_max_y_stage.tres"):
set(value):
unsubscribe_shader_stage(tile_max_y_stage)
tile_max_y_stage = value
subscirbe_shader_stage(value)
@export var construct_stage : ShaderStageResource = preload("res://addons/SphynxMotionBlurToolkit/JumpFlood/jf_simple_stage.tres"):
set(value):
unsubscribe_shader_stage(construct_stage)
construct_stage = value
subscirbe_shader_stage(value)
@export var neighbor_max_stage : ShaderStageResource = preload("res://addons/SphynxMotionBlurToolkit/JumpFlood/jump_flood_neighbor_max_stage.tres"):
set(value):
unsubscribe_shader_stage(neighbor_max_stage)
neighbor_max_stage = value
subscirbe_shader_stage(value)
@export var blur_stage : ShaderStageResource = preload("res://addons/SphynxMotionBlurToolkit/JumpFlood/simple_jf_blur_stage.tres"):
set(value):
unsubscribe_shader_stage(blur_stage)
blur_stage = value
subscirbe_shader_stage(value)
@export var overlay_stage : ShaderStageResource = preload("res://addons/SphynxMotionBlurToolkit/JumpFlood/jump_flood_overlay_stage.tres"):
set(value):
unsubscribe_shader_stage(overlay_stage)
overlay_stage = value
subscirbe_shader_stage(value)
## the portion of speed that is allowed for side bleed of velocities
## during the jfa dilation passes and before backtracking. Getting this a higher value
## would make it so that meshes at movement blur more reliably, but also bleed
## further perpendicularly to their velocity, thus wash elemets behind them out.
@export var perpen_error_threshold : float = 0.5
## an initial step size that can increase the dilation radius proportionally, at the
## sacrifice of some quality in the final resolution of the dilation.[br][br]
## the formula for the maximum radius of the dilation (in pixels) is: pow(2 + step_exponent_modifier, JFA_pass_count) * sample_step_multiplier
@export var sample_step_multiplier : int = 16
## by default, the jump flood makes samples along distances that start
## at 2 to the power of the pass count you want to perform, which is also
## the dilation radius you desire. You can change it to values higher than
## 2 with this variable, and reach higher dilation radius at the sacrifice of
## some accuracy in the dilation.
## the formula for the maximum radius of the dilation (in pixels) is: pow(2 + step_exponent_modifier, JFA_pass_count) * sample_step_multiplier
@export var step_exponent_modifier : float = 1
## the number of passes performed by the jump flood algorithm based dilation,
## each pass added doubles the maximum radius of dilation available.[br][br]
## the formula for the maximum radius of the dilation (in pixels) is: pow(2 + step_exponent_modifier, JFA_pass_count) * sample_step_multiplier
@export var JFA_pass_count : int = 3
## wether this motion blur stays the same intensity below
## target_constant_framerate
@export var framerate_independent : bool = true
## Description: Removes clamping on motion blur scale to allow framerate independent motion
## blur to scale longer than realistically possible when render framerate is higher
## than target framerate.[br][br]
## [color=yellow]Warning:[/color] Turning this on would allow over-blurring of pixels, which
## produces inaccurate results, and would likely cause nausea in players over
## long exposure durations, use with caution and out of artistic intent
@export var uncapped_independence : bool = false
## if framerate_independent is enabled, the blur would simulate
## sutter speeds at that framerate, and up.
@export var target_constant_framerate : float = 30
var tile_max_x : StringName = "tile_max_x"
var tile_max : StringName = "tile_max"
var neighbor_max : StringName = "neighbor_max"
var output_color : StringName = "output_color"
var buffer_a : StringName = "buffer_a"
var buffer_b : StringName = "buffer_b"
var custom_velocity : StringName = "custom_velocity"
var debug_1 : String = "debug_1"
var debug_2 : String = "debug_2"
var debug_3 : String = "debug_3"
var debug_4 : String = "debug_4"
var debug_5 : String = "debug_5"
var debug_6 : String = "debug_6"
var debug_7 : String = "debug_7"
var debug_8 : String = "debug_8"
var temp_motion_blur_intensity : float
var previous_time : float = 0
func _render_callback_2(render_size : Vector2i, render_scene_buffers : RenderSceneBuffersRD, render_scene_data : RenderSceneDataRD):
var time : float = float(Time.get_ticks_msec()) / 1000
var delta_time : float = time - previous_time
previous_time = time
temp_motion_blur_intensity = motion_blur_intensity
if framerate_independent:
var capped_frame_time : float = 1 / target_constant_framerate
if !uncapped_independence:
capped_frame_time = min(capped_frame_time, delta_time)
temp_motion_blur_intensity = motion_blur_intensity * capped_frame_time / delta_time
ensure_texture(custom_velocity, render_scene_buffers)
ensure_texture(tile_max_x, render_scene_buffers, RenderingDevice.DATA_FORMAT_R16G16B16A16_SFLOAT, Vector2(1. / sample_step_multiplier, 1.))
ensure_texture(tile_max, render_scene_buffers, RenderingDevice.DATA_FORMAT_R16G16B16A16_SFLOAT, Vector2(1. / sample_step_multiplier, 1. / sample_step_multiplier))
ensure_texture(buffer_a, render_scene_buffers, RenderingDevice.DATA_FORMAT_R16G16B16A16_SFLOAT, Vector2(1. / sample_step_multiplier, 1. / sample_step_multiplier))
ensure_texture(buffer_b, render_scene_buffers, RenderingDevice.DATA_FORMAT_R16G16B16A16_SFLOAT, Vector2(1. / sample_step_multiplier, 1. / sample_step_multiplier))
ensure_texture(neighbor_max, render_scene_buffers, RenderingDevice.DATA_FORMAT_R16G16B16A16_SFLOAT, Vector2(1. / sample_step_multiplier, 1. / sample_step_multiplier))
ensure_texture(output_color, render_scene_buffers)
ensure_texture(debug_1, render_scene_buffers)
ensure_texture(debug_2, render_scene_buffers)
ensure_texture(debug_3, render_scene_buffers)
ensure_texture(debug_4, render_scene_buffers)
ensure_texture(debug_5, render_scene_buffers)
ensure_texture(debug_6, render_scene_buffers)
ensure_texture(debug_7, render_scene_buffers)
ensure_texture(debug_8, render_scene_buffers)
rd.draw_command_begin_label("Motion Blur", Color(1.0, 1.0, 1.0, 1.0))
var last_iteration_index : int = JFA_pass_count - 1;
var max_dilation_radius : float = pow(2 + step_exponent_modifier, last_iteration_index) * sample_step_multiplier / motion_blur_intensity;
var tile_max_x_push_constants: PackedFloat32Array = [
0,
0,
0,
0
]
var int_tile_max_x_push_constants : PackedInt32Array = [
sample_step_multiplier,
0,
0,
0
]
var tile_max_x_push_constants_byte_array = tile_max_x_push_constants.to_byte_array()
tile_max_x_push_constants_byte_array.append_array(int_tile_max_x_push_constants.to_byte_array())
var tile_max_y_push_constants: PackedFloat32Array = [
0,
0,
0,
0
]
var int_tile_max_y_push_constants : PackedInt32Array = [
sample_step_multiplier,
0,
0,
0
]
var tile_max_y_push_constants_byte_array = tile_max_y_push_constants.to_byte_array()
tile_max_y_push_constants_byte_array.append_array(int_tile_max_y_push_constants.to_byte_array())
var neighbor_max_push_constants: PackedFloat32Array = [
0,
0,
0,
0
]
var int_neighbor_max_push_constants : PackedInt32Array = [
0,
0,
0,
0
]
var neighbor_max_push_constants_byte_array = neighbor_max_push_constants.to_byte_array()
neighbor_max_push_constants_byte_array.append_array(int_neighbor_max_push_constants.to_byte_array())
var push_constant: PackedFloat32Array = [
motion_blur_samples,
temp_motion_blur_intensity,
motion_blur_center_fade,
Engine.get_frames_drawn() % 8,
last_iteration_index,
sample_step_multiplier,
step_exponent_modifier,
max_dilation_radius,
]
var int_push_constant : PackedInt32Array = [
0,
0,
0,
0
]
var byte_array = push_constant.to_byte_array()
byte_array.append_array(int_push_constant.to_byte_array())
var view_count = render_scene_buffers.get_view_count()
for view in range(view_count):
var color_image := render_scene_buffers.get_color_layer(view)
var depth_image := render_scene_buffers.get_depth_layer(view)
var output_color_image := render_scene_buffers.get_texture_slice(context, output_color, view, 0, 1, 1)
var buffer_a_image := render_scene_buffers.get_texture_slice(context, buffer_a, view, 0, 1, 1)
var buffer_b_image := render_scene_buffers.get_texture_slice(context, buffer_b, view, 0, 1, 1)
var custom_velocity_image := render_scene_buffers.get_texture_slice(context, custom_velocity, view, 0, 1, 1)
var tile_max_x_image := render_scene_buffers.get_texture_slice(context, tile_max_x, view, 0, 1, 1)
var tile_max_image := render_scene_buffers.get_texture_slice(context, tile_max, view, 0, 1, 1)
var neighbor_max_image := render_scene_buffers.get_texture_slice(context, neighbor_max, view, 0, 1, 1)
var debug_1_image := render_scene_buffers.get_texture_slice(context, debug_1, view, 0, 1, 1)
var debug_2_image := render_scene_buffers.get_texture_slice(context, debug_2, view, 0, 1, 1)
var debug_3_image := render_scene_buffers.get_texture_slice(context, debug_3, view, 0, 1, 1)
var debug_4_image := render_scene_buffers.get_texture_slice(context, debug_4, view, 0, 1, 1)
var debug_5_image := render_scene_buffers.get_texture_slice(context, debug_5, view, 0, 1, 1)
var debug_6_image := render_scene_buffers.get_texture_slice(context, debug_6, view, 0, 1, 1)
var debug_7_image := render_scene_buffers.get_texture_slice(context, debug_7, view, 0, 1, 1)
var debug_8_image := render_scene_buffers.get_texture_slice(context, debug_8, view, 0, 1, 1)
var x_groups := floori((render_size.x / sample_step_multiplier - 1) / 16 + 1)
var y_groups := floori((render_size.y - 1) / 16 + 1)
dispatch_stage(tile_max_x_stage,
[
get_sampler_uniform(custom_velocity_image, 0, false),
get_sampler_uniform(depth_image, 1, false),
get_image_uniform(tile_max_x_image, 2)
],
tile_max_x_push_constants_byte_array,
Vector3i(x_groups, y_groups, 1),
"TileMaxX",
view)
x_groups = floori((render_size.x / sample_step_multiplier - 1) / 16 + 1)
y_groups = floori((render_size.y / sample_step_multiplier - 1) / 16 + 1)
dispatch_stage(tile_max_y_stage,
[
get_sampler_uniform(tile_max_x_image, 0, false),
get_image_uniform(tile_max_image, 1)
],
tile_max_y_push_constants_byte_array,
Vector3i(x_groups, y_groups, 1),
"TileMaxY",
view)
for i in JFA_pass_count:
var jf_push_constants : PackedInt32Array = [
i,
last_iteration_index,
0,
16
]
var step_size : float = round(pow(2 + step_exponent_modifier, last_iteration_index - i));
var jf_float_push_constants_test : PackedFloat32Array = [
perpen_error_threshold,
sample_step_multiplier,
temp_motion_blur_intensity,
0,
0,
0,
0,
step_exponent_modifier,
step_size,
max_dilation_radius,
0,
0
]
var jf_byte_array = jf_push_constants.to_byte_array()
jf_byte_array.append_array(jf_float_push_constants_test.to_byte_array())
dispatch_stage(construct_stage,
[
get_sampler_uniform(tile_max_image, 0, false),
get_image_uniform(buffer_a_image, 1),
get_image_uniform(buffer_b_image, 2),
get_sampler_uniform(buffer_a_image, 3, false),
get_sampler_uniform(buffer_b_image, 4, false)
],
jf_byte_array,
Vector3i(x_groups, y_groups, 1),
"Construct Blur",
view)
rd.draw_command_end_label()
dispatch_stage(neighbor_max_stage,
[
get_sampler_uniform(tile_max_image, 0, false),
get_sampler_uniform(buffer_b_image if last_iteration_index % 2 else buffer_a_image, 1, false),
get_image_uniform(neighbor_max_image, 2)
],
neighbor_max_push_constants_byte_array,
Vector3i(x_groups, y_groups, 1),
"NeighborMax",
view)
x_groups = floori((render_size.x - 1) / 16 + 1)
y_groups = floori((render_size.y - 1) / 16 + 1)
dispatch_stage(blur_stage,
[
get_sampler_uniform(color_image, 0, false),
get_sampler_uniform(depth_image, 1, false),
get_sampler_uniform(custom_velocity_image, 2, false),
get_sampler_uniform(neighbor_max_image, 3, false),
get_image_uniform(output_color_image, 4),
get_image_uniform(debug_1_image, 5),
get_image_uniform(debug_2_image, 6),
get_image_uniform(debug_3_image, 7),
get_image_uniform(debug_4_image, 8),
get_image_uniform(debug_5_image, 9),
get_image_uniform(debug_6_image, 10),
get_image_uniform(debug_7_image, 11),
get_image_uniform(debug_8_image, 12),
get_sampler_uniform(tile_max_image, 13, false)
],
byte_array,
Vector3i(x_groups, y_groups, 1),
"Compute Blur",
view)
dispatch_stage(overlay_stage,
[
get_sampler_uniform(output_color_image, 0),
get_image_uniform(color_image, 1)
],
[],
Vector3i(x_groups, y_groups, 1),
"Overlay Result",
view)
rd.draw_command_end_label()

View File

@ -0,0 +1,137 @@
#[compute]
#version 450
#define FLT_MAX 3.402823466e+38
#define FLT_MIN 1.175494351e-38
layout(set = 0, binding = 0) uniform sampler2D color_sampler;
layout(set = 0, binding = 1) uniform sampler2D depth_sampler;
layout(set = 0, binding = 2) uniform sampler2D velocity_sampler;
layout(set = 0, binding = 3) uniform sampler2D neighbor_max;
layout(set = 0, binding = 4) uniform sampler2D tile_variance;
layout(rgba16f, set = 0, binding = 5) uniform writeonly image2D output_color;
layout(rgba16f, set = 0, binding = 6) uniform image2D past_color_image;
layout(push_constant, std430) uniform Params
{
float minimum_user_threshold;
float importance_bias;
float maximum_jitter_value;
float nan8;
int tile_size;
int sample_count;
int frame;
int nan4;
} params;
layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
// McGuire's functions https://docs.google.com/document/d/1IIlAKTj-O01hcXEdGxTErQbCHO9iBmRx6oFUy_Jm0fI/edit
// ----------------------------------------------------------
float soft_depth_compare(float depth_X, float depth_Y, float sze)
{
return clamp(1 - (depth_X - depth_Y) / sze, 0, 1);
}
float cone(float T, float v)
{
return clamp(1 - abs(T) / v, 0, 1);
}
float cylinder(float T, float v)
{
return 1.0 - smoothstep(0.95 * v, 1.05 * v, abs(T));
}
// ----------------------------------------------------------
// Guertin's functions https://research.nvidia.com/sites/default/files/pubs/2013-11_A-Fast-and/Guertin2013MotionBlur-small.pdf
// ----------------------------------------------------------
float z_compare(float a, float b, float multiplier)
{
return clamp(1. + (a - b) * multiplier, 0, 1);
}
// ----------------------------------------------------------
// from https://www.shadertoy.com/view/ftKfzc
// ----------------------------------------------------------
float interleaved_gradient_noise(vec2 uv, int FrameId){
uv += float(FrameId) * (vec2(47, 17) * 0.695);
vec3 magic = vec3( 0.06711056, 0.00583715, 52.9829189 );
return fract(magic.z * fract(dot(uv, magic.xy)));
}
// ----------------------------------------------------------
vec2 sample_random_offset(vec2 uv, float j)
{
return vec2(0);
}
void main()
{
ivec2 render_size = ivec2(textureSize(color_sampler, 0));
ivec2 tile_render_size = ivec2(textureSize(neighbor_max, 0));
ivec2 uvi = ivec2(gl_GlobalInvocationID.xy);
if ((uvi.x >= render_size.x) || (uvi.y >= render_size.y))
{
return;
}
vec2 x = (vec2(uvi) + vec2(0.5)) / vec2(render_size);
vec2 vn = textureLod(neighbor_max, x, 0.0).xy * render_size / 2;
float vn_length = max(0.5, length(vn));
vec4 base_color = textureLod(color_sampler, x, 0.0);
if(vn_length <= 0.5)
{
imageStore(output_color, uvi, base_color);
return;
}
vec2 vx = textureLod(velocity_sampler, x, 0.0).xy * render_size / 2;
float zx = -0.05 / textureLod(depth_sampler, x, 0.0).x;
float vx_length = max(0.5, length(vx));
float weight = 1. / vx_length;
vec4 sum = base_color * weight;
float j = interleaved_gradient_noise(uvi, params.frame) - 0.5;
for(int i = 0; i < params.sample_count; i++)
{
if(i == (params.sample_count - 1) / 2)
{
continue;
}
float t = mix(-1, 1, (i + j + 1.0) / (params.sample_count + 1.0));
float T = t * vn_length;
vec2 y = x + (vn / render_size) * t;
vec2 vy = textureLod(velocity_sampler, y, 0.0).xy * render_size / 2;
float vy_length = max(0.5, length(vy));
float zy = -0.05 / textureLod(depth_sampler, y, 0.0).x;
float f = soft_depth_compare(zx, zy, 0.01);
float b = soft_depth_compare(zy, zx, 0.01);
float ay = f * cone(T, vy_length) + b * cone(T, vx_length) + cylinder(T, vy_length) * cylinder(T, vx_length) * 2;
weight += ay;
sum += ay * textureLod(color_sampler, y, 0.0);
}
sum /= weight;
imageStore(output_color, uvi, sum);
}

View File

@ -0,0 +1,14 @@
[remap]
importer="glsl"
type="RDShaderFile"
uid="uid://7fjex8wuiejk"
path="res://.godot/imported/mcguire_blur.glsl-0cc0e90626b85e4aae8d4b21c9368b86.res"
[deps]
source_file="res://addons/SphynxMotionBlurToolkit/McGuire/ShaderFiles/mcguire_blur.glsl"
dest_files=["res://.godot/imported/mcguire_blur.glsl-0cc0e90626b85e4aae8d4b21c9368b86.res"]
[params]

View File

@ -0,0 +1,72 @@
#[compute]
#version 450
#define FLT_MAX 3.402823466e+38
#define FLT_MIN 1.175494351e-38
layout(set = 0, binding = 0) uniform sampler2D tile_max;
layout(rgba16f, set = 0, binding = 1) uniform writeonly image2D neighbor_max;
layout(push_constant, std430) uniform Params
{
float nan5;
float nan6;
float nan7;
float nan8;
int nan1;
int nan2;
int nan3;
int nan4;
} params;
layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
void main()
{
ivec2 render_size = ivec2(textureSize(tile_max, 0));
ivec2 uvi = ivec2(gl_GlobalInvocationID.xy);
if ((uvi.x >= render_size.x) || (uvi.y >= render_size.y))
{
return;
}
vec2 uvn = (vec2(uvi) + vec2(0.5)) / render_size;
vec2 max_neighbor_velocity = vec2(0);
float max_neighbor_velocity_length = 0;
for(int i = -1; i < 2; i++)
{
for(int j = -1; j < 2; j++)
{
vec2 current_offset = vec2(1) / vec2(render_size) * vec2(i, j);
vec2 current_uv = uvn + current_offset;
if(current_uv.x < 0 || current_uv.x > 1 || current_uv.y < 0 || current_uv.y > 1)
{
continue;
}
bool is_diagonal = (abs(i) + abs(j) == 2);
vec2 current_neighbor_velocity = textureLod(tile_max, current_uv, 0.0).xy;
bool facing_center = dot(current_neighbor_velocity, current_offset) > 0;
if(is_diagonal && !facing_center)
{
continue;
}
float current_neighbor_velocity_length = dot(current_neighbor_velocity, current_neighbor_velocity);
if(current_neighbor_velocity_length > max_neighbor_velocity_length)
{
max_neighbor_velocity_length = current_neighbor_velocity_length;
max_neighbor_velocity = current_neighbor_velocity;
}
}
}
imageStore(neighbor_max, uvi, vec4(max_neighbor_velocity, 0, 1));
}

View File

@ -0,0 +1,14 @@
[remap]
importer="glsl"
type="RDShaderFile"
uid="uid://byfogr1qtbafi"
path="res://.godot/imported/mcguire_neighbor_max.glsl-aa40cc8d534a08ad7aaf84bf0615cc3a.res"
[deps]
source_file="res://addons/SphynxMotionBlurToolkit/McGuire/ShaderFiles/mcguire_neighbor_max.glsl"
dest_files=["res://.godot/imported/mcguire_neighbor_max.glsl-aa40cc8d534a08ad7aaf84bf0615cc3a.res"]
[params]

View File

@ -0,0 +1,18 @@
#[compute]
#version 450
layout(set = 0, binding = 0) uniform sampler2D blur_sampler;
layout(rgba16f, set = 0, binding = 1) uniform image2D color_image;
layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
void main()
{
ivec2 render_size = ivec2(textureSize(blur_sampler, 0));
ivec2 output_size = imageSize(color_image);
ivec2 uv = ivec2(gl_GlobalInvocationID.xy);
if ((uv.x >= output_size.x) || (uv.y >= output_size.y))
{
return;
}
imageStore(color_image, uv, textureLod(blur_sampler, (vec2(uv) + 0.5) / output_size, 0.0));
}

View File

@ -0,0 +1,14 @@
[remap]
importer="glsl"
type="RDShaderFile"
uid="uid://ylkrbqh7unvl"
path="res://.godot/imported/mcguire_overlay.glsl-a331e470c95eacb608a05976de7b2202.res"
[deps]
source_file="res://addons/SphynxMotionBlurToolkit/McGuire/ShaderFiles/mcguire_overlay.glsl"
dest_files=["res://.godot/imported/mcguire_overlay.glsl-a331e470c95eacb608a05976de7b2202.res"]
[params]

View File

@ -0,0 +1,54 @@
#[compute]
#version 450
#define FLT_MAX 3.402823466e+38
#define FLT_MIN 1.175494351e-38
layout(set = 0, binding = 0) uniform sampler2D velocity_sampler;
layout(rgba16f, set = 0, binding = 1) uniform writeonly image2D tile_max_x;
layout(push_constant, std430) uniform Params
{
float nan5;
float nan6;
float nan7;
float nan8;
int tile_size;
int nan2;
int nan3;
int nan4;
} params;
layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
void main()
{
ivec2 render_size = ivec2(textureSize(velocity_sampler, 0));
ivec2 output_size = imageSize(tile_max_x);
ivec2 uvi = ivec2(gl_GlobalInvocationID.xy);
ivec2 global_uvi = uvi * ivec2(params.tile_size, 1);
if ((uvi.x >= output_size.x) || (uvi.y >= output_size.y))
{
return;
}
vec2 uvn = (vec2(global_uvi) + vec2(0.5)) / render_size;
vec2 max_velocity = vec2(0);
float max_velocity_length = 0;
for(int i = 0; i < params.tile_size; i++)
{
vec2 current_uv = uvn + vec2(float(i) / render_size.x, 0);
vec2 velocity_sample = textureLod(velocity_sampler, current_uv, 0.0).xy;
float current_velocity_length = dot(velocity_sample, velocity_sample);
if(current_velocity_length > max_velocity_length)
{
max_velocity_length = current_velocity_length;
max_velocity = velocity_sample;
}
}
imageStore(tile_max_x, uvi, vec4(max_velocity, 0, 1));
}

View File

@ -0,0 +1,14 @@
[remap]
importer="glsl"
type="RDShaderFile"
uid="uid://bp5jl5351ph2d"
path="res://.godot/imported/mcguire_tile_max_x.glsl-9c459b3d537ec225893d39ee91be1c1e.res"
[deps]
source_file="res://addons/SphynxMotionBlurToolkit/McGuire/ShaderFiles/mcguire_tile_max_x.glsl"
dest_files=["res://.godot/imported/mcguire_tile_max_x.glsl-9c459b3d537ec225893d39ee91be1c1e.res"]
[params]

View File

@ -0,0 +1,54 @@
#[compute]
#version 450
#define FLT_MAX 3.402823466e+38
#define FLT_MIN 1.175494351e-38
layout(set = 0, binding = 0) uniform sampler2D tile_max_x;
layout(rgba16f, set = 0, binding = 1) uniform writeonly image2D tile_max;
layout(push_constant, std430) uniform Params
{
float nan5;
float nan6;
float nan7;
float nan8;
int tile_size;
int nan2;
int nan3;
int nan4;
} params;
layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
void main()
{
ivec2 render_size = ivec2(textureSize(tile_max_x, 0));
ivec2 output_size = imageSize(tile_max);
ivec2 uvi = ivec2(gl_GlobalInvocationID.xy);
ivec2 global_uvi = uvi * ivec2(1, params.tile_size);
if ((uvi.x >= output_size.x) || (uvi.y >= output_size.y))
{
return;
}
vec2 uvn = (vec2(global_uvi) + vec2(0.5)) / render_size;
vec2 max_velocity = vec2(0);
float max_velocity_length = 0;
for(int i = 0; i < params.tile_size; i++)
{
vec2 current_uv = uvn + vec2(0, float(i) / render_size.y);
vec2 velocity_sample = textureLod(tile_max_x, current_uv, 0.0).xy;
float current_velocity_length = dot(velocity_sample, velocity_sample);
if(current_velocity_length > max_velocity_length)
{
max_velocity_length = current_velocity_length;
max_velocity = velocity_sample;
}
}
imageStore(tile_max, uvi, vec4(max_velocity, 0, 1));
}

View File

@ -0,0 +1,14 @@
[remap]
importer="glsl"
type="RDShaderFile"
uid="uid://deow8m5u2ji84"
path="res://.godot/imported/mcguire_tile_max_y.glsl-d6c42f715f0dbdbc13190532231a64e9.res"
[deps]
source_file="res://addons/SphynxMotionBlurToolkit/McGuire/ShaderFiles/mcguire_tile_max_y.glsl"
dest_files=["res://.godot/imported/mcguire_tile_max_y.glsl-d6c42f715f0dbdbc13190532231a64e9.res"]
[params]

View File

@ -0,0 +1,68 @@
#[compute]
#version 450
#define FLT_MAX 3.402823466e+38
#define FLT_MIN 1.175494351e-38
layout(set = 0, binding = 0) uniform sampler2D tile_max;
layout(rgba16f, set = 0, binding = 1) uniform writeonly image2D tile_variance;
layout(push_constant, std430) uniform Params
{
float nan5;
float nan6;
float nan7;
float nan8;
int nan1;
int nan2;
int nan3;
int nan4;
} params;
layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
void main()
{
ivec2 render_size = ivec2(textureSize(tile_max, 0));
ivec2 uvi = ivec2(gl_GlobalInvocationID.xy);
if ((uvi.x >= render_size.x) || (uvi.y >= render_size.y))
{
return;
}
vec2 uvn = (vec2(uvi) + vec2(0.5)) / render_size;
float variance = 0;
vec2 current_velocity = abs(normalize(textureLod(tile_max, uvn, 0.0).xy));
float tile_count = 0;
for(int i = -1; i < 2; i++)
{
for(int j = -1; j < 2; j++)
{
vec2 current_offset = vec2(1) / vec2(render_size) * vec2(i, j);
vec2 current_uv = uvn + current_offset;
if(current_uv.x < 0 || current_uv.x > 1 || current_uv.y < 0 || current_uv.y > 1)
{
continue;
}
if(i == j && i == 0)
{
continue;
}
tile_count += 1;
vec2 current_neighbor_velocity = abs(normalize(textureLod(tile_max, current_uv, 0.0).xy));
variance += dot(current_velocity, current_neighbor_velocity);
}
}
variance /= tile_count;
imageStore(tile_variance, uvi, vec4(1 - variance));
}

View File

@ -0,0 +1,14 @@
[remap]
importer="glsl"
type="RDShaderFile"
uid="uid://ddo60n85uqwbk"
path="res://.godot/imported/mcguire_tile_variance.glsl-2a5a77e5f43c4a3d379a9c7c55e12bf6.res"
[deps]
source_file="res://addons/SphynxMotionBlurToolkit/McGuire/ShaderFiles/mcguire_tile_variance.glsl"
dest_files=["res://.godot/imported/mcguire_tile_variance.glsl-2a5a77e5f43c4a3d379a9c7c55e12bf6.res"]
[params]

View File

@ -0,0 +1,8 @@
[gd_resource type="Resource" script_class="ShaderStageResource" load_steps=3 format=3 uid="uid://cp5pmuoa15e5g"]
[ext_resource type="Script" path="res://addons/SphynxMotionBlurToolkit/BaseClasses/shader_pass_resource.gd" id="1_16plp"]
[ext_resource type="RDShaderFile" uid="uid://7fjex8wuiejk" path="res://addons/SphynxMotionBlurToolkit/McGuire/ShaderFiles/mcguire_blur.glsl" id="2_nk2ao"]
[resource]
script = ExtResource("1_16plp")
shader_file = ExtResource("2_nk2ao")

View File

@ -0,0 +1,249 @@
extends MotionBlurCompositorEffect
class_name McGuireMotionBlur
@export_group("Motion Blur", "motion_blur_")
# diminishing returns over 16
@export_range(4, 64) var motion_blur_samples: int = 25
# you really don't want this over 0.5, but you can if you want to try
@export_range(0, 0.5, 0.001, "or_greater") var motion_blur_intensity: float = 1
@export_range(0, 1) var motion_blur_center_fade: float = 0.0
@export var blur_stage : ShaderStageResource = preload("res://addons/SphynxMotionBlurToolkit/McGuire/mcguire_blur_stage.tres"):
set(value):
unsubscribe_shader_stage(blur_stage)
blur_stage = value
subscirbe_shader_stage(value)
@export var overlay_stage : ShaderStageResource = preload("res://addons/SphynxMotionBlurToolkit/McGuire/mcguire_overlay_stage.tres"):
set(value):
unsubscribe_shader_stage(overlay_stage)
overlay_stage = value
subscirbe_shader_stage(value)
@export var tile_max_x_stage : ShaderStageResource = preload("res://addons/SphynxMotionBlurToolkit/McGuire/mcguire_tile_max_x_stage.tres"):
set(value):
unsubscribe_shader_stage(tile_max_x_stage)
tile_max_x_stage = value
subscirbe_shader_stage(value)
@export var tile_max_y_stage : ShaderStageResource = preload("res://addons/SphynxMotionBlurToolkit/McGuire/mcguire_tile_max_y_stage.tres"):
set(value):
unsubscribe_shader_stage(tile_max_y_stage)
tile_max_y_stage = value
subscirbe_shader_stage(value)
@export var neighbor_max_stage : ShaderStageResource = preload("res://addons/SphynxMotionBlurToolkit/McGuire/mcguire_neighbor_max_stage.tres"):
set(value):
unsubscribe_shader_stage(neighbor_max_stage)
neighbor_max_stage = value
subscirbe_shader_stage(value)
@export var tile_variance_stage : ShaderStageResource = preload("res://addons/SphynxMotionBlurToolkit/McGuire/mcguire_tile_variance_stage.tres"):
set(value):
unsubscribe_shader_stage(tile_variance_stage)
tile_variance_stage = value
subscirbe_shader_stage(value)
@export var tile_size : int = 40
@export var linear_falloff_slope : float = 1
@export var importance_bias : float = 40
@export var maximum_jitter_value : float = 0.95
@export var minimum_user_threshold : float = 1.5
var output_color: StringName = "output_color"
var tile_max_x : StringName = "tile_max_x"
var tile_max : StringName = "tile_max"
var neighbor_max : StringName = "neighbor_max"
var tile_variance : StringName = "tile_variance"
var past_color : StringName = "past_color"
var custom_velocity : StringName = "custom_velocity"
var freeze : bool = false
func _get_max_dilation_range() -> float:
return tile_size;
func _render_callback_2(render_size : Vector2i, render_scene_buffers : RenderSceneBuffersRD, render_scene_data : RenderSceneDataRD):
ensure_texture(tile_max_x, render_scene_buffers, RenderingDevice.DATA_FORMAT_R16G16B16A16_SFLOAT, Vector2(1. / tile_size, 1.))
ensure_texture(tile_max, render_scene_buffers, RenderingDevice.DATA_FORMAT_R16G16B16A16_SFLOAT, Vector2(1. / tile_size, 1. / tile_size))
ensure_texture(neighbor_max, render_scene_buffers, RenderingDevice.DATA_FORMAT_R16G16B16A16_SFLOAT, Vector2(1. / tile_size, 1. / tile_size))
ensure_texture(tile_variance, render_scene_buffers, RenderingDevice.DATA_FORMAT_R16G16B16A16_SFLOAT, Vector2(1. / tile_size, 1. / tile_size))
ensure_texture(past_color, render_scene_buffers)
ensure_texture(custom_velocity, render_scene_buffers)
ensure_texture(output_color, render_scene_buffers)
rd.draw_command_begin_label("Motion Blur", Color(1.0, 1.0, 1.0, 1.0))
var tile_max_x_push_constants: PackedFloat32Array = [
0,
0,
0,
0
]
var int_tile_max_x_push_constants : PackedInt32Array = [
tile_size,
0,
0,
0
]
var tile_max_x_push_constants_byte_array = tile_max_x_push_constants.to_byte_array()
tile_max_x_push_constants_byte_array.append_array(int_tile_max_x_push_constants.to_byte_array())
var tile_max_y_push_constants: PackedFloat32Array = [
0,
0,
0,
0
]
var int_tile_max_y_push_constants : PackedInt32Array = [
tile_size,
0,
0,
0
]
var tile_max_y_push_constants_byte_array = tile_max_y_push_constants.to_byte_array()
tile_max_y_push_constants_byte_array.append_array(int_tile_max_y_push_constants.to_byte_array())
var neighbor_max_push_constants: PackedFloat32Array = [
0,
0,
0,
0
]
var int_neighbor_max_push_constants : PackedInt32Array = [
0,
0,
0,
0
]
var neighbor_max_push_constants_byte_array = neighbor_max_push_constants.to_byte_array()
neighbor_max_push_constants_byte_array.append_array(int_neighbor_max_push_constants.to_byte_array())
var tile_variance_push_constants: PackedFloat32Array = [
0,
0,
0,
0
]
var int_tile_variance_push_constants : PackedInt32Array = [
0,
0,
0,
0
]
var tile_variance_push_constants_byte_array = tile_variance_push_constants.to_byte_array()
tile_variance_push_constants_byte_array.append_array(int_tile_variance_push_constants.to_byte_array())
var blur_push_constants: PackedFloat32Array = [
minimum_user_threshold,
importance_bias,
maximum_jitter_value,
0,
]
var int_blur_push_constants : PackedInt32Array = [
tile_size,
motion_blur_samples,
Engine.get_frames_drawn() % 8,
0
]
var blur_push_constants_byte_array = blur_push_constants.to_byte_array()
blur_push_constants_byte_array.append_array(int_blur_push_constants.to_byte_array())
var view_count = render_scene_buffers.get_view_count()
for view in range(view_count):
var color_image := render_scene_buffers.get_color_layer(view)
var depth_image := render_scene_buffers.get_depth_layer(view)
var output_color_image := render_scene_buffers.get_texture_slice(context, output_color, view, 0, 1, 1)
var tile_max_x_image := render_scene_buffers.get_texture_slice(context, tile_max_x, view, 0, 1, 1)
var tile_max_image := render_scene_buffers.get_texture_slice(context, tile_max, view, 0, 1, 1)
var neighbor_max_image := render_scene_buffers.get_texture_slice(context, neighbor_max, view, 0, 1, 1)
var tile_variance_image := render_scene_buffers.get_texture_slice(context, tile_variance, view, 0, 1, 1)
var past_color_image := render_scene_buffers.get_texture_slice(context, past_color, view, 0, 1, 1)
var custom_velocity_image := render_scene_buffers.get_texture_slice(context, custom_velocity, view, 0, 1, 1)
var x_groups := floori((render_size.x / tile_size - 1) / 16 + 1)
var y_groups := floori((render_size.y - 1) / 16 + 1)
dispatch_stage(tile_max_x_stage,
[
get_sampler_uniform(custom_velocity_image, 0, false),
get_image_uniform(tile_max_x_image, 1)
],
tile_max_x_push_constants_byte_array,
Vector3i(x_groups, y_groups, 1),
"TileMaxX",
view)
x_groups = floori((render_size.x / tile_size - 1) / 16 + 1)
y_groups = floori((render_size.y / tile_size - 1) / 16 + 1)
dispatch_stage(tile_max_y_stage,
[
get_sampler_uniform(tile_max_x_image, 0, false),
get_image_uniform(tile_max_image, 1)
],
tile_max_y_push_constants_byte_array,
Vector3i(x_groups, y_groups, 1),
"TileMaxY",
view)
dispatch_stage(neighbor_max_stage,
[
get_sampler_uniform(tile_max_image, 0, false),
get_image_uniform(neighbor_max_image, 1)
],
neighbor_max_push_constants_byte_array,
Vector3i(x_groups, y_groups, 1),
"NeighborMax",
view)
dispatch_stage(tile_variance_stage,
[
get_sampler_uniform(tile_max_image, 0, false),
get_image_uniform(tile_variance_image, 1)
],
tile_variance_push_constants_byte_array,
Vector3i(x_groups, y_groups, 1),
"TileVariance",
view)
x_groups = floori((render_size.x - 1) / 16 + 1)
y_groups = floori((render_size.y - 1) / 16 + 1)
dispatch_stage(blur_stage,
[
get_sampler_uniform(color_image, 0, false),
get_sampler_uniform(depth_image, 1, false),
get_sampler_uniform(custom_velocity_image, 2, false),
get_sampler_uniform(neighbor_max_image, 3, false),
get_sampler_uniform(tile_variance_image, 4, true),
get_image_uniform(output_color_image, 5),
get_image_uniform(past_color_image, 6)
],
blur_push_constants_byte_array,
Vector3i(x_groups, y_groups, 1),
"Blur",
view)
dispatch_stage(overlay_stage,
[
get_sampler_uniform(output_color_image, 0, false),
get_image_uniform(color_image, 1)
],
[],
Vector3i(x_groups, y_groups, 1),
"Overlay result",
view)
rd.draw_command_end_label()

View File

@ -0,0 +1,8 @@
[gd_resource type="Resource" script_class="ShaderStageResource" load_steps=3 format=3 uid="uid://bk8tn7n5k0b1r"]
[ext_resource type="Script" path="res://addons/SphynxMotionBlurToolkit/BaseClasses/shader_pass_resource.gd" id="1_6n3p7"]
[ext_resource type="RDShaderFile" uid="uid://byfogr1qtbafi" path="res://addons/SphynxMotionBlurToolkit/McGuire/ShaderFiles/mcguire_neighbor_max.glsl" id="2_ig0yf"]
[resource]
script = ExtResource("1_6n3p7")
shader_file = ExtResource("2_ig0yf")

View File

@ -0,0 +1,8 @@
[gd_resource type="Resource" script_class="ShaderStageResource" load_steps=3 format=3 uid="uid://chg1vh0sap86j"]
[ext_resource type="Script" path="res://addons/SphynxMotionBlurToolkit/BaseClasses/shader_pass_resource.gd" id="1_rpgp3"]
[ext_resource type="RDShaderFile" uid="uid://ylkrbqh7unvl" path="res://addons/SphynxMotionBlurToolkit/McGuire/ShaderFiles/mcguire_overlay.glsl" id="2_sx8p0"]
[resource]
script = ExtResource("1_rpgp3")
shader_file = ExtResource("2_sx8p0")

View File

@ -0,0 +1,8 @@
[gd_resource type="Resource" script_class="ShaderStageResource" load_steps=3 format=3 uid="uid://kgrk5sdoor7t"]
[ext_resource type="Script" path="res://addons/SphynxMotionBlurToolkit/BaseClasses/shader_pass_resource.gd" id="1_50cqr"]
[ext_resource type="RDShaderFile" uid="uid://bp5jl5351ph2d" path="res://addons/SphynxMotionBlurToolkit/McGuire/ShaderFiles/mcguire_tile_max_x.glsl" id="2_m4c7y"]
[resource]
script = ExtResource("1_50cqr")
shader_file = ExtResource("2_m4c7y")

View File

@ -0,0 +1,8 @@
[gd_resource type="Resource" script_class="ShaderStageResource" load_steps=3 format=3 uid="uid://d2rdmkpi41wf1"]
[ext_resource type="Script" path="res://addons/SphynxMotionBlurToolkit/BaseClasses/shader_pass_resource.gd" id="1_4imrj"]
[ext_resource type="RDShaderFile" uid="uid://deow8m5u2ji84" path="res://addons/SphynxMotionBlurToolkit/McGuire/ShaderFiles/mcguire_tile_max_y.glsl" id="2_8ewid"]
[resource]
script = ExtResource("1_4imrj")
shader_file = ExtResource("2_8ewid")

View File

@ -0,0 +1,8 @@
[gd_resource type="Resource" script_class="ShaderStageResource" load_steps=3 format=3 uid="uid://d1ckx52l74p0"]
[ext_resource type="Script" path="res://addons/SphynxMotionBlurToolkit/BaseClasses/shader_pass_resource.gd" id="1_bipj1"]
[ext_resource type="RDShaderFile" uid="uid://ddo60n85uqwbk" path="res://addons/SphynxMotionBlurToolkit/McGuire/ShaderFiles/mcguire_tile_variance.glsl" id="2_5lusy"]
[resource]
script = ExtResource("1_bipj1")
shader_file = ExtResource("2_5lusy")

View File

@ -1,6 +1,6 @@
[gd_resource type="Resource" script_class="BlurVelocityComponentResource" load_steps=2 format=3 uid="uid://rp3mpjmisoyh"]
[ext_resource type="Script" path="res://addons/PreBlurProcessing/blur_velocity_component_resource.gd" id="1_ijikr"]
[ext_resource type="Script" path="res://addons/SphynxMotionBlurToolkit/PreBlurProcessing/blur_velocity_component_resource.gd" id="1_ijikr"]
[resource]
script = ExtResource("1_ijikr")

View File

@ -0,0 +1,8 @@
[gd_resource type="Resource" script_class="ShaderStageResource" load_steps=3 format=3 uid="uid://c8ulad7utgrg7"]
[ext_resource type="Script" path="res://addons/SphynxMotionBlurToolkit/BaseClasses/shader_pass_resource.gd" id="1_8hijg"]
[ext_resource type="RDShaderFile" uid="uid://ojudxyx6f4rx" path="res://addons/SphynxMotionBlurToolkit/PreBlurProcessing/pre_blur_processor.glsl" id="2_w54vd"]
[resource]
script = ExtResource("1_8hijg")
shader_file = ExtResource("2_w54vd")

View File

@ -0,0 +1,75 @@
extends EnhancedCompositorEffect
class_name PreBlurProcessor
@export var pre_blur_processor_stage : ShaderStageResource = preload("res://addons/SphynxMotionBlurToolkit/PreBlurProcessing/pre_blur_processing_stage.tres"):
set(value):
unsubscribe_shader_stage(pre_blur_processor_stage)
pre_blur_processor_stage = value
subscirbe_shader_stage(value)
@export var camera_rotation_component : BlurVelocityComponentResource = preload("res://addons/SphynxMotionBlurToolkit/PreBlurProcessing/default_component.tres")
@export var camera_movement_component : BlurVelocityComponentResource = preload("res://addons/SphynxMotionBlurToolkit/PreBlurProcessing/default_component.tres")
@export var object_movement_component : BlurVelocityComponentResource = preload("res://addons/SphynxMotionBlurToolkit/PreBlurProcessing/default_component.tres")
var custom_velocity : StringName = "custom_velocity"
func _init():
needs_motion_vectors = true
set_deferred("context", "MotionBlur")
super()
func _render_callback_2(render_size : Vector2i, render_scene_buffers : RenderSceneBuffersRD, render_scene_data : RenderSceneDataRD):
ensure_texture(custom_velocity, render_scene_buffers)
rd.draw_command_begin_label("Pre Blur Processing", Color(1.0, 1.0, 1.0, 1.0))
var float_pre_blur_push_constants: PackedFloat32Array = [
camera_rotation_component.multiplier,
camera_movement_component.multiplier,
object_movement_component.multiplier,
camera_rotation_component.lower_threshold,
camera_movement_component.lower_threshold,
object_movement_component.lower_threshold,
camera_rotation_component.upper_threshold,
camera_movement_component.upper_threshold,
object_movement_component.upper_threshold,
1 if true else 0,
0,
0,
]
var int_pre_blur_push_constants : PackedInt32Array = [
]
var byte_array = float_pre_blur_push_constants.to_byte_array()
byte_array.append_array(int_pre_blur_push_constants.to_byte_array())
var view_count = render_scene_buffers.get_view_count()
for view in range(view_count):
var depth_image := render_scene_buffers.get_depth_layer(view)
var velocity_image := render_scene_buffers.get_velocity_layer(view)
var custom_velocity_image := render_scene_buffers.get_texture_slice(context, custom_velocity, view, 0, 1, 1)
var scene_data_buffer : RID = render_scene_data.get_uniform_buffer()
var scene_data_buffer_uniform := RDUniform.new()
scene_data_buffer_uniform.uniform_type = RenderingDevice.UNIFORM_TYPE_UNIFORM_BUFFER
scene_data_buffer_uniform.binding = 5
scene_data_buffer_uniform.add_id(scene_data_buffer)
var x_groups := floori((render_size.x - 1) / 16 + 1)
var y_groups := floori((render_size.y - 1) / 16 + 1)
dispatch_stage(pre_blur_processor_stage,
[
get_sampler_uniform(depth_image, 0, false),
get_sampler_uniform(velocity_image, 1, false),
get_image_uniform(custom_velocity_image, 2),
scene_data_buffer_uniform
],
byte_array,
Vector3i(x_groups, y_groups, 1),
"Process Velocity Buffer",
view)
rd.draw_command_end_label()

View File

@ -175,7 +175,7 @@ void main()
+ camera_movement_uv_change * params.movement_velocity_multiplier * sharp_step(params.movement_velocity_lower_threshold, params.movement_velocity_upper_threshold, length(camera_movement_uv_change))
+ object_uv_change * params.object_velocity_multilpier * sharp_step(params.object_velocity_lower_threshold, params.object_velocity_upper_threshold, length(object_uv_change));
// if objects move, clear z direction, (z only correct for static environment)
if(dot(object_uv_change, object_uv_change) > 0.000001)
if(dot(object_uv_change.xy, object_uv_change.xy) > 0.000001)
{
total_velocity.z = 0;
base_velocity.z = 0;

View File

@ -0,0 +1,14 @@
[remap]
importer="glsl"
type="RDShaderFile"
uid="uid://ojudxyx6f4rx"
path="res://.godot/imported/pre_blur_processor.glsl-1e488552a0780ca6b7db6c45f5370f53.res"
[deps]
source_file="res://addons/SphynxMotionBlurToolkit/PreBlurProcessing/pre_blur_processor.glsl"
dest_files=["res://.godot/imported/pre_blur_processor.glsl-1e488552a0780ca6b7db6c45f5370f53.res"]
[params]

View File

@ -1,15 +1,16 @@
[gd_scene load_steps=5 format=3 uid="uid://b0shum42bqq0y"]
[gd_scene load_steps=5 format=3 uid="uid://8p6li7o742g3"]
[ext_resource type="Shader" path="res://RadialBlurTest/radial_blur_mesh.gdshader" id="1_20eg7"]
[ext_resource type="Script" path="res://RadialBlurTest/radial_blur_mesh.gd" id="2_wbael"]
[ext_resource type="Shader" path="res://RadialBlurTest/radial_blur_mesh.gdshader" id="1_36vys"]
[ext_resource type="Script" path="res://RadialBlurTest/radial_blur_mesh.gd" id="2_cfhks"]
[sub_resource type="CylinderMesh" id="CylinderMesh_pgvyt"]
resource_local_to_scene = true
height = 0.25
[sub_resource type="ShaderMaterial" id="ShaderMaterial_stapv"]
resource_local_to_scene = true
render_priority = 0
shader = ExtResource("1_20eg7")
shader = ExtResource("1_36vys")
shader_parameter/local_rotation_axis = Vector3(0, 1, 0)
shader_parameter/rotation_speed = 0.0
shader_parameter/sample_count = 8
@ -23,4 +24,4 @@ shader_parameter/debug_color = Color(1, 0, 0, 0)
process_priority = 1
mesh = SubResource("CylinderMesh_pgvyt")
surface_material_override/0 = SubResource("ShaderMaterial_stapv")
script = ExtResource("2_wbael")
script = ExtResource("2_cfhks")

View File

@ -0,0 +1,12 @@
@tool
extends EditorPlugin
func _enter_tree() -> void:
# Initialization of the plugin goes here.
pass
func _exit_tree() -> void:
# Clean-up of the plugin goes here.
pass

View File

@ -0,0 +1,7 @@
[plugin]
name="SphynxMotionBlurToolkit"
description="A toolkit containinp multiple motion blur implementations, as well as debug stages, and radial blur toolkit for propellers and wheels"
author="Sphynx"
version="4.3"
script="SphynxMotionBlurToolkit.gd"