diff options
10 files changed, 346 insertions, 278 deletions
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index ea52d8e8f1f..88caafb0c00 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -360,12 +360,10 @@ data_to_c_simple(engines/overlay/shaders/motion_path_line_geom.glsl SRC) data_to_c_simple(engines/overlay/shaders/motion_path_line_vert.glsl SRC) data_to_c_simple(engines/overlay/shaders/motion_path_point_vert.glsl SRC) data_to_c_simple(engines/overlay/shaders/outline_detect_frag.glsl SRC) -data_to_c_simple(engines/overlay/shaders/outline_expand_frag.glsl SRC) data_to_c_simple(engines/overlay/shaders/outline_prepass_frag.glsl SRC) data_to_c_simple(engines/overlay/shaders/outline_prepass_geom.glsl SRC) data_to_c_simple(engines/overlay/shaders/outline_prepass_vert.glsl SRC) data_to_c_simple(engines/overlay/shaders/outline_lightprobe_grid_vert.glsl SRC) -data_to_c_simple(engines/overlay/shaders/outline_resolve_frag.glsl SRC) data_to_c_simple(engines/overlay/shaders/paint_face_vert.glsl SRC) data_to_c_simple(engines/overlay/shaders/paint_point_vert.glsl SRC) data_to_c_simple(engines/overlay/shaders/paint_texture_frag.glsl SRC) diff --git a/source/blender/draw/engines/overlay/overlay_antialiasing.c b/source/blender/draw/engines/overlay/overlay_antialiasing.c index 569d47bf3a2..8f357d37768 100644 --- a/source/blender/draw/engines/overlay/overlay_antialiasing.c +++ b/source/blender/draw/engines/overlay/overlay_antialiasing.c @@ -60,12 +60,6 @@ #include "overlay_private.h" -void OVERLAY_antialiasing_reset(OVERLAY_Data *vedata) -{ - OVERLAY_PrivateData *pd = vedata->stl->pd; - pd->antialiasing.sample = 0; -} - void OVERLAY_antialiasing_init(OVERLAY_Data *vedata) { OVERLAY_FramebufferList *fbl = vedata->fbl; diff --git a/source/blender/draw/engines/overlay/overlay_engine.c b/source/blender/draw/engines/overlay/overlay_engine.c index e83a5c04eaf..24e2c4441e3 100644 --- a/source/blender/draw/engines/overlay/overlay_engine.c +++ b/source/blender/draw/engines/overlay/overlay_engine.c @@ -50,37 +50,27 @@ static void OVERLAY_engine_init(void *vedata) } OVERLAY_PrivateData *pd = stl->pd; - View3DOverlay overlay; - short v3d_flag, v3d_gridflag; pd->hide_overlays = (v3d->flag2 & V3D_HIDE_OVERLAYS) != 0; pd->ctx_mode = CTX_data_mode_enum_ex( draw_ctx->object_edit, draw_ctx->obact, draw_ctx->object_mode); if (!pd->hide_overlays) { - overlay = v3d->overlay; - v3d_flag = v3d->flag; - v3d_gridflag = v3d->gridflag; + pd->overlay = v3d->overlay; + pd->v3d_flag = v3d->flag; + pd->v3d_gridflag = v3d->gridflag; } else { - memset(&overlay, 0, sizeof(overlay)); - v3d_flag = 0; - v3d_gridflag = 0; - overlay.flag = V3D_OVERLAY_HIDE_TEXT | V3D_OVERLAY_HIDE_MOTION_PATHS | V3D_OVERLAY_HIDE_BONES | - V3D_OVERLAY_HIDE_OBJECT_XTRAS | V3D_OVERLAY_HIDE_OBJECT_ORIGINS; + memset(&pd->overlay, 0, sizeof(pd->overlay)); + pd->v3d_flag = 0; + pd->v3d_gridflag = 0; + pd->overlay.flag = V3D_OVERLAY_HIDE_TEXT | V3D_OVERLAY_HIDE_MOTION_PATHS | + V3D_OVERLAY_HIDE_BONES | V3D_OVERLAY_HIDE_OBJECT_XTRAS | + V3D_OVERLAY_HIDE_OBJECT_ORIGINS; } if (v3d->shading.type == OB_WIRE) { - overlay.flag |= V3D_OVERLAY_WIREFRAMES; - } - - /* Check if anything changed, and if so, reset AA. */ - if (v3d_flag != pd->v3d_flag || pd->v3d_gridflag != v3d_gridflag || - memcmp(&pd->overlay, &overlay, sizeof(overlay))) { - pd->overlay = overlay; - pd->v3d_flag = v3d_flag; - pd->v3d_gridflag = v3d_gridflag; - OVERLAY_antialiasing_reset(vedata); + pd->overlay.flag |= V3D_OVERLAY_WIREFRAMES; } pd->wireframe_mode = (v3d->shading.type == OB_WIRE); @@ -376,6 +366,9 @@ static void OVERLAY_draw_scene(void *vedata) OVERLAY_antialiasing_start(vedata); + DRW_view_set_active(NULL); + OVERLAY_outline_draw(vedata); + DRW_view_set_active(pd->view_default); OVERLAY_image_draw(vedata); @@ -387,9 +380,7 @@ static void OVERLAY_draw_scene(void *vedata) OVERLAY_extra_draw(vedata); DRW_view_set_active(NULL); - OVERLAY_grid_draw(vedata); - OVERLAY_outline_draw(vedata); DRW_view_set_active(pd->view_default); diff --git a/source/blender/draw/engines/overlay/overlay_outline.c b/source/blender/draw/engines/overlay/overlay_outline.c index cb5344630c3..706dcc95288 100644 --- a/source/blender/draw/engines/overlay/overlay_outline.c +++ b/source/blender/draw/engines/overlay/overlay_outline.c @@ -32,23 +32,28 @@ void OVERLAY_outline_init(OVERLAY_Data *vedata) { OVERLAY_FramebufferList *fbl = vedata->fbl; OVERLAY_TextureList *txl = vedata->txl; + OVERLAY_PrivateData *pd = vedata->stl->pd; + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); if (DRW_state_is_fbo()) { /* TODO only alloc if needed. */ - /* XXX TODO GPU_R16UI can overflow, it would cause no harm - * (only bad colored or missing outlines) but we should - * use 32bits only if the scene have that many objects */ DRW_texture_ensure_fullscreen_2d(&txl->temp_depth_tx, GPU_DEPTH24_STENCIL8, 0); DRW_texture_ensure_fullscreen_2d(&txl->outlines_id_tx, GPU_R16UI, 0); + GPU_framebuffer_ensure_config( &fbl->outlines_prepass_fb, {GPU_ATTACHMENT_TEXTURE(txl->temp_depth_tx), GPU_ATTACHMENT_TEXTURE(txl->outlines_id_tx)}); - for (int i = 0; i < 2; i++) { - DRW_texture_ensure_fullscreen_2d(&txl->outlines_color_tx[i], GPU_RGBA8, DRW_TEX_FILTER); + if (pd->antialiasing.enabled) { + GPU_framebuffer_ensure_config(&fbl->outlines_resolve_fb, + {GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(txl->overlay_color_tx), + GPU_ATTACHMENT_TEXTURE(txl->overlay_line_tx)}); + } + else { GPU_framebuffer_ensure_config( - &fbl->outlines_process_fb[i], - {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->outlines_color_tx[i])}); + &fbl->outlines_resolve_fb, + {GPU_ATTACHMENT_TEXTURE(txl->temp_depth_tx), GPU_ATTACHMENT_TEXTURE(dtxl->color)}); } } } @@ -133,9 +138,8 @@ void OVERLAY_outline_cache_init(OVERLAY_Data *vedata) DRWShadingGroup *grp = NULL; const float outline_width = UI_GetThemeValuef(TH_OUTLINE_WIDTH); - const bool do_outline_expand = (U.pixelsize > 1.0) || (outline_width > 2.0f); - const bool do_large_expand = ((U.pixelsize > 1.0) && (outline_width > 2.0f)) || - (outline_width > 4.0f); + const bool do_expand = (U.pixelsize > 1.0) || (outline_width > 2.0f); + { DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; DRW_PASS_CREATE(psl->outlines_prepass_ps, state | pd->clipping_state); @@ -164,50 +168,22 @@ void OVERLAY_outline_cache_init(OVERLAY_Data *vedata) } { - DRW_PASS_CREATE(psl->outlines_detect_ps, DRW_STATE_WRITE_COLOR); - DRW_PASS_CREATE(psl->outlines_expand_ps, DRW_STATE_WRITE_COLOR); - DRW_PASS_CREATE(psl->outlines_bleed_ps, DRW_STATE_WRITE_COLOR); - DRW_PASS_CREATE(psl->outlines_resolve_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA); + /* We can only do alpha blending with lineOutput just after clearing the buffer. */ + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL; + DRW_PASS_CREATE(psl->outlines_detect_ps, state); - GPUShader *sh = OVERLAY_shader_outline_detect(pd->xray_enabled_and_not_wire); + GPUShader *sh = OVERLAY_shader_outline_detect(); grp = DRW_shgroup_create(sh, psl->outlines_detect_ps); /* Don't occlude the "outline" detection pass if in xray mode (too much flickering). */ - DRW_shgroup_uniform_float_copy(grp, "alphaOcclu", (pd->xray_enabled) ? 1.0f : 0.35f); + DRW_shgroup_uniform_float_copy(grp, "alphaOcclu", (pd->xray_enabled) ? 1.0f : 0.125f); + DRW_shgroup_uniform_bool_copy(grp, "doThickOutlines", do_expand); + DRW_shgroup_uniform_bool_copy(grp, "isXrayWires", pd->xray_enabled_and_not_wire); DRW_shgroup_uniform_texture_ref(grp, "outlineId", &txl->outlines_id_tx); - DRW_shgroup_uniform_texture_ref(grp, "outlineDepth", &txl->temp_depth_tx); DRW_shgroup_uniform_texture_ref(grp, "sceneDepth", &dtxl->depth); + DRW_shgroup_uniform_texture_ref(grp, "outlineDepth", &txl->temp_depth_tx); DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); DRW_shgroup_call_procedural_triangles(grp, NULL, 1); - - if (do_outline_expand) { - sh = OVERLAY_shader_outline_expand(do_large_expand); - grp = DRW_shgroup_create(sh, psl->outlines_expand_ps); - DRW_shgroup_uniform_texture_ref(grp, "outlineColor", &txl->outlines_color_tx[0]); - DRW_shgroup_uniform_bool_copy(grp, "doExpand", true); - DRW_shgroup_call_procedural_triangles(grp, NULL, 1); - - sh = OVERLAY_shader_outline_expand(false); - grp = DRW_shgroup_create(sh, psl->outlines_bleed_ps); - DRW_shgroup_uniform_texture_ref(grp, "outlineColor", &txl->outlines_color_tx[1]); - DRW_shgroup_uniform_bool_copy(grp, "doExpand", false); - DRW_shgroup_call_procedural_triangles(grp, NULL, 1); - } - else { - sh = OVERLAY_shader_outline_expand(false); - grp = DRW_shgroup_create(sh, psl->outlines_expand_ps); - DRW_shgroup_uniform_texture_ref(grp, "outlineColor", &txl->outlines_color_tx[0]); - DRW_shgroup_uniform_bool_copy(grp, "doExpand", false); - DRW_shgroup_call_procedural_triangles(grp, NULL, 1); - } - - GPUTexture **outline_tx = &txl->outlines_color_tx[do_outline_expand ? 0 : 1]; - sh = OVERLAY_shader_outline_resolve(); - - grp = DRW_shgroup_create(sh, psl->outlines_resolve_ps); - DRW_shgroup_uniform_texture_ref(grp, "outlineBluredColor", outline_tx); - DRW_shgroup_uniform_vec2_copy(grp, "rcpDimensions", DRW_viewport_invert_size_get()); - DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } } @@ -331,25 +307,13 @@ void OVERLAY_outline_draw(OVERLAY_Data *vedata) /* Render filled polygon on a separate framebuffer */ GPU_framebuffer_bind(fbl->outlines_prepass_fb); - GPU_framebuffer_clear_color_depth(fbl->outlines_prepass_fb, clearcol, 1.0f); + GPU_framebuffer_clear_color_depth_stencil(fbl->outlines_prepass_fb, clearcol, 1.0f, 0x00); DRW_draw_pass(psl->outlines_prepass_ps); /* Search outline pixels */ - GPU_framebuffer_bind(fbl->outlines_process_fb[0]); + GPU_framebuffer_bind(fbl->outlines_resolve_fb); DRW_draw_pass(psl->outlines_detect_ps); - /* Expand outline to form a 3px wide line */ - GPU_framebuffer_bind(fbl->outlines_process_fb[1]); - DRW_draw_pass(psl->outlines_expand_ps); - - /* Bleed color so the AA can do it's stuff */ - GPU_framebuffer_bind(fbl->outlines_process_fb[0]); - DRW_draw_pass(psl->outlines_bleed_ps); - - /* restore main framebuffer */ - GPU_framebuffer_bind(fbl->overlay_default_fb); - DRW_draw_pass(psl->outlines_resolve_ps); - DRW_stats_group_end(); } else if (DRW_state_is_select()) { diff --git a/source/blender/draw/engines/overlay/overlay_private.h b/source/blender/draw/engines/overlay/overlay_private.h index 6b030b65ac0..5b25a473528 100644 --- a/source/blender/draw/engines/overlay/overlay_private.h +++ b/source/blender/draw/engines/overlay/overlay_private.h @@ -35,16 +35,14 @@ typedef struct OVERLAY_FramebufferList { struct GPUFrameBuffer *overlay_color_only_fb; struct GPUFrameBuffer *overlay_in_front_fb; struct GPUFrameBuffer *outlines_prepass_fb; - struct GPUFrameBuffer *outlines_process_fb[2]; + struct GPUFrameBuffer *outlines_resolve_fb; } OVERLAY_FramebufferList; typedef struct OVERLAY_TextureList { struct GPUTexture *temp_depth_tx; struct GPUTexture *dummy_depth_tx; struct GPUTexture *outlines_id_tx; - struct GPUTexture *outlines_color_tx[2]; struct GPUTexture *overlay_color_tx; - struct GPUTexture *overlay_color_history_tx; struct GPUTexture *overlay_line_tx; struct GPUTexture *edit_mesh_occlude_wire_tx; } OVERLAY_TextureList; @@ -87,8 +85,6 @@ typedef struct OVERLAY_PassList { DRWPass *motion_paths_ps; DRWPass *outlines_prepass_ps; DRWPass *outlines_detect_ps; - DRWPass *outlines_expand_ps; - DRWPass *outlines_bleed_ps; DRWPass *outlines_resolve_ps; DRWPass *paint_color_ps; DRWPass *paint_overlay_ps; @@ -278,9 +274,6 @@ typedef struct OVERLAY_PrivateData { OVERLAY_ShadingData shdata; struct { - short sample; - short target_sample; - float prev_persmat[4][4]; bool enabled; } antialiasing; struct { @@ -388,7 +381,6 @@ BLI_INLINE void pack_fl_in_mat4(float rmat[4][4], const float mat[4][4], float a rmat[3][3] = a; } -void OVERLAY_antialiasing_reset(OVERLAY_Data *vedata); void OVERLAY_antialiasing_init(OVERLAY_Data *vedata); void OVERLAY_antialiasing_cache_init(OVERLAY_Data *vedata); void OVERLAY_antialiasing_cache_finish(OVERLAY_Data *vedata); @@ -562,9 +554,7 @@ GPUShader *OVERLAY_shader_motion_path_vert(void); GPUShader *OVERLAY_shader_uniform_color(void); GPUShader *OVERLAY_shader_outline_prepass(bool use_wire); GPUShader *OVERLAY_shader_outline_prepass_grid(void); -GPUShader *OVERLAY_shader_outline_resolve(void); -GPUShader *OVERLAY_shader_outline_expand(bool high_dpi); -GPUShader *OVERLAY_shader_outline_detect(bool use_wire); +GPUShader *OVERLAY_shader_outline_detect(void); GPUShader *OVERLAY_shader_paint_face(void); GPUShader *OVERLAY_shader_paint_point(void); GPUShader *OVERLAY_shader_paint_texture(void); diff --git a/source/blender/draw/engines/overlay/overlay_shader.c b/source/blender/draw/engines/overlay/overlay_shader.c index 3f702a00bcd..db1d97544c0 100644 --- a/source/blender/draw/engines/overlay/overlay_shader.c +++ b/source/blender/draw/engines/overlay/overlay_shader.c @@ -80,12 +80,10 @@ extern char datatoc_motion_path_line_vert_glsl[]; extern char datatoc_motion_path_line_geom_glsl[]; extern char datatoc_motion_path_point_vert_glsl[]; extern char datatoc_outline_detect_frag_glsl[]; -extern char datatoc_outline_expand_frag_glsl[]; extern char datatoc_outline_prepass_frag_glsl[]; extern char datatoc_outline_prepass_geom_glsl[]; extern char datatoc_outline_prepass_vert_glsl[]; extern char datatoc_outline_lightprobe_grid_vert_glsl[]; -extern char datatoc_outline_resolve_frag_glsl[]; extern char datatoc_paint_face_vert_glsl[]; extern char datatoc_paint_point_vert_glsl[]; extern char datatoc_paint_texture_frag_glsl[]; @@ -159,11 +157,7 @@ typedef struct OVERLAY_Shaders { GPUShader *outline_prepass; GPUShader *outline_prepass_wire; GPUShader *outline_prepass_lightprobe_grid; - GPUShader *outline_resolve; - GPUShader *outline_fade; - GPUShader *outline_fade_large; GPUShader *outline_detect; - GPUShader *outline_detect_wire; GPUShader *paint_face; GPUShader *paint_point; GPUShader *paint_texture; @@ -941,51 +935,19 @@ GPUShader *OVERLAY_shader_outline_prepass_grid(void) return sh_data->outline_prepass_lightprobe_grid; } -GPUShader *OVERLAY_shader_outline_resolve(void) +GPUShader *OVERLAY_shader_outline_detect(void) { OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; - if (!sh_data->outline_resolve) { - sh_data->outline_resolve = DRW_shader_create_with_lib(datatoc_common_fullscreen_vert_glsl, - NULL, - datatoc_outline_resolve_frag_glsl, - datatoc_common_fxaa_lib_glsl, - "#define FXAA_ALPHA\n" - "#define USE_FXAA\n"); - } - return sh_data->outline_resolve; -} - -GPUShader *OVERLAY_shader_outline_expand(bool high_dpi) -{ - OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; - if (high_dpi && !sh_data->outline_fade_large) { - sh_data->outline_fade_large = DRW_shader_create_fullscreen(datatoc_outline_expand_frag_glsl, - "#define LARGE_OUTLINE\n"); - } - else if (!sh_data->outline_fade) { - sh_data->outline_fade = DRW_shader_create_fullscreen(datatoc_outline_expand_frag_glsl, NULL); - } - return (high_dpi) ? sh_data->outline_fade_large : sh_data->outline_fade; -} - -GPUShader *OVERLAY_shader_outline_detect(bool use_wire) -{ - OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; - if (use_wire && !sh_data->outline_detect_wire) { - sh_data->outline_detect_wire = DRW_shader_create_with_lib(datatoc_common_fullscreen_vert_glsl, - NULL, - datatoc_outline_detect_frag_glsl, - datatoc_common_globals_lib_glsl, - "#define WIRE\n"); - } - else if (!sh_data->outline_detect) { - sh_data->outline_detect = DRW_shader_create_with_lib(datatoc_common_fullscreen_vert_glsl, - NULL, - datatoc_outline_detect_frag_glsl, - datatoc_common_globals_lib_glsl, - NULL); + if (!sh_data->outline_detect) { + sh_data->outline_detect = GPU_shader_create_from_arrays({ + .vert = (const char *[]){datatoc_common_fullscreen_vert_glsl, NULL}, + .frag = (const char *[]){datatoc_common_view_lib_glsl, + datatoc_common_globals_lib_glsl, + datatoc_outline_detect_frag_glsl, + NULL}, + }); } - return (use_wire) ? sh_data->outline_detect_wire : sh_data->outline_detect; + return sh_data->outline_detect; } GPUShader *OVERLAY_shader_paint_face(void) diff --git a/source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl b/source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl index 46a2afc42fd..386e6d9e141 100644 --- a/source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl @@ -96,6 +96,8 @@ void main() fragColor = texelFetch(colorTex, center_texel, 0); + bool original_col_has_alpha = fragColor.a < 1.0; + float depth = texelFetch(depthTex, center_texel, 0).r; float dist_raw = texelFetch(lineTex, center_texel, 0).b; @@ -138,7 +140,7 @@ void main() #if 1 /* Fix aliasing issue with really dense meshes and 1 pixel sized lines. */ - if (dist_raw > 0.0 && line_kernel < 0.45) { + if (!original_col_has_alpha && dist_raw > 0.0 && line_kernel < 0.45) { vec4 lines = vec4(neightbor_line0.z, neightbor_line1.z, neightbor_line2.z, neightbor_line3.z); /* Count number of line neighbors. */ float blend = dot(vec4(0.25), step(0.001, lines)); diff --git a/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl b/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl index 79c970adfe0..6b4d424c700 100644 --- a/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl @@ -1,86 +1,325 @@ -in vec4 uvcoordsvar; - -out vec4 FragColor; - +uniform float alphaOcclu; +uniform bool isXrayWires; +uniform bool doThickOutlines; uniform usampler2D outlineId; uniform sampler2D outlineDepth; uniform sampler2D sceneDepth; -uniform float alphaOcclu; +in vec4 uvcoordsvar; -void main() -{ - ivec2 texel = ivec2(gl_FragCoord.xy); +layout(location = 0) out vec4 fragColor; +layout(location = 1) out vec4 lineOutput; -#ifdef GPU_ARB_texture_gather - vec2 texel_size = 1.0 / vec2(textureSize(outlineId, 0).xy); - vec2 uv = ceil(gl_FragCoord.xy) * texel_size; +#define XPOS 1 +#define XNEG 2 +#define YPOS 4 +#define YNEG 8 + +#define ALL (XPOS | XNEG | YPOS | YNEG) +#define NONE 0 + +#define DIAG_XNEG_YPOS (XNEG | YPOS) +#define DIAG_XPOS_YPOS (XPOS | YPOS) +#define DIAG_XPOS_YNEG (XPOS | YNEG) +#define DIAG_XNEG_YNEG (XNEG | YNEG) - /* Samples order is CW starting from top left. */ - uvec4 tmp1 = textureGather(outlineId, uv - texel_size); - uvec4 tmp2 = textureGather(outlineId, uv); +#define APEX_XPOS (ALL & (~XPOS)) +#define APEX_XNEG (ALL & (~XNEG)) +#define APEX_YPOS (ALL & (~YPOS)) +#define APEX_YNEG (ALL & (~YNEG)) - uint ref_id = tmp1.y; - uvec4 id = uvec4(tmp1.xz, tmp2.xz); +bool has_edge(uint id, vec2 uv, uint ref, inout uint ref_col, inout vec2 depth_uv) +{ + if (ref_col == 0u) { + /* Make outline bleed on the background. */ + ref_col = id; + depth_uv = uv; + } + return (id != ref); +} + +/* A gather4 + check against ref. */ +bvec4 gather_edges(vec2 uv, uint ref) +{ + uvec4 ids; +#ifdef GPU_ARB_texture_gather + ids = textureGather(outlineId, uv); #else - uvec4 id; - uint ref_id = texelFetch(outlineId, texel, 0).r; - id.x = texelFetchOffset(outlineId, texel, 0, ivec2(-1, 0)).r; - id.y = texelFetchOffset(outlineId, texel, 0, ivec2(0, -1)).r; - id.z = texelFetchOffset(outlineId, texel, 0, ivec2(0, 1)).r; - id.w = texelFetchOffset(outlineId, texel, 0, ivec2(1, 0)).r; + vec3 ofs = vec3(0.5, 0.5, -0.5) * sizeViewportInv.xyy; + ids.x = textureLod(outlineId, uv - ofs.xz, 0.0).r; + ids.y = textureLod(outlineId, uv + ofs.xy, 0.0).r; + ids.z = textureLod(outlineId, uv + ofs.xz, 0.0).r; + ids.w = textureLod(outlineId, uv - ofs.xy, 0.0).r; #endif -#ifdef WIRE - /* We want only 2px outlines. */ - /* TODO optimize, don't sample if we don't need to. */ - id.xy = uvec2(ref_id); -#endif + return notEqual(ids, uvec4(ref)); +} + +/* Apply offset to line endpoint based on surrounding edges infos. */ +bool line_offset(bvec2 edges, vec2 ofs, inout vec2 line_point) +{ + if (all(edges.xy)) { + line_point.y -= ofs.y; + } + else if (!edges.x) { + line_point.y += ofs.y; + } + else /* !edges.y */ { + line_point.x += ofs.x; + return true; + } + return false; +} + +/* Changes Antialiasing pattern and makes line thicker. 0.0 is thin. */ +#define PROXIMITY_OFS -0.35 + +/* Use surrounding edges to approximate the outline direction to create smooth lines. */ +void straight_line_dir(bvec4 edges1, bvec4 edges2, out vec2 line_start, out vec2 line_end) +{ + line_end = vec2(1.5, 0.5 + PROXIMITY_OFS); + line_start = vec2(-line_end.x, line_end.y); + + vec2 line_ofs = vec2(1.0, 0.5); + if (line_offset(edges1.xw, line_ofs, line_end)) { + line_offset(edges1.yz, line_ofs, line_end); + } + line_ofs = vec2(-line_ofs.x, line_ofs.y); + if (line_offset(edges2.yz, line_ofs, line_start)) { + line_offset(edges2.xw, line_ofs, line_start); + } +} + +/* Compute line direction vector from the bottom left corner. */ +void diag_dir(bvec4 edges, out vec2 line_start, out vec2 line_end) +{ + /* TODO Improve diagonal antialiasing. */ + if (all(edges.wz)) { + line_start = vec2(-3.0, -0.5 + PROXIMITY_OFS); + line_end = vec2(3.0, 0.5 + PROXIMITY_OFS); + } + else if (all(not(edges.xw))) { + line_start = vec2(-0.5 - PROXIMITY_OFS, -3.0); + line_end = vec2(0.5 - PROXIMITY_OFS, 3.0); + } + else if (edges.w) { + line_start = vec2(-1.0, -0.5 - PROXIMITY_OFS); + line_end = vec2(2.0, 0.5 - PROXIMITY_OFS); + } + else { + line_start = vec2(-0.6, -0.5 + PROXIMITY_OFS); + line_end = vec2(0.6 - PROXIMITY_OFS, 0.5); + } +} +/* Clockwise */ +vec2 rotate_90(vec2 v) +{ + return vec2(v.y, -v.x); +} +vec2 rotate_180(vec2 v) +{ + return vec2(-v.x, -v.y); +} +vec2 rotate_270(vec2 v) +{ + return vec2(-v.y, v.x); +} - bool outline = any(notEqual(id, uvec4(ref_id))); +/* Counter-Clockwise */ +bvec4 rotate_90(bvec4 v) +{ + return v.yzwx; +} +bvec4 rotate_180(bvec4 v) +{ + return v.zwxy; +} +bvec4 rotate_270(bvec4 v) +{ + return v.wxyz; +} - ivec2 depth_texel = texel; - /* If texel is an outline but has no valid id ... - * replace id and depth texel by a valid one. - * This keeps the outline thickness consistent everywhere. */ - if (ref_id == 0u && outline) { - depth_texel = (id.x != 0u) ? texel + ivec2(-1, 0) : depth_texel; - depth_texel = (id.y != 0u) ? texel + ivec2(0, -1) : depth_texel; - depth_texel = (id.z != 0u) ? texel + ivec2(0, 1) : depth_texel; - depth_texel = (id.w != 0u) ? texel + ivec2(1, 0) : depth_texel; +void main() +{ + uint ref = textureLod(outlineId, uvcoordsvar.st, 0.0).r; + uint ref_col = ref; + + vec2 uvs = gl_FragCoord.xy * sizeViewportInv.xy; + vec3 ofs = vec3(1.0, 1.0, 0.0) * sizeViewportInv.xyy; - ref_id = (id.x != 0u) ? id.x : ref_id; - ref_id = (id.y != 0u) ? id.y : ref_id; - ref_id = (id.z != 0u) ? id.z : ref_id; - ref_id = (id.w != 0u) ? id.w : ref_id; + vec2 depth_uv = uvs; + + uvec4 ids; +#ifdef GPU_ARB_texture_gather + /* Reminder: Samples order is CW starting from top left. */ + uvec2 tmp1, tmp2, tmp3, tmp4; + if (doThickOutlines) { + tmp1 = textureGather(outlineId, uvs + ofs.xy * vec2(1.5, -0.5)).xy; + tmp2 = textureGather(outlineId, uvs + ofs.xy * vec2(-1.5, -0.5)).yx; + tmp3 = textureGather(outlineId, uvs + ofs.xy * vec2(0.5, 1.5)).wx; + tmp4 = textureGather(outlineId, uvs + ofs.xy * vec2(0.5, -1.5)).xw; + ids.x = tmp1.x; + ids.y = tmp2.x; + ids.z = tmp3.x; + ids.w = tmp4.x; } + else { + ids.xz = textureGather(outlineId, uvs + ofs.xy * 0.5).zx; + ids.yw = textureGather(outlineId, uvs - ofs.xy * 0.5).xz; + } +#else + ids.x = textureLod(outlineId, uvs + ofs.xz, 0.0).r; + ids.y = textureLod(outlineId, uvs - ofs.xz, 0.0).r; + ids.z = textureLod(outlineId, uvs + ofs.zy, 0.0).r; + ids.w = textureLod(outlineId, uvs - ofs.zy, 0.0).r; +#endif - float ref_depth = texelFetch(outlineDepth, depth_texel, 0).r; - float scene_depth = texelFetch(sceneDepth, depth_texel, 0).r; + bool has_edge_pos_x = has_edge(ids.x, uvs + ofs.xz, ref, ref_col, depth_uv); + bool has_edge_neg_x = has_edge(ids.y, uvs - ofs.xz, ref, ref_col, depth_uv); + bool has_edge_pos_y = has_edge(ids.z, uvs + ofs.zy, ref, ref_col, depth_uv); + bool has_edge_neg_y = has_edge(ids.w, uvs - ofs.zy, ref, ref_col, depth_uv); - /* Avoid bad cases of zfighting for occlusion only. */ - const float epsilon = 3.0 / 8388608.0; - bool occluded = (ref_depth > scene_depth + epsilon); + if (doThickOutlines) { + if (!any(bvec4(has_edge_pos_x, has_edge_neg_x, has_edge_pos_y, has_edge_neg_y))) { +#ifdef GPU_ARB_texture_gather + ids.x = tmp1.y; + ids.y = tmp2.y; + ids.z = tmp3.y; + ids.w = tmp4.y; +#else + ids.x = textureLod(outlineId, uvs + 2.0 * ofs.xz, 0.0).r; + ids.y = textureLod(outlineId, uvs - 2.0 * ofs.xz, 0.0).r; + ids.z = textureLod(outlineId, uvs + 2.0 * ofs.zy, 0.0).r; + ids.w = textureLod(outlineId, uvs - 2.0 * ofs.zy, 0.0).r; +#endif + + has_edge_pos_x = has_edge(ids.x, uvs + 2.0 * ofs.xz, ref, ref_col, depth_uv); + has_edge_neg_x = has_edge(ids.y, uvs - 2.0 * ofs.xz, ref, ref_col, depth_uv); + has_edge_pos_y = has_edge(ids.z, uvs + 2.0 * ofs.zy, ref, ref_col, depth_uv); + has_edge_neg_y = has_edge(ids.w, uvs - 2.0 * ofs.zy, ref, ref_col, depth_uv); + } + } + + if (isXrayWires) { + /* Don't inflate the wire outlines too much. */ + has_edge_neg_x = has_edge_neg_y = false; + } /* WATCH: Keep in sync with outlineId of the prepass. */ - uint color_id = ref_id >> 14u; - if (ref_id == 0u) { - FragColor = vec4(0.0); + uint color_id = ref_col >> 14u; + if (ref_col == 0u) { + fragColor = vec4(0.0); } else if (color_id == 1u) { - FragColor = colorSelect; + fragColor = colorSelect; } else if (color_id == 2u) { - FragColor = colorDupliSelect; + fragColor = colorDupliSelect; } else if (color_id == 3u) { - FragColor = colorActive; + fragColor = colorActive; } else { - FragColor = colorTransform; + fragColor = colorTransform; + } + + float ref_depth = textureLod(outlineDepth, depth_uv, 0.0).r; + float scene_depth = textureLod(sceneDepth, depth_uv, 0.0).r; + + /* Avoid bad cases of zfighting for occlusion only. */ + const float epsilon = 3.0 / 8388608.0; + bool occluded = (ref_depth > scene_depth + epsilon); + + /* NOTE: We never set alpha to 1.0 to avoid Antialiasing destroying the line. */ + fragColor *= (occluded) ? alphaOcclu : (254.0 / 255.0); + + float edge_case = 0.0; + edge_case += float(has_edge_pos_x) * 1.0; + edge_case += float(has_edge_neg_x) * 2.0; + edge_case += float(has_edge_pos_y) * 4.0; + edge_case += float(has_edge_neg_y) * 8.0; + + vec2 line_start, line_end; + vec2 line_ofs; + bvec4 extra_edges, extra_edges2; + /* TODO simplify this branching hell. */ + switch (int(edge_case)) { + /* Straight lines. */ + case YPOS: + extra_edges = gather_edges(uvs + sizeViewportInv.xy * vec2(2.5, 0.5), ref); + extra_edges2 = gather_edges(uvs + sizeViewportInv.xy * vec2(-2.5, 0.5), ref); + straight_line_dir(extra_edges, extra_edges2, line_start, line_end); + break; + case YNEG: + extra_edges = gather_edges(uvs + sizeViewportInv.xy * vec2(-2.5, -0.5), ref); + extra_edges2 = gather_edges(uvs + sizeViewportInv.xy * vec2(2.5, -0.5), ref); + extra_edges = rotate_180(extra_edges); + extra_edges2 = rotate_180(extra_edges2); + straight_line_dir(extra_edges, extra_edges2, line_start, line_end); + line_start = rotate_180(line_start); + line_end = rotate_180(line_end); + break; + case XPOS: + extra_edges = gather_edges(uvs + sizeViewportInv.xy * vec2(0.5, 2.5), ref); + extra_edges2 = gather_edges(uvs + sizeViewportInv.xy * vec2(0.5, -2.5), ref); + extra_edges = rotate_90(extra_edges); + extra_edges2 = rotate_90(extra_edges2); + straight_line_dir(extra_edges, extra_edges2, line_start, line_end); + line_start = rotate_90(line_start); + line_end = rotate_90(line_end); + break; + case XNEG: + extra_edges = gather_edges(uvs + sizeViewportInv.xy * vec2(-0.5, 2.5), ref); + extra_edges2 = gather_edges(uvs + sizeViewportInv.xy * vec2(-0.5, -2.5), ref); + extra_edges = rotate_270(extra_edges); + extra_edges2 = rotate_270(extra_edges2); + straight_line_dir(extra_edges, extra_edges2, line_start, line_end); + line_start = rotate_270(line_start); + line_end = rotate_270(line_end); + break; + + /* Diagonal */ + case DIAG_XNEG_YPOS: + extra_edges = gather_edges(uvs + ofs.xy * vec2(1.5), ref); + diag_dir(extra_edges, line_start, line_end); + break; + case DIAG_XPOS_YNEG: + extra_edges = gather_edges(uvs - ofs.xy * vec2(1.5), ref); + extra_edges = rotate_180(extra_edges); + diag_dir(extra_edges, line_start, line_end); + line_start = rotate_180(line_start); + line_end = rotate_180(line_end); + break; + case DIAG_XPOS_YPOS: + extra_edges = gather_edges(uvs + ofs.xy * vec2(1.5, -1.5), ref); + extra_edges = rotate_90(extra_edges); + diag_dir(extra_edges, line_start, line_end); + line_start = rotate_90(line_start); + line_end = rotate_90(line_end); + break; + case DIAG_XNEG_YNEG: + extra_edges = gather_edges(uvs - ofs.xy * vec2(1.5, -1.5), ref); + extra_edges = rotate_270(extra_edges); + diag_dir(extra_edges, line_start, line_end); + line_start = rotate_270(line_start); + line_end = rotate_270(line_end); + break; + + /* Apex */ + case APEX_XPOS: + case APEX_XNEG: + line_start = vec2(-0.5, 0.0); + line_end = vec2(0.5, 0.0); + break; + case APEX_YPOS: + case APEX_YNEG: + line_start = vec2(0.0, -0.5); + line_end = vec2(0.0, 0.5); + break; + default: + discard; } - FragColor.a *= (occluded) ? alphaOcclu : 1.0; - FragColor.a = (outline) ? FragColor.a : 0.0; + lineOutput = pack_line_data(vec2(0.0), line_start, line_end); } diff --git a/source/blender/draw/engines/overlay/shaders/outline_expand_frag.glsl b/source/blender/draw/engines/overlay/shaders/outline_expand_frag.glsl deleted file mode 100644 index cb9fe0e7c36..00000000000 --- a/source/blender/draw/engines/overlay/shaders/outline_expand_frag.glsl +++ /dev/null @@ -1,51 +0,0 @@ - -in vec4 uvcoordsvar; - -out vec4 FragColor; - -uniform sampler2D outlineColor; - -uniform float alpha; -uniform bool doExpand; - -void main() -{ - ivec2 uv = ivec2(gl_FragCoord.xy); - FragColor = texelFetch(outlineColor, uv, 0).rgba; - - vec4 color[4]; - color[0] = texelFetchOffset(outlineColor, uv, 0, ivec2(1, 0)).rgba; - color[1] = texelFetchOffset(outlineColor, uv, 0, ivec2(0, 1)).rgba; - color[2] = texelFetchOffset(outlineColor, uv, 0, ivec2(-1, 0)).rgba; - color[3] = texelFetchOffset(outlineColor, uv, 0, ivec2(0, -1)).rgba; - - vec4 values = vec4(color[0].a, color[1].a, color[2].a, color[3].a); - - vec4 tests = step(vec4(1e-6), values); /* (color.a != 0.0) */ - bvec4 btests = equal(tests, vec4(1.0)); - - if (FragColor.a != 0.0) { - return; - } - -#ifdef LARGE_OUTLINE - if (!any(btests)) { - color[0] = texelFetchOffset(outlineColor, uv, 0, ivec2(2, 0)).rgba; - color[1] = texelFetchOffset(outlineColor, uv, 0, ivec2(0, 2)).rgba; - color[2] = texelFetchOffset(outlineColor, uv, 0, ivec2(-2, 0)).rgba; - color[3] = texelFetchOffset(outlineColor, uv, 0, ivec2(0, -2)).rgba; - - values = vec4(color[0].a, color[1].a, color[2].a, color[3].a); - - tests = step(vec4(1e-6), values); /* (color.a != 0.0) */ - btests = equal(tests, vec4(1.0)); - } -#endif - - FragColor = (btests.x) ? color[0] : FragColor; - FragColor = (btests.y) ? color[1] : FragColor; - FragColor = (btests.z) ? color[2] : FragColor; - FragColor = (btests.w) ? color[3] : FragColor; - - FragColor.a *= (!doExpand) ? 0.0 : 1.0; -} diff --git a/source/blender/draw/engines/overlay/shaders/outline_resolve_frag.glsl b/source/blender/draw/engines/overlay/shaders/outline_resolve_frag.glsl deleted file mode 100644 index ba5d073a9c2..00000000000 --- a/source/blender/draw/engines/overlay/shaders/outline_resolve_frag.glsl +++ /dev/null @@ -1,21 +0,0 @@ - -in vec4 uvcoordsvar; - -out vec4 FragColor; - -uniform sampler2D outlineBluredColor; -uniform vec2 rcpDimensions; - -void main() -{ -#ifdef USE_FXAA - float aa_alpha = - FxaaPixelShader(uvcoordsvar.st, outlineBluredColor, rcpDimensions, 1.0, 0.166, 0.0833).r; -#endif - - FragColor = texture(outlineBluredColor, uvcoordsvar.st).rgba; - -#ifdef USE_FXAA - FragColor.a = aa_alpha; -#endif -} |