Commit 93e10db7 authored by Florian Oetke's avatar Florian Oetke
Browse files

reduced TAA/GI artefakts around moving objects

parent c53900ff
......@@ -68,6 +68,11 @@ vec3 clip_aabb(vec3 aabb_min, vec3 aabb_max, vec3 p, vec3 q) {
return q;// point inside aabb
}
float pixel_intensity(vec3 c) {
return dot(c,c);
//return length(c);
}
// A Fast, Small-Radius GPU Median Filter by Morgan McGuire: http://casual-effects.com/research/McGuire2008Median/index.html
#define s2(a, b) temp = a; a = min(a, b); b = max(temp, b);
#define mn3(a, b, c) s2(a, b); s2(a, c);
......@@ -79,26 +84,25 @@ vec3 clip_aabb(vec3 aabb_min, vec3 aabb_max, vec3 p, vec3 q) {
#define mnmx6(a, b, c, d, e, f) s2(a, d); s2(b, e); s2(c, f); mn3(a, b, c); mx3(d, e, f); // 7 exchanges
void main() {
float current_mip = pcs.prev_projection[0][3];
float max_mip = pcs.prev_projection[1][3];
float base_mip = pcs.prev_projection[3][3];
// read diffuse color, modulate with modulo if equal to min/max of neighborhood => noise
ivec2 uv = ivec2(textureSize(result_sampler, 0).xy * vertex_out.tex_coords);
ivec2 result_sampler_size = textureSize(result_sampler, 0).xy;
ivec2 uv = ivec2(result_sampler_size * vertex_out.tex_coords);
vec3 colors[9];
for(int x=-1; x<=1; x++) {
for(int y=-1; y<=1; y++) {
colors[(x+1)*3+(y+1)] = texelFetch(result_sampler, uv+ivec2(x,y), 0).rgb;
ivec2 c_uv = uv+ivec2(x,y);
c_uv = clamp(c_uv, ivec2(0,0), result_sampler_size-ivec2(0,0));
colors[(x+1)*3+(y+1)] = texelFetch(result_sampler, c_uv, 0).rgb;
}
}
float min_c = dot(colors[0], colors[0]);
float min_c = pixel_intensity(colors[0]);
float max_c = min_c;
for(int i=1; i<9; i++) {
float intensity = dot(colors[i], colors[i]);
float intensity = pixel_intensity(colors[i]);
min_c = min(min_c, intensity);
max_c = min(max_c, intensity);
max_c = max(max_c, intensity);
}
vec3 org = colors[4];
......@@ -112,16 +116,20 @@ void main() {
mnmx5(colors[1], colors[2], colors[3], colors[4], colors[6]);
mnmx4(colors[2], colors[3], colors[4], colors[7]);
mnmx3(colors[3], colors[4], colors[8]);
out_color = vec4(colors[4], 1.0);
}
// modulate diffuse GI by ambient occlusion
float ao = 1.0;
if(INCLUDE_AO==1 && pcs.projection[3][3]>0.0) {
float ao = texture(ao_sampler, vertex_out.tex_coords).r;
ao = texture(ao_sampler, vertex_out.tex_coords).r;
ao = mix(1.0, ao, pcs.projection[3][3]);
out_color.rgb *= ao;
}
out_color.rgb *= ao;
for(int i=0; i<9; i++)
colors[i] *= ao;
// blend with history
vec3 c_history = texture(history_result_sampler, vertex_out.tex_coords).rgb;
......@@ -131,15 +139,15 @@ void main() {
vec2 du = vec2(texel_size.x, 0.0);
vec2 dv = vec2(0.0, texel_size.y);
vec3 ctl = texture(result_sampler, vertex_out.tex_coords - dv - du).rgb;
vec3 ctc = texture(result_sampler, vertex_out.tex_coords - dv).rgb;
vec3 ctr = texture(result_sampler, vertex_out.tex_coords - dv + du).rgb;
vec3 cml = texture(result_sampler, vertex_out.tex_coords - du).rgb;
vec3 ctl = colors[0];
vec3 ctc = colors[1];
vec3 ctr = colors[2];
vec3 cml = colors[3];
vec3 cmc = out_color.rgb;
vec3 cmr = texture(result_sampler, vertex_out.tex_coords + du).rgb;
vec3 cbl = texture(result_sampler, vertex_out.tex_coords + dv - du).rgb;
vec3 cbc = texture(result_sampler, vertex_out.tex_coords + dv).rgb;
vec3 cbr = texture(result_sampler, vertex_out.tex_coords + dv + du).rgb;
vec3 cmr = colors[5];
vec3 cbl = colors[6];
vec3 cbc = colors[7];
vec3 cbr = colors[8];
vec3 cmin = min(ctl, min(ctc, min(ctr, min(cml, min(cmc, min(cmr, min(cbl, min(cbc, cbr))))))));
vec3 cmax = max(ctl, max(ctc, max(ctr, max(cml, max(cmc, max(cmr, max(cbl, max(cbc, cbr))))))));
......@@ -160,5 +168,10 @@ void main() {
c_history = clip_aabb(cmin.xyz, cmax.xyz, clamp(cavg, cmin, cmax), c_history);
float weight = texture(history_weight_sampler, vertex_out.tex_coords).g;
out_color.rgb = mix(out_color.rgb, c_history, weight*0.9);
if(dot(c_history,c_history) < dot(out_color.rgb,out_color.rgb))
weight *= 0.98;
else
weight *= 0.8;
out_color.rgb = mix(out_color.rgb, c_history, weight);
}
......@@ -142,7 +142,7 @@ void main() {
float history_weight = texelFetch(history_weight_sampler,
ivec2(vertex_out.tex_coords * textureSize(history_weight_sampler, 0)),
0).r;
0).g;
out_color *= 1.0 - (history_weight*0.96);
......
......@@ -33,17 +33,17 @@ out gl_PerVertex {
void main() {
float unused_weight = 1.0 - dot(bone_weights, vec4(1.0));
mat3x4 bone = bones.offset[bone_ids[0]] * bone_weights[0]
+ bones.offset[bone_ids[1]] * bone_weights[1]
+ bones.offset[bone_ids[2]] * bone_weights[2]
+ bones.offset[bone_ids[3]] * bone_weights[3]
+ mat3x4(1) * unused_weight;
vec3 p = vec4(position, 1.0) * bone;
vec3 n = vec4(normal, 0.0) * bone;
//p = position;
//n = normal;
vec3 p = (vec4(position, 1.0) * bones.offset[bone_ids[0]]) * bone_weights[0]
+ (vec4(position, 1.0) * bones.offset[bone_ids[1]]) * bone_weights[1]
+ (vec4(position, 1.0) * bones.offset[bone_ids[2]]) * bone_weights[2]
+ (vec4(position, 1.0) * bones.offset[bone_ids[3]]) * bone_weights[3]
+ position * unused_weight;
vec3 n = (vec4(normal, 0.0) * bones.offset[bone_ids[0]]) * bone_weights[0]
+ (vec4(normal, 0.0) * bones.offset[bone_ids[1]]) * bone_weights[1]
+ (vec4(normal, 0.0) * bones.offset[bone_ids[2]]) * bone_weights[2]
+ (vec4(normal, 0.0) * bones.offset[bone_ids[3]]) * bone_weights[3]
+ normal * unused_weight;
vec4 view_pos = model_uniforms.model_to_view * vec4(p, 1.0);
......
......@@ -97,18 +97,28 @@ void main() {
vec4 uv_tmp = reprojection_fov * vec4(uv*2-1, 0.5, 1);
uv = uv_tmp.xy/uv_tmp.w *0.5+0.5;
float depth = texture(depth_sampler, uv).r;
float depth = texture(depth_sampler, uv - offset/2).r;
vec3 position = position_from_ldepth(vertex_out.tex_coords, depth);
vec3 position = position_from_ldepth(vertex_out.tex_coords - offset/2, depth);
vec4 prev_uv = constants.reprojection * vec4(position, 1.0);
vec4 prev_depth_uv = reprojection_fov * prev_uv;
prev_depth_uv.xy = (prev_depth_uv.xy/prev_depth_uv.w)*0.5+0.5;
float prev_depth = texture(prev_depth_sampler, prev_depth_uv.xy).r;
float proj_prev_depth = abs(prev_depth_uv.z) / global_uniforms.proj_planes.y;
float depth_mismatch = smoothstep(0.002, 0.02, abs(prev_depth-proj_prev_depth));
vec4 prev_depth = textureGather(prev_depth_sampler, prev_depth_uv.xy, 0) * global_uniforms.proj_planes.y;
float proj_prev_depth = abs(prev_depth_uv.z);
vec4 depth_diff = abs(prev_depth-vec4(proj_prev_depth));
float depth_mismatch = smoothstep(0.5, 1.0, depth_diff[0])
* smoothstep(0.5, 1.0, depth_diff[1])
* smoothstep(0.5, 1.0, depth_diff[2])
*smoothstep(0.5, 1.0, depth_diff[3]);
ivec2 px_uv = ivec2(vertex_out.tex_coords.xy * textureSize(prev_depth_sampler,0).xy);
float depth_mismatch_tmp = depth_mismatch;
depth_mismatch -= dFdx(depth_mismatch_tmp) * ((px_uv.x & 1) - 0.5);
depth_mismatch -= dFdy(depth_mismatch_tmp) * ((px_uv.y & 1) - 0.5);
prev_uv.xy = (prev_uv.xy/prev_uv.w)*0.5+0.5;
......@@ -161,11 +171,10 @@ void main() {
float lum_diff = abs(lum_curr - lum_prev) / max(lum_curr, max(lum_prev, 0.2));
float weight = 1.0 - lum_diff;
float t = mix(0.88, 0.97, weight*weight);
float t = mix(0.8, 0.97, weight*weight);
t *= 0.5 + (1.0 - depth_mismatch)*0.5;
out_color = vec4(max(vec3(0), mix(curr, prev_clamped, t)), 1.0);
out_color.rgb = out_color.rgb / (1 - luminance(out_color.rgb));
// out_color.rgb = vec3(weight*weight);
}
......@@ -39,7 +39,7 @@ float calc_upsampled_weights(sampler2D highres_depth_sampler, sampler2D highres_
// calculate the maximum depth deviation based on the distance, to reduce bluring
// near the camera where it's most noticable
float depth_dev = mix(0.3, 1.5, depth) / global_uniforms.proj_planes.y;
float depth_dev = mix(0.01, 0.3, depth) / global_uniforms.proj_planes.y;
// sample low-res depth and modulate the weights based on their difference to the high-res depth
weight_00 *= weight_depth(textureGather(depth_sampler, uv_00, 0) - depth, depth_dev);
......
......@@ -772,8 +772,10 @@ namespace mirrage {
}
anim.animation().process([&](auto& curr_animation) {
auto dqs_states = _animation_test_dqs.get<renderer::Animation_comp>().get_or_throw().states();
auto lbs_states = _animation_test_lbs.get<renderer::Animation_comp>().get_or_throw().states();
auto& dqs_anim = _animation_test_dqs.get<renderer::Animation_comp>().get_or_throw();
auto& dqs_states = dqs_anim.states();
auto& lbs_anim = _animation_test_lbs.get<renderer::Animation_comp>().get_or_throw();
auto& lbs_states = lbs_anim.states();
auto time = 0.f;
auto curr_dqs_state = std::find_if(dqs_states.begin(), dqs_states.end(), [&](auto& s) {
......@@ -794,11 +796,14 @@ namespace mirrage {
nk_label(ctx, "Time", NK_TEXT_LEFT);
auto new_time = nk_slide_float(ctx, 0.f, time, duration, 0.01f);
if(std::abs(new_time - time) > 0.00001f) {
dqs_anim.mark_dirty();
lbs_anim.mark_dirty();
if(curr_dqs_state != dqs_states.end())
curr_dqs_state->time = time;
curr_dqs_state->time = new_time;
if(curr_lbs_state != lbs_states.end())
curr_lbs_state->time = time;
curr_lbs_state->time = new_time;
}
nk_label(ctx,
......@@ -806,7 +811,7 @@ namespace mirrage {
NK_TEXT_LEFT);
auto speed = anim.speed();
nk_property_float(ctx, "Speed", 0.f, &speed, 5.f, 0.01f, 0.2f);
nk_property_float(ctx, "Speed", 0.f, &speed, 5.f, 0.01f, 0.001f);
anim.speed(speed);
......
......@@ -79,6 +79,7 @@ namespace mirrage::renderer {
auto states() const -> auto& { return _animation_states; }
void step_time(util::Time delta_time);
void mark_dirty() { _dirty = true; }
private:
friend class Animation_pass;
......
......@@ -260,12 +260,13 @@ namespace mirrage::renderer {
}
}
/// returns the index of the first element not >= value or the top/bottom if out of range
/// returns the index of the last element not >= value or the top/bottom if out of range
/// performs an interpolation search starting at a given index
/// O(1) if the given index is already near the solution
/// O(log log N) if the data is nearly uniformly distributed
/// O(N) else (worst case)
auto binary_search(gsl::span<const float> container, float value, std::int16_t i) -> std::int16_t
auto interpolation_search(gsl::span<const float> container, float value, std::int16_t i)
-> std::int16_t
{
auto high = std::int16_t(container.size() - 2);
auto low = std::int16_t(0);
......@@ -324,8 +325,9 @@ namespace mirrage::renderer {
}
index = std::clamp(
binary_search(times, time, index), std::int16_t(0), std::int16_t(times.size() - 2));
index = std::clamp(interpolation_search(times, time, index),
std::int16_t(0),
std::int16_t(times.size() - 2));
return (time - times[index]) / (times[index + 1] - times[index]);
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment