ac6751fb5fb3bb470751ad8efa7c5819977b5b0f
[blender.git] / source / blender / draw / engines / eevee / shaders / effect_temporal_aa.glsl
1
2 uniform sampler2D colorHistoryBuffer;
3 uniform sampler2D velocityBuffer;
4
5 out vec4 FragColor;
6
7 vec4 safe_color(vec4 c)
8 {
9   /* Clamp to avoid black square artifacts if a pixel goes NaN. */
10   return clamp(c, vec4(0.0), vec4(1e20)); /* 1e20 arbitrary. */
11 }
12
13 #ifdef USE_REPROJECTION
14
15 /**
16  * Adapted from https://casual-effects.com/g3d/G3D10/data-files/shader/Film/Film_temporalAA.pix
17  * which is adapted from
18  * https://github.com/gokselgoktas/temporal-anti-aliasing/blob/master/Assets/Resources/Shaders/TemporalAntiAliasing.cginc
19  * which is adapted from https://github.com/playdeadgames/temporal
20  * Optimization by Stubbesaurus and epsilon adjustment to avoid division by zero.
21  *
22  * This can cause 3x3 blocks of color when there is a thin edge of a similar color that
23  * is varying in intensity.
24  */
25 vec3 clip_to_aabb(vec3 color, vec3 minimum, vec3 maximum, vec3 average)
26 {
27   /* note: only clips towards aabb center (but fast!) */
28   vec3 center = 0.5 * (maximum + minimum);
29   vec3 extents = 0.5 * (maximum - minimum);
30   vec3 dist = color - center;
31   vec3 ts = abs(extents) / max(abs(dist), vec3(0.0001));
32   float t = saturate(min_v3(ts));
33   return center + dist * t;
34 }
35
36 /**
37  * Vastly based on https://github.com/playdeadgames/temporal
38  */
39 void main()
40 {
41   ivec2 texel = ivec2(gl_FragCoord.xy);
42   vec2 motion = texelFetch(velocityBuffer, texel, 0).rg;
43
44   /* Decode from unsigned normalized 16bit texture. */
45   motion = motion * 2.0 - 1.0;
46
47   /* Compute pixel position in previous frame. */
48   vec2 screen_res = vec2(textureSize(colorBuffer, 0).xy);
49   vec2 uv = gl_FragCoord.xy / screen_res;
50   vec2 uv_history = uv - motion;
51
52   ivec2 texel_history = ivec2(uv_history * screen_res);
53   vec4 color_history = textureLod(colorHistoryBuffer, uv_history, 0.0);
54
55   /* Color bounding box clamping. 3x3 neighborhood. */
56   vec4 c02 = texelFetchOffset(colorBuffer, texel, 0, ivec2(-1, 1));
57   vec4 c12 = texelFetchOffset(colorBuffer, texel, 0, ivec2(0, 1));
58   vec4 c22 = texelFetchOffset(colorBuffer, texel, 0, ivec2(1, 1));
59   vec4 c01 = texelFetchOffset(colorBuffer, texel, 0, ivec2(-1, 0));
60   vec4 c11 = texelFetchOffset(colorBuffer, texel, 0, ivec2(0, 0));
61   vec4 c21 = texelFetchOffset(colorBuffer, texel, 0, ivec2(1, 0));
62   vec4 c00 = texelFetchOffset(colorBuffer, texel, 0, ivec2(-1, -1));
63   vec4 c10 = texelFetchOffset(colorBuffer, texel, 0, ivec2(0, -1));
64   vec4 c20 = texelFetchOffset(colorBuffer, texel, 0, ivec2(1, -1));
65
66   vec4 color = c11;
67
68   /* AABB minmax */
69   vec4 min_col = min9(c02, c12, c22, c01, c11, c21, c00, c10, c20);
70   vec4 max_col = max9(c02, c12, c22, c01, c11, c21, c00, c10, c20);
71   vec4 avg_col = avg9(c02, c12, c22, c01, c11, c21, c00, c10, c20);
72
73   /* bias the color aabb toward the center (rounding the shape) */
74   vec4 min_center = min5(c12, c01, c11, c21, c10);
75   vec4 max_center = max5(c12, c01, c11, c21, c10);
76   vec4 avg_center = avg5(c12, c01, c11, c21, c10);
77   min_col = (min_col + min_center) * 0.5;
78   max_col = (max_col + max_center) * 0.5;
79   avg_col = (avg_col + avg_center) * 0.5;
80
81   /* Clip color toward the center of the neighborhood colors AABB box. */
82   color_history.rgb = clip_to_aabb(color_history.rgb, min_col.rgb, max_col.rgb, avg_col.rgb);
83
84   /* Luminance weighting. */
85   /* TODO correct luminance */
86   float lum0 = dot(color.rgb, vec3(0.333));
87   float lum1 = dot(color_history.rgb, vec3(0.333));
88   float diff = abs(lum0 - lum1) / max(lum0, max(lum1, 0.2));
89   float weight = 1.0 - diff;
90   float alpha = mix(0.04, 0.12, weight * weight);
91
92   color_history = mix(color_history, color, alpha);
93
94   bool out_of_view = any(greaterThanEqual(abs(uv_history - 0.5), vec2(0.5)));
95   color_history = (out_of_view) ? color : color_history;
96
97   FragColor = safe_color(color_history);
98   /* There is some ghost issue if we use the alpha
99    * in the viewport. Overwritting alpha fixes it. */
100   FragColor.a = color.a;
101 }
102
103 #else
104
105 uniform float alpha;
106
107 void main()
108 {
109   ivec2 texel = ivec2(gl_FragCoord.xy);
110   vec4 color = texelFetch(colorBuffer, texel, 0);
111   vec4 color_history = texelFetch(colorHistoryBuffer, texel, 0);
112   FragColor = safe_color(mix(color_history, color, alpha));
113 }
114 #endif