Eevee: Fix Missing alpha when rendering with DOF
[blender.git] / source / blender / draw / engines / eevee / shaders / effect_dof_frag.glsl
1
2 uniform mat4 ProjectionMatrix;
3
4 uniform sampler2D colorBuffer;
5 uniform sampler2D depthBuffer;
6
7 uniform vec3 dofParams;
8
9 #define dof_aperturesize    dofParams.x
10 #define dof_distance        dofParams.y
11 #define dof_invsensorsize   dofParams.z
12
13 uniform vec4 bokehParams[2];
14
15 #define bokeh_rotation      bokehParams[0].x
16 #define bokeh_ratio         bokehParams[0].y
17 #define bokeh_maxsize       bokehParams[0].z
18 #define bokeh_sides         bokehParams[1] /* Polygon Bokeh shape number of sides (with precomputed vars) */
19
20 uniform vec2 nearFar; /* Near & far view depths values */
21
22 #define M_PI 3.1415926535897932384626433832795
23 #define M_2PI 6.2831853071795864769252868
24
25 /* -------------- Utils ------------- */
26
27 /* divide by sensor size to get the normalized size */
28 #define calculate_coc(zdepth) (dof_aperturesize * (dof_distance / zdepth - 1.0) * dof_invsensorsize)
29
30 #define linear_depth(z) ((ProjectionMatrix[3][3] == 0.0) \
31                 ? (nearFar.x  * nearFar.y) / (z * (nearFar.x - nearFar.y) + nearFar.y) \
32                 : (z * 2.0 - 1.0) * nearFar.y)
33
34 #define weighted_sum(a, b, c, d, e) (a * e.x + b * e.y + c * e.z + d * e.w) / max(1e-6, dot(e, vec4(1.0)));
35
36 float max_v4(vec4 v) { return max(max(v.x, v.y), max(v.z, v.w)); }
37
38 #define THRESHOLD 1.0
39
40 #ifdef STEP_DOWNSAMPLE
41
42 layout(location = 0) out vec4 nearColor;
43 layout(location = 1) out vec4 farColor;
44 layout(location = 2) out vec2 cocData;
45
46 /* Downsample the color buffer to half resolution.
47  * Weight color samples by
48  * Compute maximum CoC for near and far blur. */
49 void main(void)
50 {
51         ivec4 uvs = ivec4(gl_FragCoord.xyxy) * 2 + ivec4(0, 0, 1, 1);
52
53         /* custom downsampling */
54         vec4 color1 = texelFetch(colorBuffer, uvs.xy, 0);
55         vec4 color2 = texelFetch(colorBuffer, uvs.zw, 0);
56         vec4 color3 = texelFetch(colorBuffer, uvs.zy, 0);
57         vec4 color4 = texelFetch(colorBuffer, uvs.xw, 0);
58
59         /* Leverage SIMD by combining 4 depth samples into a vec4 */
60         vec4 depth;
61         depth.r = texelFetch(depthBuffer, uvs.xy, 0).r;
62         depth.g = texelFetch(depthBuffer, uvs.zw, 0).r;
63         depth.b = texelFetch(depthBuffer, uvs.zy, 0).r;
64         depth.a = texelFetch(depthBuffer, uvs.xw, 0).r;
65
66         vec4 zdepth = linear_depth(depth);
67
68         /* Compute signed CoC for each depth samples */
69         vec4 coc_near = calculate_coc(zdepth);
70         vec4 coc_far = -coc_near;
71
72         cocData.x = max(max_v4(coc_near), 0.0);
73         cocData.y = max(max_v4(coc_far), 0.0);
74
75         /* now we need to write the near-far fields premultiplied by the coc
76          * also use bilateral weighting by each coc values to avoid bleeding. */
77         vec4 near_weights = step(THRESHOLD, coc_near) * clamp(1.0 - abs(cocData.x - coc_near), 0.0, 1.0);
78         vec4 far_weights  = step(THRESHOLD, coc_far)  * clamp(1.0 - abs(cocData.y - coc_far),  0.0, 1.0);
79
80 #  ifdef USE_ALPHA_DOF
81         /* Premult */
82         color1.rgb *= color1.a;
83         color2.rgb *= color2.a;
84         color3.rgb *= color3.a;
85         color4.rgb *= color4.a;
86 #  endif
87
88         /* now write output to weighted buffers. */
89         nearColor = weighted_sum(color1, color2, color3, color4, near_weights);
90         farColor = weighted_sum(color1, color2, color3, color4, far_weights);
91 }
92
93 #elif defined(STEP_SCATTER)
94
95 flat in vec4 color;
96 flat in float weight;
97 flat in float smoothFac;
98 flat in ivec2 edge;
99 /* coordinate used for calculating radius */
100 in vec2 particlecoord;
101
102 layout(location = 0) out vec4 fragColor;
103 #  ifdef USE_ALPHA_DOF
104 layout(location = 1) out float fragAlpha;
105 #  endif
106
107 /* accumulate color in the near/far blur buffers */
108 void main(void)
109 {
110         /* Discard to avoid bleeding onto the next layer */
111         if (int(gl_FragCoord.x) * edge.x + edge.y > 0)
112                 discard;
113
114         /* Circle Dof */
115         float dist = length(particlecoord);
116
117         /* Ouside of bokeh shape */
118         if (dist > 1.0)
119                 discard;
120
121         /* Regular Polygon Dof */
122         if (bokeh_sides.x > 0.0) {
123                 /* Circle parametrization */
124                 float theta = atan(particlecoord.y, particlecoord.x) + bokeh_rotation;
125
126                 /* Optimized version of :
127                  * float denom = theta - (M_2PI / bokeh_sides) * floor((bokeh_sides * theta + M_PI) / M_2PI);
128                  * float r = cos(M_PI / bokeh_sides) / cos(denom); */
129                 float denom = theta - bokeh_sides.y * floor(bokeh_sides.z * theta + 0.5);
130                 float r = bokeh_sides.w / cos(denom);
131
132                 /* Divide circle radial coord by the shape radius for angle theta.
133                  * Giving us the new linear radius to the shape edge. */
134                 dist /= r;
135
136                 /* Ouside of bokeh shape */
137                 if (dist > 1.0)
138                         discard;
139         }
140
141         fragColor = color;
142
143         /* Smooth the edges a bit. This effectively reduce the bokeh shape
144          * but does fade out the undersampling artifacts. */
145         float shape = smoothstep(1.0, min(0.999, smoothFac), dist);
146
147         fragColor *= shape;
148
149 #  ifdef USE_ALPHA_DOF
150         fragAlpha = fragColor.a;
151         fragColor.a = weight * shape;
152 #  endif
153 }
154
155 #elif defined(STEP_RESOLVE)
156
157 #define MERGE_THRESHOLD 4.0
158
159 uniform sampler2D scatterBuffer;
160 uniform sampler2D scatterAlphaBuffer;
161
162 in vec4 uvcoordsvar;
163 out vec4 fragColor;
164
165 vec4 upsample_filter(sampler2D tex, vec2 uv, vec2 texelSize)
166 {
167         /* TODO FIXME: Clamp the sample position
168          * depending on the layer to avoid bleeding.
169          * This is not really noticeable so leaving it as is for now. */
170
171 #if 1 /* 9-tap bilinear upsampler (tent filter) */
172         vec4 d = texelSize.xyxy * vec4(1, 1, -1, 0);
173
174         vec4 s;
175         s  = textureLod(tex, uv - d.xy, 0.0);
176         s += textureLod(tex, uv - d.wy, 0.0) * 2;
177         s += textureLod(tex, uv - d.zy, 0.0);
178
179         s += textureLod(tex, uv + d.zw, 0.0) * 2;
180         s += textureLod(tex, uv       , 0.0) * 4;
181         s += textureLod(tex, uv + d.xw, 0.0) * 2;
182
183         s += textureLod(tex, uv + d.zy, 0.0);
184         s += textureLod(tex, uv + d.wy, 0.0) * 2;
185         s += textureLod(tex, uv + d.xy, 0.0);
186
187         return s * (1.0 / 16.0);
188 #else
189         /* 4-tap bilinear upsampler */
190         vec4 d = texelSize.xyxy * vec4(-1, -1, +1, +1) * 0.5;
191
192         vec4 s;
193         s  = textureLod(tex, uv + d.xy, 0.0);
194         s += textureLod(tex, uv + d.zy, 0.0);
195         s += textureLod(tex, uv + d.xw, 0.0);
196         s += textureLod(tex, uv + d.zw, 0.0);
197
198         return s * (1.0 / 4.0);
199 #endif
200 }
201
202 /* Combine the Far and Near color buffers */
203 void main(void)
204 {
205         vec2 uv = uvcoordsvar.xy;
206         /* Recompute Near / Far CoC per pixel */
207         float depth = textureLod(depthBuffer, uv, 0.0).r;
208         float zdepth = linear_depth(depth);
209         float coc_signed = calculate_coc(zdepth);
210         float coc_far = max(-coc_signed, 0.0);
211         float coc_near = max(coc_signed, 0.0);
212
213         vec4 focus_col = textureLod(colorBuffer, uv, 0.0);
214
215         vec2 texelSize = vec2(0.5, 1.0) / vec2(textureSize(scatterBuffer, 0));
216         vec2 near_uv = uv * vec2(0.5, 1.0);
217         vec2 far_uv = near_uv + vec2(0.5, 0.0);
218         vec4 near_col = upsample_filter(scatterBuffer, near_uv, texelSize);
219         vec4 far_col = upsample_filter(scatterBuffer, far_uv, texelSize);
220
221         float far_w = far_col.a;
222         float near_w = near_col.a;
223         float focus_w = 1.0 - smoothstep(1.0, MERGE_THRESHOLD, abs(coc_signed));
224         float inv_weight_sum = 1.0 / (near_w + focus_w + far_w);
225
226         focus_col *= focus_w; /* Premul */
227
228 #  ifdef USE_ALPHA_DOF
229         near_col.a = upsample_filter(scatterAlphaBuffer, near_uv, texelSize).r;
230         far_col.a = upsample_filter(scatterAlphaBuffer, far_uv, texelSize).r;
231 #  endif
232
233         fragColor = (far_col + near_col + focus_col) * inv_weight_sum;
234
235 #  ifdef USE_ALPHA_DOF
236         /* Unpremult */
237         fragColor.rgb /= (fragColor.a > 0.0) ? fragColor.a : 1.0;
238 #  endif
239 }
240
241 #endif