diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2019-12-01 14:35:34 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2019-12-02 03:31:05 +0300 |
commit | 7164e63fefcfa26caf387a2ad04a8c51b533c32b (patch) | |
tree | 3951ac6ac451adecff68396f4925082a2d902e9b | |
parent | 915e54ee9db0894d9689cbef235b321885b04e62 (diff) |
Overlay Engine: Change Antialiasing implementation to a novel method!
19 files changed, 314 insertions, 283 deletions
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 667f56b47b5..9527c6c9612 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -340,6 +340,7 @@ data_to_c_simple(engines/overlay/shaders/edit_mesh_skin_root_vert.glsl SRC) data_to_c_simple(engines/overlay/shaders/edit_mesh_vert.glsl SRC) data_to_c_simple(engines/overlay/shaders/edit_particle_strand_vert.glsl SRC) data_to_c_simple(engines/overlay/shaders/edit_particle_point_vert.glsl SRC) +data_to_c_simple(engines/overlay/shaders/extra_frag.glsl SRC) data_to_c_simple(engines/overlay/shaders/extra_vert.glsl SRC) data_to_c_simple(engines/overlay/shaders/extra_groundline_vert.glsl SRC) data_to_c_simple(engines/overlay/shaders/extra_loose_point_frag.glsl SRC) diff --git a/source/blender/draw/engines/overlay/overlay_antialiasing.c b/source/blender/draw/engines/overlay/overlay_antialiasing.c index 779ec1035a3..54a598633fb 100644 --- a/source/blender/draw/engines/overlay/overlay_antialiasing.c +++ b/source/blender/draw/engines/overlay/overlay_antialiasing.c @@ -18,6 +18,40 @@ /** \file * \ingroup draw_engine + * + * Overlay antialiasing: + * + * Most of the overlays are wires which causes a lot of flickering in motions + * due to aliasing problems. + * + * Our goal is to have a technique that works with single sample per pixel + * to avoid extra cost of managing MSAA or additional texture buffers and jitters. + * + * To solve this we use a simple and effective post-process AA. The technique + * goes like this: + * + * - During wireframe rendering, we output the line color, the line direction + * and the distance from the line for the pixel center. + * + * - Then, in a post process pass, for each pixels we gather all lines in a search area + * that could cover (even partially) the center pixel. + * We compute the coverage of each line and do a sorted alpha compositing of them. + * + * This technique has one major shortcoming compared to MSAA: + * - It handles (initial) partial visibility poorly (because of single sample). This makes + * overlaping / crossing wires a bit too thin at their intersection. + * Wireframe meshes overlaid over solid meshes can have half of the edge missing due to + * z-fighting (this has workaround). + * Another manifestation of this, is fickering of really dense wireframe if using small + * line thickness (also has workaround). + * + * The pros of this approach are many: + * - Works without geometry shader. + * - Can inflate line thickness. + * - Coverage is very close to perfect and can even be filtered (Blackman-Harris, gaussian). + * - Wires can "bleed" / overlap non-line objects since the filter is in screenspace. + * - Only uses one additional lightweight fullscreen buffer (compared to MSAA/SMAA). + * - No convergence time (compared to TAA). */ #include "DRW_render.h" @@ -25,12 +59,6 @@ #include "ED_screen.h" #include "overlay_private.h" -#include "smaa_textures.h" - -struct { - GPUTexture *smaa_search_tx; - GPUTexture *smaa_area_tx; -} e_data = {NULL}; void OVERLAY_antialiasing_reset(OVERLAY_Data *vedata) { @@ -55,51 +83,12 @@ void OVERLAY_antialiasing_init(OVERLAY_Data *vedata) /* TODO Get real userpref option and remove MSAA buffer. */ pd->antialiasing.enabled = dtxl->multisample_color != NULL; - if (pd->antialiasing.enabled) { - - if (e_data.smaa_search_tx == NULL) { - e_data.smaa_search_tx = GPU_texture_create_nD(SEARCHTEX_WIDTH, - SEARCHTEX_HEIGHT, - 0, - 2, - searchTexBytes, - GPU_R8, - GPU_DATA_UNSIGNED_BYTE, - 0, - false, - NULL); - - e_data.smaa_area_tx = GPU_texture_create_nD(AREATEX_WIDTH, - AREATEX_HEIGHT, - 0, - 2, - areaTexBytes, - GPU_RG8, - GPU_DATA_UNSIGNED_BYTE, - 0, - false, - NULL); - GPU_texture_bind(e_data.smaa_area_tx, 0); - GPU_texture_filter_mode(e_data.smaa_area_tx, true); - GPU_texture_unbind(e_data.smaa_area_tx); - - GPU_texture_bind(e_data.smaa_search_tx, 0); - GPU_texture_filter_mode(e_data.smaa_search_tx, true); - GPU_texture_unbind(e_data.smaa_search_tx); - } + /* Use default view */ + pd->view_default = (DRWView *)DRW_view_default_get(); - pd->antialiasing.target_sample = 4; - - bool valid_history = true; - if (txl->overlay_color_history_tx == NULL || pd->antialiasing.sample == 0) { - valid_history = false; - } - - DRW_texture_ensure_fullscreen_2d(&txl->temp_depth_tx, GPU_DEPTH24_STENCIL8, 0); + if (pd->antialiasing.enabled) { DRW_texture_ensure_fullscreen_2d(&txl->overlay_color_tx, GPU_RGBA8, DRW_TEX_FILTER); - DRW_texture_ensure_fullscreen_2d(&txl->overlay_color_history_tx, GPU_RGBA8, DRW_TEX_FILTER); - DRW_texture_ensure_fullscreen_2d(&txl->smaa_edge_tx, GPU_RG8, DRW_TEX_FILTER); - DRW_texture_ensure_fullscreen_2d(&txl->smaa_blend_tx, GPU_RGBA8, DRW_TEX_FILTER); + DRW_texture_ensure_fullscreen_2d(&txl->overlay_line_tx, GPU_RGBA8, 0); GPU_framebuffer_ensure_config( &fbl->overlay_color_only_fb, @@ -107,63 +96,10 @@ void OVERLAY_antialiasing_init(OVERLAY_Data *vedata) GPU_framebuffer_ensure_config( &fbl->overlay_default_fb, {GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_TEXTURE(txl->overlay_color_tx)}); - GPU_framebuffer_ensure_config(&fbl->overlay_in_front_fb, - {GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front), - GPU_ATTACHMENT_TEXTURE(txl->overlay_color_tx)}); - - GPU_framebuffer_ensure_config( - &fbl->overlay_color_history_fb, - {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->overlay_color_history_tx)}); - GPU_framebuffer_ensure_config( - &fbl->smaa_edge_fb, - {GPU_ATTACHMENT_TEXTURE(txl->temp_depth_tx), GPU_ATTACHMENT_TEXTURE(txl->smaa_edge_tx)}); - GPU_framebuffer_ensure_config( - &fbl->smaa_blend_fb, - {GPU_ATTACHMENT_TEXTURE(txl->temp_depth_tx), GPU_ATTACHMENT_TEXTURE(txl->smaa_blend_tx)}); - - /* Test if we can do TAA */ - if (valid_history) { - float persmat[4][4]; - DRW_view_persmat_get(NULL, persmat, false); - valid_history = compare_m4m4(persmat, pd->antialiasing.prev_persmat, FLT_MIN); - copy_m4_m4(pd->antialiasing.prev_persmat, persmat); - } - - const DRWContextState *draw_ctx = DRW_context_state_get(); - if (valid_history && draw_ctx->evil_C != NULL) { - struct wmWindowManager *wm = CTX_wm_manager(draw_ctx->evil_C); - valid_history = (ED_screen_animation_no_scrub(wm) == NULL); - } - - if (valid_history) { - /* TAA */ - float persmat[4][4], viewmat[4][4], winmat[4][4]; - DRW_view_persmat_get(NULL, persmat, false); - DRW_view_viewmat_get(NULL, viewmat, false); - DRW_view_winmat_get(NULL, winmat, false); - - const float *viewport_size = DRW_viewport_size_get(); - int nr = min_ii(pd->antialiasing.sample, pd->antialiasing.target_sample); - /* x4 rotated grid. TODO(fclem) better patterns. */ - const float samples_pos[5][2] = {{0, 0}, {-2, -6}, {6, -2}, {-6, 2}, {2, 6}}; - /* For nr = 0,we should sample {0, 0} (goes through the FXAA branch). */ - float ofs[2] = {samples_pos[nr][0] / 6.0f, samples_pos[nr][1] / 6.0f}; - - // window_translate_m4(winmat, persmat, ofs[0] / viewport_size[0], ofs[1] / - // viewport_size[1]); - - const DRWView *default_view = DRW_view_default_get(); - pd->view_default = DRW_view_create_sub(default_view, viewmat, winmat); - - /* Avoid infinite sample count. */ - CLAMP_MAX(pd->antialiasing.sample, pd->antialiasing.target_sample + 1); - } - else { - /* FXAA */ - OVERLAY_antialiasing_reset(vedata); - /* Use default view */ - pd->view_default = (DRWView *)DRW_view_default_get(); - } + GPU_framebuffer_ensure_config(&fbl->overlay_line_fb, + {GPU_ATTACHMENT_TEXTURE(dtxl->depth), + GPU_ATTACHMENT_TEXTURE(txl->overlay_color_tx), + GPU_ATTACHMENT_TEXTURE(txl->overlay_line_tx)}); } else { /* Just a copy of the defaults framebuffers. */ @@ -173,11 +109,8 @@ void OVERLAY_antialiasing_init(OVERLAY_Data *vedata) &fbl->overlay_default_fb, {GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_TEXTURE(dtxl->color)}); GPU_framebuffer_ensure_config( - &fbl->overlay_in_front_fb, - {GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front), GPU_ATTACHMENT_TEXTURE(dtxl->color)}); - - /* Use default view */ - pd->view_default = (DRWView *)DRW_view_default_get(); + &fbl->overlay_line_fb, + {GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_TEXTURE(dtxl->color)}); } } @@ -191,33 +124,34 @@ void OVERLAY_antialiasing_cache_init(OVERLAY_Data *vedata) DRWShadingGroup *grp; if (pd->antialiasing.enabled) { - DRW_PASS_CREATE(psl->smaa_edge_detect_ps, - DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_ALWAYS); - DRW_PASS_CREATE(psl->smaa_blend_weight_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_STENCIL_EQUAL); - DRW_PASS_CREATE(psl->smaa_resolve_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL); + DRW_PASS_CREATE(psl->antialiasing_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL); - sh = OVERLAY_shader_antialiasing(0); - grp = DRW_shgroup_create(sh, psl->smaa_edge_detect_ps); + sh = OVERLAY_shader_antialiasing(); + grp = DRW_shgroup_create(sh, psl->antialiasing_ps); DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_texture_ref(grp, "depthTex", &dtxl->depth); DRW_shgroup_uniform_texture_ref(grp, "colorTex", &txl->overlay_color_tx); - DRW_shgroup_stencil_mask(grp, 0xFF); + DRW_shgroup_uniform_texture_ref(grp, "lineTex", &txl->overlay_line_tx); DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + } +} - sh = OVERLAY_shader_antialiasing(1); - grp = DRW_shgroup_create(sh, psl->smaa_blend_weight_ps); - DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_texture_ref(grp, "edgesTex", &txl->smaa_edge_tx); - DRW_shgroup_uniform_texture(grp, "areaTex", e_data.smaa_area_tx); - DRW_shgroup_uniform_texture(grp, "searchTex", e_data.smaa_search_tx); - DRW_shgroup_stencil_mask(grp, 0xFF); - DRW_shgroup_call_procedural_triangles(grp, NULL, 1); +void OVERLAY_antialiasing_cache_finish(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(); - sh = OVERLAY_shader_antialiasing(2); - grp = DRW_shgroup_create(sh, psl->smaa_resolve_ps); - DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); - DRW_shgroup_uniform_texture_ref(grp, "blendTex", &txl->smaa_blend_tx); - DRW_shgroup_uniform_texture_ref(grp, "colorTex", &txl->overlay_color_tx); - DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + if (pd->antialiasing.enabled) { + GPU_framebuffer_ensure_config(&fbl->overlay_in_front_fb, + {GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front), + GPU_ATTACHMENT_TEXTURE(txl->overlay_color_tx)}); + } + else { + GPU_framebuffer_ensure_config( + &fbl->overlay_in_front_fb, + {GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front), GPU_ATTACHMENT_TEXTURE(dtxl->color)}); } } @@ -228,8 +162,10 @@ void OVERLAY_antialiasing_start(OVERLAY_Data *vedata) if (pd->antialiasing.enabled) { float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + GPU_framebuffer_bind(fbl->overlay_line_fb); + GPU_framebuffer_clear_color(fbl->overlay_line_fb, clear_col); + GPU_framebuffer_bind(fbl->overlay_default_fb); - GPU_framebuffer_clear_color(fbl->overlay_default_fb, clear_col); } } @@ -237,28 +173,12 @@ void OVERLAY_antialiasing_end(OVERLAY_Data *vedata) { OVERLAY_PassList *psl = vedata->psl; OVERLAY_PrivateData *pd = vedata->stl->pd; - OVERLAY_FramebufferList *fbl = vedata->fbl; DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); if (pd->antialiasing.enabled) { - float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - - GPU_framebuffer_bind(fbl->smaa_edge_fb); - GPU_framebuffer_clear_color(fbl->smaa_edge_fb, clear_col); - GPU_framebuffer_clear_stencil(fbl->smaa_edge_fb, 0x00); - DRW_draw_pass(psl->smaa_edge_detect_ps); - - GPU_framebuffer_bind(fbl->smaa_blend_fb); - GPU_framebuffer_clear_color(fbl->smaa_blend_fb, clear_col); - DRW_draw_pass(psl->smaa_blend_weight_ps); + GPU_framebuffer_bind(dfbl->color_only_fb); + DRW_draw_pass(psl->antialiasing_ps); GPU_framebuffer_bind(dfbl->default_fb); - DRW_draw_pass(psl->smaa_resolve_ps); } } - -void OVERLAY_antialiasing_free(void) -{ - DRW_TEXTURE_FREE_SAFE(e_data.smaa_area_tx); - DRW_TEXTURE_FREE_SAFE(e_data.smaa_search_tx); -} diff --git a/source/blender/draw/engines/overlay/overlay_engine.c b/source/blender/draw/engines/overlay/overlay_engine.c index 8d3112fc38e..667172e5bb5 100644 --- a/source/blender/draw/engines/overlay/overlay_engine.c +++ b/source/blender/draw/engines/overlay/overlay_engine.c @@ -361,6 +361,7 @@ static void OVERLAY_cache_finish(void *vedata) {GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front), GPU_ATTACHMENT_TEXTURE(dtxl->color)}); } + OVERLAY_antialiasing_cache_finish(vedata); OVERLAY_armature_cache_finish(vedata); OVERLAY_image_cache_finish(vedata); } @@ -458,36 +459,6 @@ static void OVERLAY_draw_scene(void *vedata) static void OVERLAY_engine_free(void) { OVERLAY_shader_free(); - OVERLAY_antialiasing_free(); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Updates - * \{ */ - -static void OVERLAY_view_update(void *vedata) -{ - OVERLAY_Data *data = vedata; - if (data->stl && data->stl->pd) { - OVERLAY_antialiasing_reset(data); - } -} - -static void OVERLAY_id_update(void *vedata, ID *id) -{ - OVERLAY_Data *data = vedata; - if (data->stl && data->stl->pd) { - if (GS(id->name) == ID_OB) { - DrawData *dd = DRW_drawdata_ensure( - id, &draw_engine_overlay_type, sizeof(DrawData), NULL, NULL); - if (dd->recalc != 0) { - OVERLAY_antialiasing_reset(data); - dd->recalc = 0; - } - } - } } /** \} */ @@ -510,8 +481,8 @@ DrawEngineType draw_engine_overlay_type = { &OVERLAY_cache_finish, NULL, &OVERLAY_draw_scene, - &OVERLAY_view_update, - &OVERLAY_id_update, + NULL, + NULL, NULL, }; diff --git a/source/blender/draw/engines/overlay/overlay_extra.c b/source/blender/draw/engines/overlay/overlay_extra.c index f22a2984ac1..d088142bdef 100644 --- a/source/blender/draw/engines/overlay/overlay_extra.c +++ b/source/blender/draw/engines/overlay/overlay_extra.c @@ -1552,10 +1552,21 @@ void OVERLAY_extra_cache_populate(OVERLAY_Data *vedata, Object *ob) void OVERLAY_extra_draw(OVERLAY_Data *vedata) { + OVERLAY_FramebufferList *fbl = vedata->fbl; + OVERLAY_PrivateData *pd = vedata->stl->pd; OVERLAY_PassList *psl = vedata->psl; DRW_draw_pass(psl->extra_blend_ps); + + if (pd->antialiasing.enabled) { + GPU_framebuffer_bind(fbl->overlay_line_fb); + } + DRW_draw_pass(psl->extra_ps[0]); + + if (pd->antialiasing.enabled) { + GPU_framebuffer_bind(fbl->overlay_default_fb); + } } void OVERLAY_extra_in_front_draw(OVERLAY_Data *vedata) diff --git a/source/blender/draw/engines/overlay/overlay_private.h b/source/blender/draw/engines/overlay/overlay_private.h index f0991231dee..6b030b65ac0 100644 --- a/source/blender/draw/engines/overlay/overlay_private.h +++ b/source/blender/draw/engines/overlay/overlay_private.h @@ -30,12 +30,10 @@ #endif typedef struct OVERLAY_FramebufferList { - struct GPUFrameBuffer *smaa_blend_fb; - struct GPUFrameBuffer *smaa_edge_fb; struct GPUFrameBuffer *overlay_default_fb; + struct GPUFrameBuffer *overlay_line_fb; struct GPUFrameBuffer *overlay_color_only_fb; struct GPUFrameBuffer *overlay_in_front_fb; - struct GPUFrameBuffer *overlay_color_history_fb; struct GPUFrameBuffer *outlines_prepass_fb; struct GPUFrameBuffer *outlines_process_fb[2]; } OVERLAY_FramebufferList; @@ -47,8 +45,7 @@ typedef struct OVERLAY_TextureList { struct GPUTexture *outlines_color_tx[2]; struct GPUTexture *overlay_color_tx; struct GPUTexture *overlay_color_history_tx; - struct GPUTexture *smaa_edge_tx; - struct GPUTexture *smaa_blend_tx; + struct GPUTexture *overlay_line_tx; struct GPUTexture *edit_mesh_occlude_wire_tx; } OVERLAY_TextureList; @@ -56,9 +53,7 @@ typedef struct OVERLAY_TextureList { #define IN_FRONT 1 typedef struct OVERLAY_PassList { - DRWPass *smaa_edge_detect_ps; - DRWPass *smaa_blend_weight_ps; - DRWPass *smaa_resolve_ps; + DRWPass *antialiasing_ps; DRWPass *armature_ps[2]; DRWPass *armature_bone_select_ps; DRWPass *armature_transp_ps; @@ -396,9 +391,9 @@ BLI_INLINE void pack_fl_in_mat4(float rmat[4][4], const float mat[4][4], float 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); void OVERLAY_antialiasing_start(OVERLAY_Data *vedata); void OVERLAY_antialiasing_end(OVERLAY_Data *vedata); -void OVERLAY_antialiasing_free(void); bool OVERLAY_armature_is_pose_mode(Object *ob, const struct DRWContextState *draw_ctx); void OVERLAY_armature_cache_init(OVERLAY_Data *vedata); @@ -532,7 +527,7 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata, void OVERLAY_wireframe_draw(OVERLAY_Data *vedata); void OVERLAY_wireframe_in_front_draw(OVERLAY_Data *vedata); -GPUShader *OVERLAY_shader_antialiasing(int step); +GPUShader *OVERLAY_shader_antialiasing(void); GPUShader *OVERLAY_shader_armature_degrees_of_freedom(void); GPUShader *OVERLAY_shader_armature_envelope(bool use_outline); GPUShader *OVERLAY_shader_armature_shape(bool use_outline); diff --git a/source/blender/draw/engines/overlay/overlay_shader.c b/source/blender/draw/engines/overlay/overlay_shader.c index 35bc0290738..fa495d153e9 100644 --- a/source/blender/draw/engines/overlay/overlay_shader.c +++ b/source/blender/draw/engines/overlay/overlay_shader.c @@ -62,6 +62,7 @@ extern char datatoc_edit_mesh_analysis_vert_glsl[]; extern char datatoc_edit_mesh_analysis_frag_glsl[]; extern char datatoc_edit_particle_strand_vert_glsl[]; extern char datatoc_edit_particle_point_vert_glsl[]; +extern char datatoc_extra_frag_glsl[]; extern char datatoc_extra_vert_glsl[]; extern char datatoc_extra_groundline_vert_glsl[]; extern char datatoc_extra_loose_point_vert_glsl[]; @@ -118,7 +119,7 @@ extern char datatoc_common_globals_lib_glsl[]; extern char datatoc_common_view_lib_glsl[]; typedef struct OVERLAY_Shaders { - GPUShader *antialiasing[3]; + GPUShader *antialiasing; GPUShader *armature_dof; GPUShader *armature_envelope_outline; GPUShader *armature_envelope_solid; @@ -182,35 +183,23 @@ typedef struct OVERLAY_Shaders { static struct { OVERLAY_Shaders sh_data[GPU_SHADER_CFG_LEN]; -} e_data = {{{{NULL}}}}; +} e_data = {{{NULL}}}; -GPUShader *OVERLAY_shader_antialiasing(int step) +GPUShader *OVERLAY_shader_antialiasing(void) { OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; - if (!sh_data->antialiasing[step]) { - char defines[64]; - BLI_snprintf(defines, sizeof(defines), "#define STEP %d\n", step); - sh_data->antialiasing[step] = GPU_shader_create_from_arrays({ - .vert = (const char *[]){"#define SMAA_INCLUDE_VS 1\n", - "#define SMAA_INCLUDE_PS 0\n", - "#define SMAA_PRESET_ULTRA\n", - "#define SMAA_RT_METRICS (sizeViewport.zwxy)\n", - datatoc_common_globals_lib_glsl, - datatoc_common_smaa_lib_glsl, + if (!sh_data->antialiasing) { + sh_data->antialiasing = GPU_shader_create_from_arrays({ + .vert = (const char *[]){datatoc_common_globals_lib_glsl, datatoc_antialiasing_vert_glsl, NULL}, - .frag = (const char *[]){"#define SMAA_INCLUDE_VS 0\n", - "#define SMAA_INCLUDE_PS 1\n", - "#define SMAA_PRESET_ULTRA\n", - "#define SMAA_RT_METRICS (sizeViewport.zwxy)\n", - datatoc_common_globals_lib_glsl, - datatoc_common_smaa_lib_glsl, + .frag = (const char *[]){datatoc_common_globals_lib_glsl, datatoc_antialiasing_frag_glsl, NULL}, - .defs = (const char *[]){defines, "#define SMAA_GLSL_3\n", NULL}, + .defs = (const char *[]){NULL}, }); } - return sh_data->antialiasing[step]; + return sh_data->antialiasing; } GPUShader *OVERLAY_shader_depth_only(void) @@ -699,7 +688,7 @@ GPUShader *OVERLAY_shader_extra(void) datatoc_common_view_lib_glsl, datatoc_extra_vert_glsl, NULL}, - .frag = (const char *[]){datatoc_gpu_shader_flat_color_frag_glsl, NULL}, + .frag = (const char *[]){datatoc_common_view_lib_glsl, datatoc_extra_frag_glsl, NULL}, .defs = (const char *[]){sh_cfg->def, NULL}, }); } @@ -718,7 +707,7 @@ GPUShader *OVERLAY_shader_extra_groundline(void) datatoc_common_view_lib_glsl, datatoc_extra_groundline_vert_glsl, NULL}, - .frag = (const char *[]){datatoc_gpu_shader_flat_color_frag_glsl, NULL}, + .frag = (const char *[]){datatoc_common_view_lib_glsl, datatoc_extra_frag_glsl, NULL}, .defs = (const char *[]){sh_cfg->def, NULL}, }); } @@ -751,7 +740,7 @@ GPUShader *OVERLAY_shader_extra_wire(bool use_object) datatoc_common_view_lib_glsl, datatoc_extra_wire_vert_glsl, NULL}, - .frag = (const char *[]){datatoc_extra_wire_frag_glsl, NULL}, + .frag = (const char *[]){datatoc_common_view_lib_glsl, datatoc_extra_wire_frag_glsl, NULL}, .defs = (const char *[]){sh_cfg->def, colorids, (use_object) ? "#define OBJECT_WIRE \n" : NULL, @@ -1251,7 +1240,7 @@ GPUShader *OVERLAY_shader_wireframe(void) datatoc_gpu_shader_common_obinfos_lib_glsl, datatoc_wireframe_vert_glsl, NULL}, - .frag = (const char *[]){datatoc_wireframe_frag_glsl, NULL}, + .frag = (const char *[]){datatoc_common_view_lib_glsl, datatoc_wireframe_frag_glsl, NULL}, /* Apple drivers does not support wide wires. Use geometry shader as a workaround. */ #if USE_GEOM_SHADER_WORKAROUND .geom = (const char *[]){sh_cfg->lib, diff --git a/source/blender/draw/engines/overlay/overlay_wireframe.c b/source/blender/draw/engines/overlay/overlay_wireframe.c index 5a8b1d5c616..d86f524cb48 100644 --- a/source/blender/draw/engines/overlay/overlay_wireframe.c +++ b/source/blender/draw/engines/overlay/overlay_wireframe.c @@ -201,13 +201,22 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata, void OVERLAY_wireframe_draw(OVERLAY_Data *data) { + OVERLAY_FramebufferList *fbl = data->fbl; OVERLAY_PassList *psl = data->psl; OVERLAY_PrivateData *pd = data->stl->pd; + if (pd->antialiasing.enabled) { + GPU_framebuffer_bind(fbl->overlay_line_fb); + } + DRW_view_set_active(pd->view_wires); DRW_draw_pass(psl->wireframe_ps); DRW_view_set_active(pd->view_default); + + if (pd->antialiasing.enabled) { + GPU_framebuffer_bind(fbl->overlay_default_fb); + } } void OVERLAY_wireframe_in_front_draw(OVERLAY_Data *data) diff --git a/source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl b/source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl index aa7ef63e49b..98f69abe89f 100644 --- a/source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl @@ -1,48 +1,135 @@ -in vec2 uvs; - -#if STEP == 0 - uniform sampler2D colorTex; +uniform sampler2D depthTex; +uniform sampler2D lineTex; -in vec4 offsets[3]; +in vec2 uvs; out vec4 fragColor; -void main() +#define M_1_SQRTPI 0.5641895835477563 /* 1/sqrt(pi) */ + +/** + * We want to know how much a pixel is covered by a line. + * We replace the square pixel with acircle of the same area and try to find the intersection area. + * The area we search is the circular segment. https://en.wikipedia.org/wiki/Circular_segment + * The formula for the area uses inverse trig function and is quite complexe. Instead, + * we approximate it by using the smoothstep function and a 1.05 factor to the disc radius. + */ +#define DISC_RADIUS (M_1_SQRTPI * 1.05) +#define LINE_SMOOTH_START (0.5 - DISC_RADIUS) +#define LINE_SMOOTH_END (0.5 + DISC_RADIUS) + +/** + * Returns coverage of a line onto a sample that is distance_to_line (in pixels) far from the line. + * line_kernel_size is the inner size of the line with 100% coverage. + */ +float line_coverage(float distance_to_line, float line_kernel_size) { - fragColor = SMAALumaEdgeDetectionPS(uvs, offsets, colorTex).xyxy; + return smoothstep(LINE_SMOOTH_END, LINE_SMOOTH_START, abs(distance_to_line) - line_kernel_size); } - -#elif STEP == 1 - -uniform sampler2D edgesTex; -uniform sampler2D areaTex; -uniform sampler2D searchTex; - -in vec2 pixcoord; -in vec4 offsets[3]; - -out vec4 fragColor; - -void main() +vec4 line_coverage(vec4 distance_to_line, float line_kernel_size) { - fragColor = SMAABlendingWeightCalculationPS( - uvs, pixcoord, offsets, edgesTex, areaTex, searchTex, vec4(0)); + return smoothstep(LINE_SMOOTH_END, LINE_SMOOTH_START, abs(distance_to_line) - line_kernel_size); } -#elif STEP == 2 - -uniform sampler2D colorTex; -uniform sampler2D blendTex; +vec2 decode_line_dir(vec2 dir) +{ + return dir * 2.0 - 1.0; +} -in vec4 offset; +float decode_line_dist(float dist) +{ + return (dist - 0.1) * 4.0 - 2.0; +} -out vec4 fragColor; +float neighbor_dist(vec3 line_dir_and_dist, vec2 ofs) +{ + float dist = decode_line_dist(line_dir_and_dist.z); + vec2 dir = decode_line_dir(line_dir_and_dist.xy); + + bool is_line = line_dir_and_dist.z != 0.0; + bool dir_horiz = abs(dir.x) > abs(dir.y); + bool ofs_horiz = (ofs.x != 0); + + if (!is_line || (ofs_horiz != dir_horiz)) { + dist += 1e10; /* No line. */ + } + else { + dist += dot(ofs, -dir); + } + return dist; +} -void main() +void neighbor_blend( + float line_coverage, float line_depth, vec4 line_color, inout float frag_depth, inout vec4 col) { - fragColor = SMAANeighborhoodBlendingPS(uvs, offset, colorTex, blendTex); + line_color *= line_coverage; + if (line_coverage > 0.0 && line_depth < frag_depth) { + /* Alpha over. */ + col = col * (1.0 - line_color.a) + line_color; + frag_depth = line_depth; + } + else { + /* Alpha under. */ + col = col + line_color * (1.0 - col.a); + } } +void main() +{ + ivec2 center_texel = ivec2(gl_FragCoord.xy); + const float line_kernel = 0.0; + + fragColor = texelFetch(colorTex, center_texel, 0); + + float depth = texelFetch(depthTex, center_texel, 0).r; + + float dist_raw = texelFetch(lineTex, center_texel, 0).b; + float dist = decode_line_dist(dist_raw); + + /* TODO Opti: use textureGather */ + vec4 neightbor_col0 = texelFetchOffset(colorTex, center_texel, 0, ivec2(1, 0)); + vec4 neightbor_col1 = texelFetchOffset(colorTex, center_texel, 0, ivec2(-1, 0)); + vec4 neightbor_col2 = texelFetchOffset(colorTex, center_texel, 0, ivec2(0, 1)); + vec4 neightbor_col3 = texelFetchOffset(colorTex, center_texel, 0, ivec2(0, -1)); + + vec3 neightbor_line0 = texelFetchOffset(lineTex, center_texel, 0, ivec2(1, 0)).rgb; + vec3 neightbor_line1 = texelFetchOffset(lineTex, center_texel, 0, ivec2(-1, 0)).rgb; + vec3 neightbor_line2 = texelFetchOffset(lineTex, center_texel, 0, ivec2(0, 1)).rgb; + vec3 neightbor_line3 = texelFetchOffset(lineTex, center_texel, 0, ivec2(0, -1)).rgb; + + vec4 depths; + depths.x = texelFetchOffset(depthTex, center_texel, 0, ivec2(1, 0)).r; + depths.y = texelFetchOffset(depthTex, center_texel, 0, ivec2(-1, 0)).r; + depths.z = texelFetchOffset(depthTex, center_texel, 0, ivec2(0, 1)).r; + depths.w = texelFetchOffset(depthTex, center_texel, 0, ivec2(0, -1)).r; + + vec4 line_dists; + line_dists.x = neighbor_dist(neightbor_line0, vec2(1, 0)); + line_dists.y = neighbor_dist(neightbor_line1, vec2(-1, 0)); + line_dists.z = neighbor_dist(neightbor_line2, vec2(0, 1)); + line_dists.w = neighbor_dist(neightbor_line3, vec2(0, -1)); + + vec4 coverage = line_coverage(line_dists, line_kernel); + + if (dist_raw > 0.0) { + fragColor *= line_coverage(dist, line_kernel); + } + + /* We dont order fragments but use alpha over/alpha under based on current minimum frag depth. */ + neighbor_blend(coverage.x, depths.x, neightbor_col0, depth, fragColor); + neighbor_blend(coverage.y, depths.y, neightbor_col1, depth, fragColor); + neighbor_blend(coverage.z, depths.z, neightbor_col2, depth, fragColor); + neighbor_blend(coverage.w, depths.w, neightbor_col3, depth, fragColor); + +#if 1 + /* Fix aliasing issue with really dense meshes and 1 pixel sized lines. */ + if (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)); + fragColor = mix(fragColor, fragColor / fragColor.a, blend); + } #endif +}
\ No newline at end of file diff --git a/source/blender/draw/engines/overlay/shaders/antialiasing_vert.glsl b/source/blender/draw/engines/overlay/shaders/antialiasing_vert.glsl index 9ded3b6c6c5..4f3c36c7bd7 100644 --- a/source/blender/draw/engines/overlay/shaders/antialiasing_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/antialiasing_vert.glsl @@ -1,29 +1,11 @@ out vec2 uvs; -#if STEP == 1 -out vec2 pixcoord; -#endif - -#if STEP == 2 -out vec4 offset; -#else -out vec4 offsets[3]; -#endif - void main() { int v = gl_VertexID % 3; - float x = -1.0 + float((v & 1) << 2); - float y = -1.0 + float((v & 2) << 1); - gl_Position = vec4(x, y, 1.0, 1.0); - uvs = (gl_Position.xy * 0.5 + 0.5).xy; - -#if STEP == 0 - SMAAEdgeDetectionVS(uvs, offsets); -#elif STEP == 1 - SMAABlendingWeightCalculationVS(uvs, pixcoord, offsets); -#elif STEP == 2 - SMAANeighborhoodBlendingVS(uvs, offset); -#endif + float x = float((v & 1) << 2); + float y = float((v & 2) << 1); + gl_Position = vec4(x - 1.0, y - 1.0, 1.0, 1.0); + uvs = vec2(x, y) * 0.5; }
\ No newline at end of file diff --git a/source/blender/draw/engines/overlay/shaders/extra_frag.glsl b/source/blender/draw/engines/overlay/shaders/extra_frag.glsl new file mode 100644 index 00000000000..8a8ae8a9611 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/extra_frag.glsl @@ -0,0 +1,13 @@ + +noperspective in vec2 edgePos; +flat in vec2 edgeStart; +flat in vec4 finalColor; + +layout(location = 0) out vec4 fragColor; +layout(location = 1) out vec4 lineOutput; + +void main() +{ + fragColor = finalColor; + lineOutput = pack_line_data(gl_FragCoord.xy, edgeStart, edgePos); +}
\ No newline at end of file diff --git a/source/blender/draw/engines/overlay/shaders/extra_groundline_vert.glsl b/source/blender/draw/engines/overlay/shaders/extra_groundline_vert.glsl index 73630f2b945..4b08ea587d4 100644 --- a/source/blender/draw/engines/overlay/shaders/extra_groundline_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/extra_groundline_vert.glsl @@ -5,6 +5,8 @@ in vec3 pos; in vec3 inst_pos; flat out vec4 finalColor; +flat out vec2 edgeStart; +noperspective out vec2 edgePos; void main() { @@ -19,6 +21,9 @@ void main() gl_Position = point_world_to_ndc(world_pos); + /* Convert to screen position [0..sizeVp]. */ + edgePos = edgeStart = ((gl_Position.xy / gl_Position.w) * 0.5 + 0.5) * sizeViewport.xy; + #ifdef USE_WORLD_CLIP_PLANES world_clip_planes_calc_clip_distance(world_pos); #endif diff --git a/source/blender/draw/engines/overlay/shaders/extra_vert.glsl b/source/blender/draw/engines/overlay/shaders/extra_vert.glsl index d6799ea6aa7..a72c5adb691 100644 --- a/source/blender/draw/engines/overlay/shaders/extra_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/extra_vert.glsl @@ -43,6 +43,8 @@ in vec4 color; #define VCLASS_EMPTY_SIZE (1 << 14) flat out vec4 finalColor; +flat out vec2 edgeStart; +noperspective out vec2 edgePos; void main() { @@ -216,6 +218,9 @@ void main() gl_Position = point_world_to_ndc(world_pos); + /* Convert to screen position [0..sizeVp]. */ + edgePos = edgeStart = ((gl_Position.xy / gl_Position.w) * 0.5 + 0.5) * sizeViewport.xy; + #ifdef USE_WORLD_CLIP_PLANES world_clip_planes_calc_clip_distance(world_pos); #endif diff --git a/source/blender/draw/engines/overlay/shaders/extra_wire_frag.glsl b/source/blender/draw/engines/overlay/shaders/extra_wire_frag.glsl index 3281d0f8f9a..7e469aee18d 100644 --- a/source/blender/draw/engines/overlay/shaders/extra_wire_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/extra_wire_frag.glsl @@ -1,11 +1,10 @@ -uniform vec4 color; - noperspective in vec2 stipple_coord; flat in vec2 stipple_start; flat in vec4 finalColor; -out vec4 fragColor; +layout(location = 0) out vec4 fragColor; +layout(location = 1) out vec4 lineOutput; void main() { @@ -15,7 +14,15 @@ void main() const float dash_width = 6.0; const float dash_factor = 0.5; + lineOutput = pack_line_data(gl_FragCoord.xy, stipple_start, stipple_coord); + float dist = distance(stipple_start, stipple_coord); + + if (fragColor.a == 0.0) { + /* Disable stippling. */ + dist = 0.0; + } + fragColor.a = 1.0; if (fract(dist / dash_width) > dash_factor) { diff --git a/source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl index bd807bd2683..933b9d65a5f 100644 --- a/source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl @@ -9,8 +9,7 @@ flat out vec4 finalColor; vec2 screen_position(vec4 p) { - vec2 s = p.xy / p.w; - return s * sizeViewport.xy * 0.5; + return ((p.xy / p.w) * 0.5 + 0.5) * sizeViewport.xy; } void main() @@ -18,7 +17,7 @@ void main() vec3 world_pos = point_object_to_world(pos); gl_Position = point_world_to_ndc(world_pos); - stipple_coord = stipple_start = vec2(0.0); + stipple_coord = stipple_start = screen_position(gl_Position); #ifdef OBJECT_WIRE /* Extract data packed inside the unused mat4 members. */ @@ -27,10 +26,11 @@ void main() if (colorid == TH_CAMERA_PATH) { finalColor = colorCameraPath; + finalColor.a = 0.0; /* No Stipple */ } else { finalColor = color; - stipple_coord = stipple_start = screen_position(gl_Position); + finalColor.a = 1.0; /* Stipple */ } #endif diff --git a/source/blender/draw/engines/overlay/shaders/wireframe_frag.glsl b/source/blender/draw/engines/overlay/shaders/wireframe_frag.glsl index 287bed5b5aa..39d0012574c 100644 --- a/source/blender/draw/engines/overlay/shaders/wireframe_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/wireframe_frag.glsl @@ -1,11 +1,12 @@ -uniform vec3 wireColor; -uniform vec3 rimColor; - in vec3 finalColor; flat in float edgeSharpness; -out vec4 fragColor; +flat in vec2 edgeStart; +noperspective in vec2 edgePos; + +layout(location = 0) out vec4 fragColor; +layout(location = 1) out vec4 lineOutput; void main() { @@ -13,6 +14,7 @@ void main() discard; } + lineOutput = pack_line_data(gl_FragCoord.xy, edgeStart, edgePos); fragColor.rgb = finalColor; - fragColor.a = 1.0f; + fragColor.a = 1.0; } diff --git a/source/blender/draw/engines/overlay/shaders/wireframe_geom.glsl b/source/blender/draw/engines/overlay/shaders/wireframe_geom.glsl index 0cb06df0108..346c9d83a9e 100644 --- a/source/blender/draw/engines/overlay/shaders/wireframe_geom.glsl +++ b/source/blender/draw/engines/overlay/shaders/wireframe_geom.glsl @@ -10,11 +10,16 @@ in float edgeSharpness_g[]; #ifndef SELECT_EDGES out vec3 finalColor; flat out float edgeSharpness; + +flat out vec2 edgeStart; +noperspective out vec2 edgePos; #endif void do_vertex(const int i, float coord, vec2 offset) { #ifndef SELECT_EDGES + /* TODO */ + edgePos = edgeStart = vec2(0); edgeSharpness = edgeSharpness_g[i]; finalColor = finalColor_g[i]; #endif diff --git a/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl b/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl index 9b0a61b7bae..78ce8fd8a8f 100644 --- a/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl @@ -16,6 +16,10 @@ out vec3 finalColor_g; out float edgeSharpness_g; #else /* USE_GEOM */ + +flat out vec2 edgeStart; +noperspective out vec2 edgePos; + out vec3 finalColor; flat out float edgeSharpness; # define finalColor_g finalColor @@ -111,6 +115,11 @@ void main() vec3 wpos = point_object_to_world(pos); gl_Position = point_world_to_ndc(wpos); +#if !(defined(SELECT_EDGES) || defined(USE_GEOM)) + /* Convert to screen position [0..sizeVp]. */ + edgePos = edgeStart = ((gl_Position.xy / gl_Position.w) * 0.5 + 0.5) * sizeViewport.xy; +#endif + edgeSharpness_g = get_edge_sharpness(wd); vec3 rim_col, wire_col; diff --git a/source/blender/draw/intern/shaders/common_smaa_lib.glsl b/source/blender/draw/intern/shaders/common_smaa_lib.glsl index 73813083114..09b573d4bb5 100644 --- a/source/blender/draw/intern/shaders/common_smaa_lib.glsl +++ b/source/blender/draw/intern/shaders/common_smaa_lib.glsl @@ -319,7 +319,7 @@ # define SMAA_THRESHOLD 0.05 # define SMAA_MAX_SEARCH_STEPS 32 # define SMAA_MAX_SEARCH_STEPS_DIAG 16 -# define SMAA_CORNER_ROUNDING 50 +# define SMAA_CORNER_ROUNDING 25 #endif //----------------------------------------------------------------------------- diff --git a/source/blender/draw/intern/shaders/common_view_lib.glsl b/source/blender/draw/intern/shaders/common_view_lib.glsl index 2f2125ad813..1a28a307163 100644 --- a/source/blender/draw/intern/shaders/common_view_lib.glsl +++ b/source/blender/draw/intern/shaders/common_view_lib.glsl @@ -48,6 +48,26 @@ mat4 extract_matrix_packed_data(mat4 mat, out vec4 dataA, out vec4 dataB) return mat; } +/* Same here, Not the right place but need to be common to all overlay's. + * TODO Split to an overlay lib. */ +/* edge_start and edge_pos needs to be in the range [0..sizeViewport]. */ +vec4 pack_line_data(vec2 frag_co, vec2 edge_start, vec2 edge_pos) +{ + vec2 edge = edge_start - edge_pos; + float len = length(edge); + if (len > 0.0) { + edge /= len; + vec2 perp = vec2(-edge.y, edge.x); + float dist = dot(perp, frag_co - edge_start); + /* Add 0.1 to diffenrentiate with cleared pixels. */ + return vec4(perp * 0.5 + 0.5, dist * 0.25 + 0.5 + 0.1, 0.0); + } + else { + /* Default line if the origin is perfectly aligned with a pixel. */ + return vec4(1.0, 0.0, 0.5 + 0.1, 0.0); + } +} + uniform int resourceChunk; #ifdef GPU_VERTEX_SHADER |