Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntony Riakiotakis <kalast@gmail.com>2015-03-03 19:47:31 +0300
committerAntony Riakiotakis <kalast@gmail.com>2015-03-19 17:18:14 +0300
commit3e9947c4d4714a4752c768bb78fe6d227fc6be97 (patch)
tree1c21bc46db3bb15f9efeab0c5c0e5d2b8d75d74f /source/blender/gpu/shaders
parent93048873f10bab6ebcee9467a1e462f410f1bf12 (diff)
Depth of field high quality:
A new checkbox "High quality" is provided in camera settings to enable this. This creates a depth of field that is much closer to the rendered result and even supports aperture blades in the effect, but it's more expensive too. There are optimizations to do here since the technique is very fill rate heavy. People, be careful, this -can- lock up your screen if depth of field blurring is too extreme. Technical details: This uses geometry shaders + instancing and is an adaptation of techniques gathered from http://bartwronski.com/2014/04/07/bokeh-depth-of-field-going-insane- http://advances.realtimerendering.com/s2011/SousaSchulzKazyan%20- %20in%20Real-Time%20Rendering%20Course).ppt TODOs: * Support dithering to minimize banding. * Optimize fill rate in geometry shader.
Diffstat (limited to 'source/blender/gpu/shaders')
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl166
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_dof_hq_geo.glsl50
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_dof_hq_vert.glsl58
3 files changed, 274 insertions, 0 deletions
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl
new file mode 100644
index 00000000000..e2d3ab36ec8
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl
@@ -0,0 +1,166 @@
+/* amount of offset to move one pixel left-right.
+ * In second pass some dimensions are zero to control verical/horizontal convolution */
+uniform vec2 invrendertargetdim;
+
+uniform ivec2 rendertargetdim;
+
+/* color buffer */
+uniform sampler2D colorbuffer;
+uniform sampler2D farbuffer;
+uniform sampler2D nearbuffer;
+
+/* depth buffer */
+uniform sampler2D depthbuffer;
+
+uniform sampler2D cocbuffer;
+
+/* this includes focal distance in x and aperture size in y */
+uniform vec4 dof_params;
+
+/* viewvectors for reconstruction of world space */
+uniform vec4 viewvecs[3];
+
+/* initial uv coordinate */
+varying vec2 uvcoord;
+
+/* coordinate used for calculating radius et al set in geometry shader */
+varying vec2 particlecoord;
+varying vec4 color;
+
+/* downsampling coordinates */
+varying vec2 downsample1;
+varying vec2 downsample2;
+varying vec2 downsample3;
+varying vec2 downsample4;
+
+#define M_PI 3.1415926535897932384626433832795
+
+/* calculate 4 samples at once */
+vec4 calculate_coc(in vec4 zdepth)
+{
+ vec4 coc = dof_params.x * (vec4(dof_params.y) / zdepth - vec4(1.0));
+
+ /* multiply by 1.0 / sensor size to get the normalized size */
+ return coc * dof_params.z;
+}
+
+#define THRESHOLD 0.0
+
+/* downsample the color buffer to half resolution */
+void downsample_pass()
+{
+ vec4 depth;
+ vec4 zdepth;
+ vec4 coc;
+ float far_coc, near_coc;
+
+ /* custom downsampling. We need to be careful to sample nearest here to avoid leaks */
+ vec4 color1 = texture2D(colorbuffer, downsample1);
+ vec4 color2 = texture2D(colorbuffer, downsample2);
+ vec4 color3 = texture2D(colorbuffer, downsample3);
+ vec4 color4 = texture2D(colorbuffer, downsample4);
+
+ depth.r = texture2D(depthbuffer, downsample1).r;
+ depth.g = texture2D(depthbuffer, downsample2).r;
+ depth.b = texture2D(depthbuffer, downsample3).r;
+ depth.a = texture2D(depthbuffer, downsample4).r;
+
+ zdepth = get_view_space_z_from_depth(vec4(viewvecs[0].z), vec4(viewvecs[1].z), depth);
+ coc = calculate_coc(zdepth);
+ vec4 coc_far = -coc;
+
+ /* now we need to write the near-far fields premultiplied by the coc */
+ vec4 near_weights = vec4((coc.x >= THRESHOLD) ? 1.0 : 0.0, (coc.y >= THRESHOLD) ? 1.0 : 0.0,
+ (coc.z >= THRESHOLD) ? 1.0 : 0.0, (coc.w >= THRESHOLD) ? 1.0 : 0.0);
+ vec4 far_weights = vec4((coc_far.x >= THRESHOLD) ? 1.0 : 0.0, (coc_far.y >= THRESHOLD) ? 1.0 : 0.0,
+ (coc_far.z >= THRESHOLD) ? 1.0 : 0.0, (coc_far.w >= THRESHOLD) ? 1.0 : 0.0);
+
+ near_coc = max(max(max(coc.x, coc.y), max(coc.z, coc.w)), 0.0);
+ far_coc = max(max(max(coc_far.x, coc_far.y), max(coc_far.z, coc_far.w)), 0.0);
+
+ float norm_near = dot(near_weights, vec4(1.0));
+ float norm_far = dot(far_weights, vec4(1.0));
+
+ /* now write output to weighted buffers. */
+ gl_FragData[0] = color1 * near_weights.x + color2 * near_weights.y + color3 * near_weights.z +
+ color4 * near_weights.w;
+ gl_FragData[1] = color1 * far_weights.x + color2 * far_weights.y + color3 * far_weights.z +
+ color4 * far_weights.w;
+
+ if (norm_near > 0.0)
+ gl_FragData[0] /= norm_near;
+ if (norm_far > 0.0)
+ gl_FragData[1] /= norm_far;
+ gl_FragData[2] = vec4(near_coc, far_coc, 0.0, 1.0);
+}
+
+/* accumulate color in the near/far blur buffers */
+void accumulate_pass(void) {
+ float theta = atan(particlecoord.y, particlecoord.x);
+ float r;
+
+ if (dof_params.w == 0.0)
+ r = 1.0;
+ else
+ r = cos(M_PI / dof_params.w) / (cos(theta - (2.0 * M_PI / dof_params.w) * floor((dof_params.w * theta + M_PI) / (2 * M_PI))));
+
+ if (dot(particlecoord, particlecoord) > r * r)
+ discard;
+
+ gl_FragColor = color;
+}
+#define MERGE_THRESHOLD 4.0
+
+/* combine the passes, */
+void final_pass(void) {
+ vec4 finalcolor;
+ float totalweight;
+ float depth = texture2D(depthbuffer, uvcoord).r;
+
+ vec4 zdepth = get_view_space_z_from_depth(vec4(viewvecs[0].z), vec4(viewvecs[1].z), vec4(depth));
+ float coc_near = calculate_coc(zdepth).r;
+ float coc_far = max(-coc_near, 0.0);
+ coc_near = max(coc_near, 0.0);
+
+ vec4 farcolor = texture2D(farbuffer, uvcoord);
+ float farweight = farcolor.a;
+ if (farweight > 0)
+ farcolor /= farweight;
+ vec4 nearcolor = texture2D(nearbuffer, uvcoord);
+
+ vec4 srccolor = texture2D(colorbuffer, uvcoord);
+
+ vec4 coc = texture2D(cocbuffer, uvcoord);
+
+ float mixfac = smoothstep(1.0, MERGE_THRESHOLD, coc_far);
+ finalcolor = mix(srccolor, farcolor, mixfac);
+
+ farweight = mix(1.0, farweight, mixfac);
+
+ float nearweight = nearcolor.a;
+ if (nearweight > 0) {
+ nearcolor /= nearweight;
+ }
+
+ if (coc_near > 1.0) {
+ nearweight = 1.0;
+ finalcolor = nearcolor;
+ }
+ else {
+ totalweight = nearweight + farweight;
+ finalcolor = mix(finalcolor, nearcolor, nearweight / totalweight);
+ }
+
+ gl_FragColor = finalcolor;
+}
+
+void main()
+{
+#ifdef FIRST_PASS
+ downsample_pass();
+#elif defined(SECOND_PASS)
+ accumulate_pass();
+#elif defined(THIRD_PASS)
+ final_pass();
+#endif
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_geo.glsl b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_geo.glsl
new file mode 100644
index 00000000000..9f365a0d671
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_geo.glsl
@@ -0,0 +1,50 @@
+uniform ivec2 rendertargetdim;
+uniform sampler2D colorbuffer;
+
+uniform vec2 layerselection;
+
+uniform sampler2D cocbuffer;
+
+/* initial uv coordinate */
+varying in vec2 uvcoord[];
+varying out vec2 particlecoord;
+varying out vec4 color;
+
+
+#define M_PI 3.1415926535897932384626433832795
+
+void main(void)
+{
+ vec4 coc = texture2DLod(cocbuffer, uvcoord[0], 0.0);
+
+ float offset_val = dot(coc.rg, layerselection);
+ if (offset_val < 1.0)
+ return;
+
+ vec4 colortex = texture2DLod(colorbuffer, uvcoord[0], 0.0);
+
+ /* find the area the pixel will cover and divide the color by it */
+ float alpha = 1.0 / (offset_val * offset_val * M_PI);
+ colortex *= alpha;
+ colortex.a = alpha;
+
+ vec2 offset_far = vec2(offset_val * 0.5) / vec2(rendertargetdim.x, rendertargetdim.y);
+
+ gl_Position = gl_PositionIn[0] + vec4(-offset_far.x, -offset_far.y, 0.0, 0.0);
+ color = colortex;
+ particlecoord = vec2(-1.0, -1.0);
+ EmitVertex();
+ gl_Position = gl_PositionIn[0] + vec4(-offset_far.x, offset_far.y, 0.0, 0.0);
+ particlecoord = vec2(-1.0, 1.0);
+ color = colortex;
+ EmitVertex();
+ gl_Position = gl_PositionIn[0] + vec4(offset_far.x, -offset_far.y, 0.0, 0.0);
+ particlecoord = vec2(1.0, -1.0);
+ color = colortex;
+ EmitVertex();
+ gl_Position = gl_PositionIn[0] + vec4(offset_far.x, offset_far.y, 0.0, 0.0);
+ particlecoord = vec2(1.0, 1.0);
+ color = colortex;
+ EmitVertex();
+ EndPrimitive();
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_vert.glsl b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_vert.glsl
new file mode 100644
index 00000000000..e8c505bd15f
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_vert.glsl
@@ -0,0 +1,58 @@
+uniform vec2 invrendertargetdim;
+uniform ivec2 rendertargetdim;
+/* initial uv coordinate */
+varying vec2 uvcoord;
+
+/* coordinate used for calculating radius et al set in geometry shader */
+varying vec2 particlecoord;
+
+/* downsampling coordinates */
+varying vec2 downsample1;
+varying vec2 downsample2;
+varying vec2 downsample3;
+varying vec2 downsample4;
+
+void vert_dof_downsample()
+{
+ /* gather pixels from neighbors. half dimensions means we offset half a pixel to
+ * get this right though it's possible we may lose a pixel at some point */
+ downsample1 = gl_MultiTexCoord0.xy + vec2(-0.5, -0.5) * invrendertargetdim;
+ downsample2 = gl_MultiTexCoord0.xy + vec2(-0.5, 0.5) * invrendertargetdim;
+ downsample3 = gl_MultiTexCoord0.xy + vec2(0.5, 0.5) * invrendertargetdim;
+ downsample4 = gl_MultiTexCoord0.xy + vec2(0.5, -0.5) * invrendertargetdim;
+
+ gl_Position = gl_Vertex;
+}
+
+/* geometry shading pass, calculate a texture coordinate based on the indexed id */
+void vert_dof_coc_scatter_pass()
+{
+ vec2 pixel = vec2(1.0 / float(rendertargetdim.x), 1.0 / float(rendertargetdim.y));
+ /* some math to get the target pixel */
+ int row = gl_InstanceID / rendertargetdim.x;
+ int column = gl_InstanceID % rendertargetdim.x;
+ uvcoord = vec2(column, row) * pixel + 0.5 * pixel;
+
+ vec2 pos = uvcoord * 2.0 - vec2(1.0);
+ gl_Position = vec4(pos.x, pos.y, 0.0, 1.0);
+
+// uvcoord = vec2(0.5, 0.5);
+// gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
+}
+
+void vert_dof_final()
+{
+ uvcoord = gl_MultiTexCoord0.xy;
+ gl_Position = gl_Vertex;
+}
+
+void main()
+{
+#if defined(FIRST_PASS)
+ vert_dof_downsample();
+#elif defined(SECOND_PASS)
+ vert_dof_coc_scatter_pass();
+#else
+ vert_dof_final();
+#endif
+} \ No newline at end of file