better guertin, new experimental blur

- Improved on guertin's original blurring scheme for better realizm
- working experimental retrospective blur with fake transparency
This commit is contained in:
sphynx-owner
2024-08-19 01:18:09 +03:00
parent f0e2d1415f
commit d0376a456f
31 changed files with 1842 additions and 271 deletions

View File

@ -0,0 +1,200 @@
#[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 velocity_sampler;
layout(set = 0, binding = 2) uniform sampler2D neighbor_max;
layout(set = 0, binding = 3) uniform sampler2D tile_variance;
layout(rgba16f, set = 0, binding = 4) uniform writeonly image2D output_color;
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), 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(l >= 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);
vec4 vnzw = textureLod(neighbor_max, x + vec2(params.tile_size / 2) / vec2(render_size) + jitter_tile(uvi), 0.0) * vec4(render_size / 2., 1, 1);
vec2 vn = vnzw.xy;
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);
#ifdef DEBUG
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));
#endif
return;
}
vec2 wn = safenorm(vn);
vec4 vxzw = textureLod(velocity_sampler, x, 0.0) * vec4(render_size / 2., 1, 1);
vec2 vx = vxzw.xy;
float vx_length = max(0.5, length(vx));
vec2 wx = safenorm(vx);
float j = interleaved_gradient_noise(uvi) * 2. - 1.;
float zx = vxzw.w;
float weight = 1e-6;
vec4 sum = base_color * weight;
float nai_weight = 1e-6;
vec4 nai_sum = base_color * nai_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));
bool use_vn = ((i % 2) == 0);
vec2 d = use_vn ? vn : vx;
float dz = use_vn ? vnzw.z : vxzw.z;
vec2 wd = use_vn ? wn : wx;
float T = abs(t * vn_length);
vec2 y = x + t * d / render_size;
float wa = abs(dot(wx, wd));
vec4 vyzw = textureLod(velocity_sampler, y, 0.0) * vec4(render_size / 2, 1, 1);
vec2 vy = vyzw.xy - dz * t;
float vy_length = max(0.5, length(vy));
float zy = vyzw.w;
float f = z_compare(-zy, -zx, 20000);
float b = z_compare(-zx, -zy, 20000);
float wb = abs(dot(vy / vy_length, wd));
if(use_vn)
{
float ay = f * step(T, vy_length * wb);
weight += ay;
sum += textureLod(color_sampler, y, 0.0) * ay;
}
float nai_ay = b * step(T, vx_length * wa);
nai_weight += nai_ay;
nai_sum += textureLod(color_sampler, y, 0.0) * nai_ay;
}
sum /= weight;
weight /= params.sample_count / 2;
nai_sum /= nai_weight;
sum = mix(nai_sum, sum, weight);
imageStore(output_color, uvi, sum);
#ifdef DEBUG
imageStore(debug_1_image, uvi, sum);
imageStore(debug_2_image, uvi, vec4(vn / render_size * 2, 0, 1));
imageStore(debug_3_image, uvi, vnzw);
imageStore(debug_4_image, uvi, vxzw);
#endif
}

View File

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

View File

@ -95,7 +95,7 @@ void main()
float j = interleaved_gradient_noise(uvi) * 2. - 1.;
vec4 vnzw = textureLod(neighbor_max, x + jitter_tile(uvi), 0.0) * vec4(render_size / 2., 1, 1);
vec4 vnzw = textureLod(neighbor_max, x + vec2(params.tile_size / 2) / vec2(render_size) + jitter_tile(uvi), 0.0) * vec4(render_size / 2., 1, 1);
vec2 vn = vnzw.xy;

View File

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

View File

@ -1,5 +1,5 @@
extends "res://addons/SphynxMotionBlurToolkit/Guertin/base_guertin_motion_blur.gd"
class_name GuertinMotionBlur
class_name OldGuertinMotionBlur
@export_group("Shader Stages")
@export var blur_stage : ShaderStageResource = preload("res://addons/SphynxMotionBlurToolkit/Guertin/guertin_blur_stage.tres"):

View File

@ -0,0 +1,228 @@
extends "res://addons/SphynxMotionBlurToolkit/Guertin/base_guertin_motion_blur.gd"
class_name GuertinMotionBlur
@export_group("Shader Stages")
@export var blur_stage : ShaderStageResource = preload("res://addons/SphynxMotionBlurToolkit/Guertin/guertin_experimental_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)
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 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)
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,
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 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(custom_velocity_image, 1, false),
get_sampler_uniform(neighbor_max_image, 2, false),
get_sampler_uniform(tile_variance_image, 3, true),
get_image_uniform(output_color_image, 4),
],
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()