diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2020-06-22 20:57:53 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2020-06-22 20:57:53 +0300 |
commit | 15dda0115c783805753119984decb4d9249b1f01 (patch) | |
tree | c2d674f83d02edd6eb694c2510dbe1aaff510fe7 /source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl | |
parent | 3cea42ce29cb986cf9614d9b712d72915d52e546 (diff) |
UI: Widget: Replace geometry by fragment shader drawing
This means all the antiailasing is done inside the fragment shader.
We use a Signed Distance Field to draw the 2D rounded boxes. This ensure
the best quality for AA.
This reduce the averge Batch for widget to 16 verts instead of ~600 and
reduce overshading a lot.
Theme Emboss alpha and tria alpha needs to be changed after this refactor.
The shadow drawing is left unchanged and still use geometry.
Reviewed By: Severin
Differential Revision: https://developer.blender.org/D7833
Diffstat (limited to 'source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl')
-rw-r--r-- | source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl | 81 |
1 files changed, 74 insertions, 7 deletions
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl index bdc87baf924..05fbae53e18 100644 --- a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl @@ -1,11 +1,62 @@ uniform vec3 checkerColorAndSize; -noperspective in vec4 finalColor; +noperspective in vec2 uvInterp; noperspective in float butCo; flat in float discardFac; +flat in float shadeTri; +flat in vec2 outRectSize; +flat in vec4 outRoundCorners; +noperspective in vec4 innerColor; +flat in vec4 borderColor; +flat in vec4 embossColor; +flat in float lineWidth; out vec4 fragColor; +vec3 compute_masks(vec2 uv) +{ + bool upper_half = uv.y > outRectSize.y * 0.5; + bool right_half = uv.x > outRectSize.x * 0.5; + float corner_rad; + + vec2 uv_sdf = uv; + if (right_half) { + uv_sdf.x = outRectSize.x - uv_sdf.x; + } + if (upper_half) { + uv_sdf.y = outRectSize.y - uv_sdf.y; + corner_rad = right_half ? outRoundCorners.z : outRoundCorners.w; + } + else { + corner_rad = right_half ? outRoundCorners.y : outRoundCorners.x; + } + + /* Signed distance field from the corner (in pixel). + * inner_sdf is sharp and outer_sdf is rounded. */ + uv_sdf -= corner_rad; + float inner_sdf = max(0.0, min(uv_sdf.x, uv_sdf.y)); + float outer_sdf = -length(min(uv_sdf, 0.0)); + float sdf = inner_sdf + outer_sdf + corner_rad; + + /* Fade emboss at the border. */ + float emboss_size = clamp((upper_half) ? 0.0 : (uv.x / corner_rad), 0.0, 1.0); + + /* Clamp line width to be at least 1px wide. This can happen if the projection matrix + * has been scaled (i.e: Node editor)... */ + float line_width = (lineWidth > 0.0) ? max(fwidth(uv.x), lineWidth) : 0.0; + + const float aa_radius = 0.5; + vec3 masks; + masks.x = smoothstep(-aa_radius, aa_radius, sdf); + masks.y = smoothstep(-aa_radius, aa_radius, sdf - line_width); + masks.z = smoothstep(-aa_radius, aa_radius, sdf + line_width * emboss_size); + + /* Compose masks together to avoid having too much alpha. */ + masks.zx = max(vec2(0.0), masks.zx - masks.xy); + + return masks; +} + vec4 do_checkerboard() { float size = checkerColorAndSize.z; @@ -25,16 +76,32 @@ void main() discard; } - fragColor = finalColor; - - if (butCo > 0.5) { - vec4 checker = do_checkerboard(); - fragColor = mix(checker, fragColor, fragColor.a); - } + vec3 masks = compute_masks(uvInterp); if (butCo > 0.0) { + /* Alpha checker widget. */ + if (butCo > 0.5) { + vec4 checker = do_checkerboard(); + fragColor = mix(checker, innerColor, innerColor.a); + } + else { + /* Set alpha to 1.0. */ + fragColor = innerColor; + } fragColor.a = 1.0; } + else { + /* Premultiply here. */ + fragColor = innerColor * vec4(innerColor.aaa, 1.0); + } + fragColor *= masks.y; + fragColor += masks.x * borderColor; + fragColor += masks.z * embossColor; + + /* Un-premult because the blend equation is already doing the mult. */ + if (fragColor.a > 0.0) { + fragColor.rgb /= fragColor.a; + } fragColor = blender_srgb_to_framebuffer_space(fragColor); } |