diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2017-05-09 22:57:13 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2017-05-10 00:55:19 +0300 |
commit | 9075f934aae2cccad18ba96130650965875f2fa1 (patch) | |
tree | 061d478698a2951f46a2ce0f1cae5035a8d3cc05 /source/blender/draw/engines/eevee/shaders | |
parent | 435f5017fafe81b90f59cb41be391f85b770e604 (diff) |
Eevee: Initial Depth Of Field commit.
Diffstat (limited to 'source/blender/draw/engines/eevee/shaders')
3 files changed, 369 insertions, 0 deletions
diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_frag.glsl new file mode 100644 index 00000000000..0eaee94165d --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/effect_dof_frag.glsl @@ -0,0 +1,222 @@ + +uniform mat4 ProjectionMatrix; + +uniform sampler2D colorBuffer; +uniform sampler2D depthBuffer; + +uniform vec3 dofParams; + +#define dof_aperturesize dofParams.x +#define dof_distance dofParams.y +#define dof_invsensorsize dofParams.z + +uniform vec3 bokehParams; + +#define bokeh_sides bokehParams.x /* Polygon Bokeh shape number of sides */ +#define bokeh_rotation bokehParams.y + +uniform vec2 nearFar; /* Near & far view depths values */ + +/* initial uv coordinate */ +in vec2 uvcoord; + +layout(location = 0) out vec4 fragData0; +layout(location = 1) out vec4 fragData1; +layout(location = 2) out vec4 fragData2; + +#define M_PI 3.1415926535897932384626433832795 +#define M_2PI 6.2831853071795864769252868 + +/* -------------- Utils ------------- */ + +/* calculate 4 samples at once */ +float calculate_coc(in float zdepth) +{ + float coc = dof_aperturesize * (dof_distance / zdepth - 1.0); + + /* multiply by 1.0 / sensor size to get the normalized size */ + return coc * dof_invsensorsize; +} + +vec4 calculate_coc(in vec4 zdepth) +{ + vec4 coc = dof_aperturesize * (vec4(dof_distance) / zdepth - vec4(1.0)); + + /* multiply by 1.0 / sensor size to get the normalized size */ + return coc * dof_invsensorsize; +} + +float max4(vec4 x) +{ + return max(max(x.x, x.y), max(x.z, x.w)); +} + +float linear_depth(float z) +{ + /* if persp */ + if (ProjectionMatrix[3][3] == 0.0) { + return (nearFar.x * nearFar.y) / (z * (nearFar.x - nearFar.y) + nearFar.y); + } + else { + return (z * 2.0 - 1.0) * nearFar.y; + } +} + +vec4 linear_depth(vec4 z) +{ + /* if persp */ + if (ProjectionMatrix[3][3] == 0.0) { + return (nearFar.xxxx * nearFar.yyyy) / (z * (nearFar.xxxx - nearFar.yyyy) + nearFar.yyyy); + } + else { + return (z * 2.0 - 1.0) * nearFar.yyyy; + } +} + +#define THRESHOLD 0.0 + +/* ----------- Steps ----------- */ + +/* Downsample the color buffer to half resolution. + * Weight color samples by + * Compute maximum CoC for near and far blur. */ +void step_downsample(void) +{ + ivec4 uvs = ivec4(gl_FragCoord.xyxy) * 2 + ivec4(0, 0, 1, 1); + + /* custom downsampling */ + vec4 color1 = texelFetch(colorBuffer, uvs.xy, 0); + vec4 color2 = texelFetch(colorBuffer, uvs.zw, 0); + vec4 color3 = texelFetch(colorBuffer, uvs.zy, 0); + vec4 color4 = texelFetch(colorBuffer, uvs.xw, 0); + + /* Leverage SIMD by combining 4 depth samples into a vec4 */ + vec4 depth; + depth.r = texelFetch(depthBuffer, uvs.xy, 0).r; + depth.g = texelFetch(depthBuffer, uvs.zw, 0).r; + depth.b = texelFetch(depthBuffer, uvs.zy, 0).r; + depth.a = texelFetch(depthBuffer, uvs.xw, 0).r; + + vec4 zdepth = linear_depth(depth); + + /* Compute signed CoC for each depth samples */ + vec4 coc_near = calculate_coc(zdepth); + vec4 coc_far = -coc_near; + + /* now we need to write the near-far fields premultiplied by the coc */ + vec4 near_weights = step(THRESHOLD, coc_near); + vec4 far_weights = step(THRESHOLD, coc_far); + + /* now write output to weighted buffers. */ + fragData0 = color1 * near_weights.x + + color2 * near_weights.y + + color3 * near_weights.z + + color4 * near_weights.w; + + fragData1 = color1 * far_weights.x + + color2 * far_weights.y + + color3 * far_weights.z + + color4 * far_weights.w; + + float norm_near = dot(near_weights, near_weights); + float norm_far = dot(far_weights, far_weights); + + if (norm_near > 0.0) { + fragData0 /= norm_near; + } + + if (norm_far > 0.0) { + fragData1 /= norm_far; + } + + float max_near_coc = max(max4(coc_near), 0.0); + float max_far_coc = max(max4(coc_far), 0.0); + + fragData2 = vec4(max_near_coc, max_far_coc, 0.0, 1.0); +} + +/* coordinate used for calculating radius et al set in geometry shader */ +in vec2 particlecoord; +flat in vec4 color; + +/* accumulate color in the near/far blur buffers */ +void step_scatter(void) +{ + /* Early out */ + float dist_sqrd = dot(particlecoord, particlecoord); + + /* Circle Dof */ + if (dist_sqrd > 1.0) { + discard; + } + + /* Regular Polygon Dof */ + if (bokeh_sides > 0.0) { + /* Circle parametrization */ + float theta = atan(particlecoord.y, particlecoord.x) + bokeh_rotation; + float r; + + r = cos(M_PI / bokeh_sides) / + (cos(theta - (M_2PI / bokeh_sides) * floor((bokeh_sides * theta + M_PI) / M_2PI))); + + if (dist_sqrd > r * r) { + discard; + } + } + + fragData0 = color; +} + +#define MERGE_THRESHOLD 4.0 + +uniform sampler2D farBuffer; +uniform sampler2D nearBuffer; + +/* Combine the Far and Near color buffers */ +void step_resolve(void) +{ + /* Recompute Near / Far CoC */ + float depth = texture(depthBuffer, uvcoord).r; + float zdepth = linear_depth(depth); + float coc_signed = calculate_coc(zdepth); + float coc_far = max(-coc_signed, 0.0); + float coc_near = max(coc_signed, 0.0); + + /* Recompute Near / Far CoC */ + vec4 srccolor = texture(colorBuffer, uvcoord); + vec4 farcolor = texture(farBuffer, uvcoord); + vec4 nearcolor = texture(nearBuffer, uvcoord); + + float farweight = farcolor.a; + if (farweight > 0.0) + farcolor /= farweight; + + float mixfac = smoothstep(1.0, MERGE_THRESHOLD, coc_far); + + farweight = mix(1.0, farweight, mixfac); + + float nearweight = nearcolor.a; + if (nearweight > 0.0) { + nearcolor /= nearweight; + } + + if (coc_near > 1.0) { + fragData0 = nearcolor; + } + else { + float totalweight = nearweight + farweight; + vec4 finalcolor = mix(srccolor, farcolor, mixfac); + fragData0 = mix(finalcolor, nearcolor, nearweight / totalweight); + } +} + +void main() +{ +#ifdef STEP_DOWNSAMPLE + step_downsample(); +#elif defined(STEP_SCATTER) + step_scatter(); +#elif defined(STEP_RESOLVE) + step_resolve(); +#endif +} diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_geom.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_geom.glsl new file mode 100644 index 00000000000..1c774885a32 --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/effect_dof_geom.glsl @@ -0,0 +1,55 @@ +uniform ivec2 targetBufferSize; + +uniform vec2 layerSelection; + +uniform sampler2D colorBuffer; +uniform sampler2D cocBuffer; + +layout(points) in; +layout(triangle_strip, max_vertices = 4) out; + +#define POS gl_in[0].gl_Position + +in vec2 uvcoord[]; +out vec2 particlecoord; +flat out vec4 color; + +#define M_PI 3.1415926535897932384626433832795 + +void main() +{ + vec4 coc = textureLod(cocBuffer, uvcoord[0], 0.0); + + float offset_val = dot(coc.rg, layerSelection); + if (offset_val < 1.0) + return; + + vec4 colortex = textureLod(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(targetBufferSize.x, targetBufferSize.y); + + color = colortex; + + gl_Position = POS + vec4(-offset_far.x, -offset_far.y, 0.0, 0.0); + particlecoord = vec2(-1.0, -1.0); + EmitVertex(); + + gl_Position = POS + vec4(-offset_far.x, offset_far.y, 0.0, 0.0); + particlecoord = vec2(-1.0, 1.0); + EmitVertex(); + + gl_Position = POS + vec4(offset_far.x, -offset_far.y, 0.0, 0.0); + particlecoord = vec2(1.0, -1.0); + EmitVertex(); + + gl_Position = POS + vec4(offset_far.x, offset_far.y, 0.0, 0.0); + particlecoord = vec2(1.0, 1.0); + EmitVertex(); + + EndPrimitive(); +} diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_vert.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_vert.glsl new file mode 100644 index 00000000000..3899365a771 --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/effect_dof_vert.glsl @@ -0,0 +1,92 @@ + +in vec2 pos; +in vec2 uvs; + +uniform vec2 layerSelection; + +uniform sampler2D colorBuffer; +uniform sampler2D cocBuffer; + +flat out vec4 color; +out vec2 particlecoord; + +#define M_PI 3.1415926535897932384626433832795 + +/* geometry shading pass, calculate a texture coordinate based on the indexed id */ +void step_scatter() +{ + ivec2 tex_size = textureSize(cocBuffer, 0); + vec2 texel_size = 1.0 / vec2(tex_size); + + int t_id = gl_VertexID / 3; /* Triangle Id */ + + ivec2 texelco = ivec2(0); + /* some math to get the target pixel */ + texelco.x = t_id % tex_size.x; + texelco.y = t_id / tex_size.x; + + float coc = dot(layerSelection, texelFetch(cocBuffer, texelco, 0).rg); + + /* Clamp to max size for performance */ + coc = min(coc, 100.0); + + if (coc >= 1.0) { + color = texelFetch(colorBuffer, texelco, 0); + /* find the area the pixel will cover and divide the color by it */ + float alpha = 1.0 / (coc * coc * M_PI); + color *= alpha; + color.a = alpha; + } + else { + color = vec4(0.0); + } + + /* Generate Triangle : less memory fetches from a VBO */ + int v_id = gl_VertexID % 3; /* Vertex Id */ + + /* Extend to cover at least the unit circle */ + const float extend = (cos(M_PI / 4.0) + 1.0) * 2.0; + /* Crappy diagram + * ex 1 + * | \ + * | \ + * 1 | \ + * | \ + * | \ + * 0 | x \ + * | Circle \ + * | Origin \ + * -1 0 --------------- 2 + * -1 0 1 ex + **/ + gl_Position.x = float(v_id / 2) * extend - 1.0; /* int divisor round down */ + gl_Position.y = float(v_id % 2) * extend - 1.0; + gl_Position.z = 0.0; + gl_Position.w = 1.0; + + /* Generate Triangle */ + particlecoord = gl_Position.xy; + + gl_Position.xy *= coc * texel_size; + gl_Position.xy -= 1.0 - 0.5 * texel_size; /* NDC Bottom left */ + gl_Position.xy += (0.5 + vec2(texelco) * 2.0) * texel_size; +} + +out vec2 uvcoord; + +void passthrough() +{ + uvcoord = uvs; + gl_Position = vec4(pos, 0.0, 1.0); +} + +void main() +{ +#if defined(STEP_DOWNSAMPLE) + passthrough(); +#elif defined(STEP_SCATTER) + step_scatter(); +#elif defined(STEP_RESOLVE) + passthrough(); +#endif +}
\ No newline at end of file |