Commit 55c08c1f authored by Florian Oetke's avatar Florian Oetke
Browse files

reduced temporal artefacts caused by GI/TAA

parent 43587639
......@@ -59,6 +59,12 @@ frag_shader:gi_spec_blur = shader/bin/gi_spec_blur.frag.spv
vert_shader:gi_reproject = shader/bin/fullscreen.vert.spv
frag_shader:gi_reproject = shader/bin/gi_reproject.frag.spv
vert_shader:gi_reprojection_weights = shader/bin/fullscreen.vert.spv
frag_shader:gi_reprojection_weights = shader/bin/gi_reprojection_weights.frag.spv
vert_shader:gi_weight_mipgen = shader/bin/fullscreen.vert.spv
frag_shader:gi_weight_mipgen = shader/bin/gi_weight_mipgen.frag.spv
vert_shader:median_filter = shader/bin/fullscreen.vert.spv
frag_shader:median_filter = shader/bin/median_filter.frag.spv
......
......@@ -27,8 +27,12 @@ layout(push_constant) uniform Push_constants {
void main() {
vec3 radiance = textureLod(result_diff_sampler, vertex_out.tex_coords, 0).rgb;
vec3 specular = textureLod(result_spec_sampler, vertex_out.tex_coords, 0).rgb;
vec3 radiance;
vec3 specular;
fast_upsampled_two(depth_sampler, mat_data_sampler,
lowres_depth_sampler, lowres_mat_data_sampler,
result_diff_sampler, result_spec_sampler, vertex_out.tex_coords,
radiance, specular);
out_color = vec4(calculate_gi(vertex_out.tex_coords, radiance, specular, albedo_sampler, mat_data_sampler, brdf_sampler), 0);
......
......@@ -7,18 +7,10 @@
#include "color_conversion.glsl"
float luminance_norm(vec3 c) {
vec3 f = vec3(0.299,0.587,0.114);
return sqrt(c.r*c.r*f.r + c.g*c.g*f.g + c.b*c.b*f.b);
}
vec3 calculate_gi(vec2 uv, vec3 radiance, vec3 specular,
sampler2D albedo_sampler, sampler2D mat_sampler, sampler2D brdf_sampler) {
const float PI = 3.14159265359;
// radiance /= max(1, 1 - luminance_norm(radiance)/1);
// specular /= max(1, 1 - luminance_norm(specular)/1);
// load / calculate material properties and factors
vec3 albedo = textureLod(albedo_sampler, uv, 0.0).rgb;
......@@ -45,13 +37,4 @@ vec3 calculate_gi(vec2 uv, vec3 radiance, vec3 specular,
return max(diff + spec, vec3(0,0,0))*1000.0;
}
vec3 calculate_gi(vec2 uv, vec2 gi_uv, int gi_lod, sampler2D diff_sampler, sampler2D spec_sampler,
sampler2D albedo_sampler, sampler2D mat_sampler, sampler2D brdf_sampler) {
// load diff + spec GI
vec3 radiance = textureLod(diff_sampler, gi_uv, 0).rgb;
vec3 specular = textureLod(spec_sampler, gi_uv, 0).rgb;
return calculate_gi(uv, radiance, specular, albedo_sampler, mat_sampler, brdf_sampler);
}
#endif
......@@ -21,7 +21,6 @@ layout(set=1, binding = 3) uniform sampler2D history_diff_sampler;
layout(set=1, binding = 4) uniform sampler2D history_spec_sampler;
layout(set=1, binding = 5) uniform sampler2D prev_depth_sampler;
layout(set=1, binding = 6) uniform sampler2D brdf_sampler;
layout(set=1, binding = 7) uniform sampler2D prev_weight_sampler;
layout(push_constant) uniform Push_constants {
mat4 reprojection;
......
......@@ -15,7 +15,7 @@ layout(location = 0) in Vertex_data {
layout(location = 0) out vec4 out_input; // input to current run
layout(location = 1) out vec4 out_diffuse; // reprojected diffuse GI from last frame
layout(location = 2) out vec4 out_specular; // reprojected specular GI from last frame
layout(location = 3) out vec4 out_weight; // weight of reprojected GI
layout(location = 3) out vec4 out_success; // 0=failed reprojection; 1=success
layout(set=1, binding = 0) uniform sampler2D depth_sampler;
layout(set=1, binding = 1) uniform sampler2D mat_data_sampler;
......@@ -38,6 +38,7 @@ void main() {
const float PI = 3.14159265359;
float depth = textureLod(depth_sampler, vertex_out.tex_coords, 0.0).r;
float depth_dev = fwidth(depth*global_uniforms.proj_planes.y);
vec3 pos = position_from_ldepth(vertex_out.tex_coords, depth);
......@@ -69,7 +70,7 @@ void main() {
out_input = vec4(0, 0, 0, 0);
out_diffuse = vec4(0, 0, 0, 1);
out_specular = vec4(0, 0, 0, 1);
out_weight = vec4(0, 0, 0, 1);
out_success = vec4(0, 0, 0, 1);
if(prev_uv.x>=0.0 && prev_uv.x<=1.0 && prev_uv.y>=0.0 && prev_uv.y<=1.0) {
// load diff + spec GI
......@@ -81,29 +82,16 @@ void main() {
out_input = vec4(gi, 0.0);
float proj_prev_depth = abs(prev_pos.z);
float prev_depth = textureLod(prev_depth_sampler, prev_uv.xy, 0.0).r;
vec3 real_prev_pos = vec3((prev_uv.xy * prev_projection_info.xy + prev_projection_info.zw), 1)
* prev_depth * -global_uniforms.proj_planes.y;
vec3 pos_error = real_prev_pos - prev_pos.xyz;
out_weight.r = 0.98 * (1.0-smoothstep(0.05, 0.07, length(pos_error)));
float pos_error = prev_depth*-global_uniforms.proj_planes.y - prev_pos.z;
float min_depth_error = mix(0.08, 0.6, depth);
float max_depth_error = mix(0.12, 0.4, depth);
out_success.r = clamp(1.0-step(min_depth_error, abs(pos_error)), 0, 1);
out_success.g = texture(prev_weight_sampler, prev_uv.xy).r;
out_diffuse.rgb = radiance;
out_specular.rgb = specular;
out_input *= (1.0 - smoothstep(0.1, 0.4, dot(pos_error,pos_error)));
vec2 hws_step = 1.0 / textureSize(prev_weight_sampler, 0);
float history_sample_count = dot(textureGather(prev_weight_sampler, prev_uv.xy-hws_step, 1), vec4(1));
history_sample_count += texture(prev_weight_sampler, prev_uv.xy+hws_step*vec2(1,-1)).g;
history_sample_count += texture(prev_weight_sampler, prev_uv.xy+hws_step*vec2(1, 0)).g;
history_sample_count += texture(prev_weight_sampler, prev_uv.xy+hws_step*vec2(1, 1)).g;
history_sample_count += texture(prev_weight_sampler, prev_uv.xy+hws_step*vec2(-1,1)).g;
history_sample_count += texture(prev_weight_sampler, prev_uv.xy+hws_step*vec2( 0,1)).g;
history_sample_count = history_sample_count / 9.0;
float sample_incr = global_uniforms.time.z * 6.0;
out_weight.g = out_weight.r * clamp((history_sample_count + sample_incr), 0, 1);
out_input *= out_success.r;
}
}
#version 450
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable
#include "median.glsl"
layout(location = 0) in Vertex_data {
vec2 tex_coords;
} vertex_out;
layout(location = 0) out vec4 out_weight; // weight of reprojected GI
layout(set=1, binding = 0) uniform sampler2D success_sampler;
void main() {
vec2 hws_size = textureSize(success_sampler, 0);
vec2 hws_step = 1.0 / hws_size;
ivec2 hws_uv = ivec2(hws_size * vertex_out.tex_coords.xy);
float weights[9];
vec4 w = textureGather(success_sampler, vertex_out.tex_coords.xy-hws_step, 0);
weights[0] = w[0];
weights[1] = w[1];
weights[2] = w[2];
weights[3] = w[3];
weights[4] = texelFetchOffset(success_sampler, hws_uv, 0, ivec2(1,-1)).r;
weights[5] = texelFetchOffset(success_sampler, hws_uv, 0, ivec2(1, 0)).r;
weights[6] = texelFetchOffset(success_sampler, hws_uv, 0, ivec2(1, 1)).r;
weights[7] = texelFetchOffset(success_sampler, hws_uv, 0, ivec2(-1,1)).r;
weights[8] = texelFetchOffset(success_sampler, hws_uv, 0, ivec2( 0,1)).r;
vec2 weight = vec2(weights[0], texelFetch(success_sampler, hws_uv, 0).g);
for(int i=0; i<9; i++)
weight.r = min(weight.r, weights[i]);
weight.r = mix(weight.r, median_float(weights), 0.2);
out_weight = vec4(weight.r * (weight.g+1), 0, 0, 1);
}
......@@ -98,7 +98,7 @@ vec3 gi_sample(int lod, int base_mip) {
// fetch SAMPLES samples in a spiral pattern and combine their GI contribution
vec3 c = vec3(0,0,0);
float angle = PDnrand2(vec4(vertex_out.tex_coords, lod, global_uniforms.time.x*10.0)).r * 2*PI;
float angle = random(vec4(vertex_out.tex_coords, lod, global_uniforms.time.w)).r * 2*PI;
float outer_radius = R;
float inner_radius = LAST_SAMPLE==0 ? outer_radius / 2.0 - 4.0 : 0.0;
......@@ -139,6 +139,37 @@ vec3 gi_sample(int lod, int base_mip) {
return c;
}
float v(int lod, vec3 p1, vec3 p2, vec2 p1_uv, vec2 p2_uv) {
vec3 dir = p2-p1;
float max_distance = length(dir);
float max_steps = max_distance*5;
dir /= max_distance;
max_distance-=1.0;
if(max_distance<=0)
return 0;
vec2 depthSize = textureSize(depth_sampler, 0);
mat4 proj = pcs.projection;
proj[3][3] = 0;
vec3 jitter = PDnrand3(p1_uv);
vec2 raycast_hit_uv;
vec3 raycast_hit_point;
if(traceScreenSpaceRay1(p1+dir*0.5, dir, proj, depth_sampler,
depthSize, 50.0, global_uniforms.proj_planes.x,
4, 0.5*jitter.z, max_steps, max_distance, 0,
raycast_hit_uv, raycast_hit_point)) {
vec2 mat = texelFetch(mat_data_sampler, ivec2(raycast_hit_uv), 0).ba;
if(dot(mat,mat) > 0.00001)
return 0.02;
}
return 1;
}
// calculate the light transfer between two pixel of the current level
vec3 calc_illumination_from(int lod, vec2 tex_size, ivec2 src_uv, vec2 shaded_uv, float shaded_depth,
vec3 shaded_point, vec3 shaded_normal) {
......@@ -154,7 +185,8 @@ vec3 calc_illumination_from(int lod, vec2 tex_size, ivec2 src_uv, vec2 shaded_uv
vec3 dir = normalize(diff);
float r2 = dot(diff, diff);
float visibility = 1.0; // v(x, x_i); currently not implemented
float visibility = 1;//lod<=1 ? 1.0 : v(lod, shaded_point, P, shaded_uv, src_uv);
float NdotL_src = clamp(dot(N, dir), 0.0, 1.0); // cos(θ')
float NdotL_dst = clamp(dot(shaded_normal, -dir), 0.0, 1.0); // cos(θ)
......@@ -169,9 +201,9 @@ vec3 calc_illumination_from(int lod, vec2 tex_size, ivec2 src_uv, vec2 shaded_uv
float ds = pcs.prev_projection[2][3] * depth*depth * clamp(cos_alpha / cos_beta, 0.001, 1000.0);
// multiply all factors, that modulate the light transfer
float weight = visibility * NdotL_dst * NdotL_src * ds / (0.001+r2);
float weight = visibility * NdotL_dst * NdotL_src * ds / (0.01+r2);
if(weight<0.001) {
if(weight<0.0001) {
return vec3(0);
} else {
......
......@@ -45,6 +45,7 @@ layout(push_constant) uniform Push_constants {
#include "brdf.glsl"
#include "upsample.glsl"
#include "raycast.glsl"
#include "median.glsl"
// calculate luminance of a color (used for normalization)
float luminance_norm(vec3 c) {
......@@ -70,31 +71,36 @@ vec3 clip_aabb(vec3 aabb_min, vec3 aabb_max, vec3 p, vec3 q) {
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);
#define mx3(a, b, c) s2(b, c); s2(a, c);
#define mnmx3(a, b, c) mx3(a, b, c); s2(a, b); // 3 exchanges
#define mnmx4(a, b, c, d) s2(a, b); s2(c, d); s2(a, c); s2(b, d); // 4 exchanges
#define mnmx5(a, b, c, d, e) s2(a, b); s2(c, d); mn3(a, c, e); mx3(b, d, e); // 6 exchanges
#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() {
// read diffuse color, modulate with modulo if equal to min/max of neighborhood => noise
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++) {
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;
}
}
vec3 colors[9] = vec3[](
texelFetchOffset(result_sampler, uv, 0, ivec2(-1,-1)).rgb,
texelFetchOffset(result_sampler, uv, 0, ivec2(-1, 0)).rgb,
texelFetchOffset(result_sampler, uv, 0, ivec2( 0,-1)).rgb,
texelFetchOffset(result_sampler, uv, 0, ivec2( 0, 1)).rgb,
texelFetchOffset(result_sampler, uv, 0, ivec2( 0, 0)).rgb,
texelFetchOffset(result_sampler, uv, 0, ivec2( 1,-1)).rgb,
texelFetchOffset(result_sampler, uv, 0, ivec2(-1, 1)).rgb,
texelFetchOffset(result_sampler, uv, 0, ivec2( 1, 0)).rgb,
texelFetchOffset(result_sampler, uv, 0, ivec2( 1, 1)).rgb
);
// clamp texture coordinates
float w = result_sampler_size.x;
float h = result_sampler_size.y;
colors[0] = uv.x>0 && uv.y>0 ? colors[0] : colors[4];
colors[1] = uv.x>0 ? colors[1] : colors[4];
colors[2] = uv.y>0 ? colors[2] : colors[4];
colors[3] = uv.y<h ? colors[3] : colors[4];
colors[5] = uv.x<w && uv.y>0 ? colors[5] : colors[4];
colors[6] = uv.x>0 && uv.y<h ? colors[6] : colors[4];
colors[7] = uv.x<w ? colors[7] : colors[4];
colors[8] = uv.x<w && uv.y<h ? colors[8] : colors[4];
float min_c = pixel_intensity(colors[0]);
float max_c = min_c;
......@@ -107,32 +113,22 @@ void main() {
vec3 org = colors[4];
float org_intensity = dot(org, org);
if(min_c<org_intensity && max_c>org_intensity)
if(max_c>org_intensity)
out_color = vec4(org, 1.0);
else {
// Starting with a subset of size 6, remove the min and max each time
vec3 temp;
mnmx6(colors[0], colors[1], colors[2], colors[3], colors[4], colors[5]);
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);
out_color = vec4(median_vec3(colors), 1.0);
}
// modulate diffuse GI by ambient occlusion
float ao = 1.0;
if(INCLUDE_AO==1 && pcs.projection[3][3]>0.0) {
ao = texture(ao_sampler, vertex_out.tex_coords).r;
ao = mix(1.0, ao, pcs.projection[3][3]);
if(INCLUDE_AO==1) {
float ao = texture(ao_sampler, vertex_out.tex_coords).r * 0.75 + 0.25;
out_color.rgb *= ao;
for(int i=0; i<9; i++)
colors[i] *= 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;
vec3 c_history = texelFetch(history_result_sampler, uv, 0).rgb;
vec2 texel_size = 1.0 / textureSize(result_sampler, 0);
......@@ -163,15 +159,15 @@ void main() {
vec3 d = cmax - cmin;
cmin -= d * 0.5;
cmax += d * 0.5;
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;
if(dot(c_history,c_history) < dot(out_color.rgb,out_color.rgb))
weight *= 0.98;
float weight = texelFetch(history_weight_sampler, uv, 0).r;
if(weight<=0)
weight = 0.0;
else
weight *= 0.8;
weight = 1.0-1.0/(1+weight);
out_color.rgb = mix(out_color.rgb, c_history, weight);
out_color.rgb = mix(out_color.rgb, c_history, min(weight, 0.94));
}
Markdown is supported
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