10const DEFAULT_HISTORY_BLEND_RATE: f32 = 0.1; 11const MIN_HISTORY_BLEND_RATE: f32 = 0.015; 13@group(0) @binding(0) var view_target: texture_2d<f32>; 14@group(0) @binding(1) var history: texture_2d<f32>; 15@group(0) @binding(2) var motion_vectors: texture_2d<f32>; 16@group(0) @binding(3) var depth: texture_depth_2d; 17@group(0) @binding(4) var nearest_sampler: sampler; 18@group(0) @binding(5) var linear_sampler: sampler; 21 @location(0) view_target: vec4<f32>, 22 @location(1) history: vec4<f32>, 30fn rcp(x: f32) -> f32 { return 1.0 / x; } 31fn max3(x: vec3<f32>) -> f32 { return max(x.r, max(x.g, x.b)); } 32fn tonemap(color: vec3<f32>) -> vec3<f32> { return color * rcp(max3(color) + 1.0); } 33fn reverse_tonemap(color: vec3<f32>) -> vec3<f32> { return color * rcp(1.0 - max3(color)); } 37fn RGB_to_YCoCg(rgb: vec3<f32>) -> vec3<f32> { 38 let y = (rgb.r / 4.0) + (rgb.g / 2.0) + (rgb.b / 4.0); 39 let co = (rgb.r / 2.0) - (rgb.b / 2.0); 40 let cg = (-rgb.r / 4.0) + (rgb.g / 2.0) - (rgb.b / 4.0); 41 return vec3(y, co, cg); 44fn YCoCg_to_RGB(ycocg: vec3<f32>) -> vec3<f32> { 45 let r = ycocg.x + ycocg.y - ycocg.z; 46 let g = ycocg.x + ycocg.z; 47 let b = ycocg.x - ycocg.y - ycocg.z; 48 return saturate(vec3(r, g, b)); 51fn clip_towards_aabb_center(history_color: vec3<f32>, current_color: vec3<f32>, aabb_min: vec3<f32>, aabb_max: vec3<f32>) -> vec3<f32> { 52 let p_clip = 0.5 * (aabb_max + aabb_min); 53 let e_clip = 0.5 * (aabb_max - aabb_min) + 0.00000001; 54 let v_clip = history_color - p_clip; 55 let v_unit = v_clip / e_clip; 56 let a_unit = abs(v_unit); 57 let ma_unit = max3(a_unit); 59 return p_clip + (v_clip / ma_unit); 65fn sample_history(u: f32, v: f32) -> vec3<f32> { 66 return textureSample(history, linear_sampler, vec2(u, v)).rgb; 69fn sample_view_target(uv: vec2<f32>) -> vec3<f32> { 70 var sample = textureSample(view_target, nearest_sampler, uv).rgb; 72 sample = tonemap(sample); 73 return RGB_to_YCoCg(sample); 77fn taa(@location(0) uv: vec2<f32>) -> Output { 78 let texture_size = vec2<f32>(textureDimensions(view_target)); 79 let texel_size = 1.0 / texture_size; 82 let original_color = textureSample(view_target, nearest_sampler, uv); 83 var current_color = original_color.rgb; 85 current_color = tonemap(current_color); 87 var history_confidence: f32; 91 let offset = texel_size * 2.0; 92 let d_uv_tl = uv + vec2(-offset.x, offset.y); 93 let d_uv_tr = uv + vec2(offset.x, offset.y); 94 let d_uv_bl = uv + vec2(-offset.x, -offset.y); 95 let d_uv_br = uv + vec2(offset.x, -offset.y); 97 let d_tl = textureSample(depth, nearest_sampler, d_uv_tl); 98 let d_tr = textureSample(depth, nearest_sampler, d_uv_tr); 99 var closest_depth = textureSample(depth, nearest_sampler, uv); 100 let d_bl = textureSample(depth, nearest_sampler, d_uv_bl); 101 let d_br = textureSample(depth, nearest_sampler, d_uv_br); 102 if d_tl > closest_depth { 103 closest_uv = d_uv_tl; 104 closest_depth = d_tl; 106 if d_tr > closest_depth { 107 closest_uv = d_uv_tr; 108 closest_depth = d_tr; 110 if d_bl > closest_depth { 111 closest_uv = d_uv_bl; 112 closest_depth = d_bl; 114 if d_br > closest_depth { 115 closest_uv = d_uv_br; 117 let closest_motion_vector = textureSample(motion_vectors, nearest_sampler, closest_uv).rg; 124 let history_uv = uv - closest_motion_vector; 125 let sample_position = history_uv * texture_size; 126 let texel_center = floor(sample_position - 0.5) + 0.5; 127 let f = sample_position - texel_center; 128 let w0 = f * (-0.5 + f * (1.0 - 0.5 * f)); 129 let w1 = 1.0 + f * f * (-2.5 + 1.5 * f); 130 let w2 = f * (0.5 + f * (2.0 - 1.5 * f)); 131 let w3 = f * f * (-0.5 + 0.5 * f); 133 let texel_position_0 = (texel_center - 1.0) * texel_size; 134 let texel_position_3 = (texel_center + 2.0) * texel_size; 135 let texel_position_12 = (texel_center + (w2 / w12)) * texel_size; 136 var history_color = sample_history(texel_position_12.x, texel_position_0.y) * w12.x * w0.y; 137 history_color += sample_history(texel_position_0.x, texel_position_12.y) * w0.x * w12.y; 138 history_color += sample_history(texel_position_12.x, texel_position_12.y) * w12.x * w12.y; 139 history_color += sample_history(texel_position_3.x, texel_position_12.y) * w3.x * w12.y; 140 history_color += sample_history(texel_position_12.x, texel_position_3.y) * w12.x * w3.y; 145 let s_tl = sample_view_target(uv + vec2(-texel_size.x, texel_size.y)); 146 let s_tm = sample_view_target(uv + vec2( 0.0, texel_size.y)); 147 let s_tr = sample_view_target(uv + vec2( texel_size.x, texel_size.y)); 148 let s_ml = sample_view_target(uv + vec2(-texel_size.x, 0.0)); 149 let s_mm = RGB_to_YCoCg(current_color); 150 let s_mr = sample_view_target(uv + vec2( texel_size.x, 0.0)); 151 let s_bl = sample_view_target(uv + vec2(-texel_size.x, -texel_size.y)); 152 let s_bm = sample_view_target(uv + vec2( 0.0, -texel_size.y)); 153 let s_br = sample_view_target(uv + vec2( texel_size.x, -texel_size.y)); 154 let moment_1 = s_tl + s_tm + s_tr + s_ml + s_mm + s_mr + s_bl + s_bm + s_br; 155 let moment_2 = (s_tl * s_tl) + (s_tm * s_tm) + (s_tr * s_tr) + (s_ml * s_ml) + (s_mm * s_mm) + (s_mr * s_mr) + (s_bl * s_bl) + (s_bm * s_bm) + (s_br * s_br); 156 let mean = moment_1 / 9.0; 157 let variance = (moment_2 / 9.0) - (mean * mean); 158 let std_deviation = sqrt(max(variance, vec3(0.0))); 159 history_color = RGB_to_YCoCg(history_color); 160 history_color = clip_towards_aabb_center(history_color, s_mm, mean - std_deviation, mean + std_deviation); 161 history_color = YCoCg_to_RGB(history_color); 164 history_confidence = textureSample(history, nearest_sampler, uv).a; 165 let pixel_motion_vector = abs(closest_motion_vector) * texture_size; 166 if pixel_motion_vector.x < 0.01 && pixel_motion_vector.y < 0.01 { 168 history_confidence += 10.0; 171 history_confidence = 1.0; 177 var current_color_factor = clamp(1.0 / history_confidence, MIN_HISTORY_BLEND_RATE, DEFAULT_HISTORY_BLEND_RATE); 180 if any(saturate(history_uv) != history_uv) { 181 current_color_factor = 1.0; 182 history_confidence = 1.0; 185 current_color = mix(history_color, current_color, current_color_factor); 192 history_confidence = 1.0 / MIN_HISTORY_BLEND_RATE; 193 out.history = vec4(current_color, history_confidence); 195 current_color = reverse_tonemap(current_color); 196 out.view_target = vec4(current_color, original_color.a);