From e000dcb8490880d6d49aa91588c457612685e9f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Thu, 26 Mar 2020 15:36:15 +0100 Subject: Overlay: Wireframe: New method to avoid zfighting with geometry This new method is only enabled if Overlay Smooth Wire is enabled. This method gives really nice results but has some downside: - Require a depth copy or loose the ability to write wire depth to the depth buffer and have correct depth ordering of wires. This patch use the former, with its associated cost. - Require some depth sampling and prevent early depth test (i.e: has some performance impact). - Has some relatively minor instability with geometry that are perpendicular to the view and intersecting with other geometry. Pros: - Compared to a fullpass approach this is surely going to have less performance impact and much higher quality. - Removes the additional vertex offset. (see T74961) - Fixes all half edges z-fighting. {F8428014} {F8428015} Reviewed By: brecht Differential Revision: https://developer.blender.org/D7233 --- .../draw/engines/overlay/overlay_antialiasing.c | 50 +++++++++++++++------- .../blender/draw/engines/overlay/overlay_engine.c | 2 + .../blender/draw/engines/overlay/overlay_private.h | 5 ++- .../blender/draw/engines/overlay/overlay_shader.c | 19 +++++--- .../draw/engines/overlay/overlay_wireframe.c | 8 +++- .../engines/overlay/shaders/wireframe_frag.glsl | 30 +++++++++++++ .../engines/overlay/shaders/wireframe_vert.glsl | 9 ++-- 7 files changed, 96 insertions(+), 27 deletions(-) (limited to 'source/blender/draw') diff --git a/source/blender/draw/engines/overlay/overlay_antialiasing.c b/source/blender/draw/engines/overlay/overlay_antialiasing.c index 0b7637aa098..e13d27032d5 100644 --- a/source/blender/draw/engines/overlay/overlay_antialiasing.c +++ b/source/blender/draw/engines/overlay/overlay_antialiasing.c @@ -113,16 +113,6 @@ void OVERLAY_antialiasing_init(OVERLAY_Data *vedata) GPU_ATTACHMENT_TEXTURE(color_tex), GPU_ATTACHMENT_TEXTURE(line_tex), }); - - if (pd->xray_enabled) { - DRW_texture_ensure_fullscreen_2d(&txl->temp_depth_tx, GPU_DEPTH24_STENCIL8, 0); - - GPU_framebuffer_ensure_config(&fbl->overlay_xray_depth_copy_fb, - { - GPU_ATTACHMENT_TEXTURE(txl->temp_depth_tx), - GPU_ATTACHMENT_NONE, - }); - } } void OVERLAY_antialiasing_cache_init(OVERLAY_Data *vedata) @@ -168,6 +158,7 @@ void OVERLAY_antialiasing_cache_finish(OVERLAY_Data *vedata) { OVERLAY_FramebufferList *fbl = vedata->fbl; OVERLAY_TextureList *txl = vedata->txl; + OVERLAY_PassList *psl = vedata->psl; OVERLAY_PrivateData *pd = vedata->stl->pd; DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); @@ -191,6 +182,22 @@ void OVERLAY_antialiasing_cache_finish(OVERLAY_Data *vedata) GPU_ATTACHMENT_TEXTURE(dtxl->color_overlay), GPU_ATTACHMENT_TEXTURE(txl->overlay_line_tx)}); } + + pd->antialiasing.do_depth_copy = !DRW_pass_is_empty(psl->wireframe_ps) || + (pd->xray_enabled && pd->xray_opacity > 0.0f); + pd->antialiasing.do_depth_infront_copy = !DRW_pass_is_empty(psl->wireframe_xray_ps); + + const bool do_wireframe = pd->antialiasing.do_depth_copy || + pd->antialiasing.do_depth_infront_copy; + if (pd->xray_enabled || do_wireframe) { + DRW_texture_ensure_fullscreen_2d(&txl->temp_depth_tx, GPU_DEPTH24_STENCIL8, 0); + + GPU_framebuffer_ensure_config(&fbl->overlay_xray_depth_copy_fb, + { + GPU_ATTACHMENT_TEXTURE(txl->temp_depth_tx), + GPU_ATTACHMENT_NONE, + }); + } } void OVERLAY_antialiasing_start(OVERLAY_Data *vedata) @@ -217,18 +224,31 @@ void OVERLAY_xray_depth_copy(OVERLAY_Data *vedata) OVERLAY_FramebufferList *fbl = vedata->fbl; OVERLAY_PrivateData *pd = vedata->stl->pd; + if (DRW_state_is_fbo() && pd->antialiasing.do_depth_copy) { + /* We copy the depth of the rendered geometry to be able to compare to the overlays depth. */ + GPU_framebuffer_blit( + fbl->overlay_default_fb, 0, fbl->overlay_xray_depth_copy_fb, 0, GPU_DEPTH_BIT); + } + if (DRW_state_is_fbo() && pd->xray_enabled) { - if (pd->xray_opacity > 0.0f) { - /* We copy the depth of the rendered geometry to be able to compare to the overlays depth. */ - GPU_framebuffer_blit( - fbl->overlay_default_fb, 0, fbl->overlay_xray_depth_copy_fb, 0, GPU_DEPTH_BIT); - } /* We then clear to not occlude the overlays directly. */ GPU_framebuffer_bind(fbl->overlay_default_fb); GPU_framebuffer_clear_depth(fbl->overlay_default_fb, 1.0f); } } +void OVERLAY_xray_depth_infront_copy(OVERLAY_Data *vedata) +{ + OVERLAY_FramebufferList *fbl = vedata->fbl; + OVERLAY_PrivateData *pd = vedata->stl->pd; + + if (DRW_state_is_fbo() && pd->antialiasing.do_depth_infront_copy) { + /* We copy the depth of the rendered geometry to be able to compare to the overlays depth. */ + GPU_framebuffer_blit( + fbl->overlay_in_front_fb, 0, fbl->overlay_xray_depth_copy_fb, 0, GPU_DEPTH_BIT); + } +} + void OVERLAY_xray_fade_draw(OVERLAY_Data *vedata) { OVERLAY_PassList *psl = vedata->psl; diff --git a/source/blender/draw/engines/overlay/overlay_engine.c b/source/blender/draw/engines/overlay/overlay_engine.c index adbcd3c7f28..97f6b91b7a9 100644 --- a/source/blender/draw/engines/overlay/overlay_engine.c +++ b/source/blender/draw/engines/overlay/overlay_engine.c @@ -466,6 +466,8 @@ static void OVERLAY_draw_scene(void *vedata) OVERLAY_xray_fade_draw(vedata); OVERLAY_grid_draw(vedata); + OVERLAY_xray_depth_infront_copy(vedata); + if (DRW_state_is_fbo()) { GPU_framebuffer_bind(fbl->overlay_line_in_front_fb); } diff --git a/source/blender/draw/engines/overlay/overlay_private.h b/source/blender/draw/engines/overlay/overlay_private.h index 7cc83c76857..bd9583c6a5f 100644 --- a/source/blender/draw/engines/overlay/overlay_private.h +++ b/source/blender/draw/engines/overlay/overlay_private.h @@ -293,6 +293,8 @@ typedef struct OVERLAY_PrivateData { struct { bool enabled; + bool do_depth_copy; + bool do_depth_infront_copy; } antialiasing; struct { bool show_handles; @@ -411,6 +413,7 @@ void OVERLAY_antialiasing_start(OVERLAY_Data *vedata); void OVERLAY_antialiasing_end(OVERLAY_Data *vedata); void OVERLAY_xray_fade_draw(OVERLAY_Data *vedata); void OVERLAY_xray_depth_copy(OVERLAY_Data *vedata); +void OVERLAY_xray_depth_infront_copy(OVERLAY_Data *vedata); bool OVERLAY_armature_is_pose_mode(Object *ob, const struct DRWContextState *draw_ctx); void OVERLAY_armature_cache_init(OVERLAY_Data *vedata); @@ -613,7 +616,7 @@ GPUShader *OVERLAY_shader_particle_shape(void); GPUShader *OVERLAY_shader_pointcloud_dot(void); GPUShader *OVERLAY_shader_sculpt_mask(void); GPUShader *OVERLAY_shader_volume_velocity(bool use_needle); -GPUShader *OVERLAY_shader_wireframe(void); +GPUShader *OVERLAY_shader_wireframe(bool custom_bias); GPUShader *OVERLAY_shader_wireframe_select(void); GPUShader *OVERLAY_shader_xray_fade(void); diff --git a/source/blender/draw/engines/overlay/overlay_shader.c b/source/blender/draw/engines/overlay/overlay_shader.c index 0b2f98294ec..8b70a0982af 100644 --- a/source/blender/draw/engines/overlay/overlay_shader.c +++ b/source/blender/draw/engines/overlay/overlay_shader.c @@ -192,7 +192,7 @@ typedef struct OVERLAY_Shaders { GPUShader *volume_velocity_needle_sh; GPUShader *volume_velocity_sh; GPUShader *wireframe_select; - GPUShader *wireframe; + GPUShader *wireframe[2]; GPUShader *xray_fade; } OVERLAY_Shaders; @@ -1372,24 +1372,29 @@ GPUShader *OVERLAY_shader_wireframe_select(void) return sh_data->wireframe_select; } -GPUShader *OVERLAY_shader_wireframe(void) +GPUShader *OVERLAY_shader_wireframe(bool custom_bias) { const DRWContextState *draw_ctx = DRW_context_state_get(); const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg]; OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - if (!sh_data->wireframe) { - sh_data->wireframe = GPU_shader_create_from_arrays({ + if (!sh_data->wireframe[custom_bias]) { + sh_data->wireframe[custom_bias] = GPU_shader_create_from_arrays({ .vert = (const char *[]){sh_cfg->lib, datatoc_common_view_lib_glsl, datatoc_common_globals_lib_glsl, datatoc_gpu_shader_common_obinfos_lib_glsl, datatoc_wireframe_vert_glsl, NULL}, - .frag = (const char *[]){datatoc_common_view_lib_glsl, datatoc_wireframe_frag_glsl, NULL}, - .defs = (const char *[]){sh_cfg->def, NULL}, + .frag = (const char *[]){datatoc_common_view_lib_glsl, + datatoc_common_globals_lib_glsl, + datatoc_wireframe_frag_glsl, + NULL}, + .defs = (const char *[]){sh_cfg->def, + custom_bias ? "#define CUSTOM_DEPTH_BIAS\n" : NULL, + NULL}, }); } - return sh_data->wireframe; + return sh_data->wireframe[custom_bias]; } GPUShader *OVERLAY_shader_xray_fade(void) diff --git a/source/blender/draw/engines/overlay/overlay_wireframe.c b/source/blender/draw/engines/overlay/overlay_wireframe.c index 17b412b143c..27f3f4ae9af 100644 --- a/source/blender/draw/engines/overlay/overlay_wireframe.c +++ b/source/blender/draw/engines/overlay/overlay_wireframe.c @@ -51,6 +51,7 @@ void OVERLAY_wireframe_init(OVERLAY_Data *vedata) void OVERLAY_wireframe_cache_init(OVERLAY_Data *vedata) { OVERLAY_PassList *psl = vedata->psl; + OVERLAY_TextureList *txl = vedata->txl; OVERLAY_PrivateData *pd = vedata->stl->pd; const DRWContextState *draw_ctx = DRW_context_state_get(); DRWShadingGroup *grp = NULL; @@ -66,12 +67,14 @@ void OVERLAY_wireframe_cache_init(OVERLAY_Data *vedata) const bool use_select = (DRW_state_is_select() || DRW_state_is_depth()); GPUShader *wires_sh = use_select ? OVERLAY_shader_wireframe_select() : - OVERLAY_shader_wireframe(); + OVERLAY_shader_wireframe(pd->antialiasing.enabled); for (int xray = 0; xray < (is_material_shmode ? 1 : 2); xray++) { DRWState state = DRW_STATE_FIRST_VERTEX_CONVENTION | DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; DRWPass *pass; + GPUTexture **depth_tx = (pd->xray_enabled || pd->xray_opacity > 0.0f) ? &txl->temp_depth_tx : + &txl->dummy_depth_tx; if (xray == 0) { DRW_PASS_CREATE(psl->wireframe_ps, state | pd->clipping_state); @@ -85,6 +88,7 @@ void OVERLAY_wireframe_cache_init(OVERLAY_Data *vedata) for (int use_coloring = 0; use_coloring < 2; use_coloring++) { pd->wires_grp[xray][use_coloring] = grp = DRW_shgroup_create(wires_sh, pass); DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_texture_ref(grp, "depthTex", depth_tx); DRW_shgroup_uniform_float_copy(grp, "wireStepParam", pd->shdata.wire_step_param); DRW_shgroup_uniform_bool_copy(grp, "useColoring", use_coloring); DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0); @@ -92,10 +96,12 @@ void OVERLAY_wireframe_cache_init(OVERLAY_Data *vedata) DRW_shgroup_uniform_bool_copy(grp, "isRandomColor", is_random_color); pd->wires_all_grp[xray][use_coloring] = grp = DRW_shgroup_create(wires_sh, pass); + DRW_shgroup_uniform_texture_ref(grp, "depthTex", depth_tx); DRW_shgroup_uniform_float_copy(grp, "wireStepParam", 1.0f); } pd->wires_sculpt_grp[xray] = grp = DRW_shgroup_create(wires_sh, pass); + DRW_shgroup_uniform_texture_ref(grp, "depthTex", depth_tx); DRW_shgroup_uniform_float_copy(grp, "wireStepParam", 10.0f); DRW_shgroup_uniform_bool_copy(grp, "useColoring", false); } diff --git a/source/blender/draw/engines/overlay/shaders/wireframe_frag.glsl b/source/blender/draw/engines/overlay/shaders/wireframe_frag.glsl index edfe720da0c..b5442dc1b0b 100644 --- a/source/blender/draw/engines/overlay/shaders/wireframe_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/wireframe_frag.glsl @@ -1,4 +1,7 @@ +/* Scene Depth texture copy for manual depth test. */ +uniform sampler2D depthTex; + flat in vec2 edgeStart; #ifndef SELECT_EDGES @@ -21,5 +24,32 @@ void main() lineOutput = pack_line_data(gl_FragCoord.xy, edgeStart, edgePos); fragColor.rgb = finalColor; fragColor.a = 1.0; + +# ifdef CUSTOM_DEPTH_BIAS + vec2 dir = lineOutput.xy * 2.0 - 1.0; + bool dir_horiz = abs(dir.x) > abs(dir.y); + + vec2 uv = gl_FragCoord.xy * sizeViewportInv.xy; + float depth_occluder = texture(depthTex, uv).r; + float depth_min = depth_occluder; + + if (dir_horiz) { + depth_min = min(depth_min, texture(depthTex, uv + vec2(-sizeViewportInv.x, 0.0)).r); + depth_min = min(depth_min, texture(depthTex, uv + vec2(sizeViewportInv.x, 0.0)).r); + } + else { + depth_min = min(depth_min, texture(depthTex, uv + vec2(0, -sizeViewportInv.y)).r); + depth_min = min(depth_min, texture(depthTex, uv + vec2(0, sizeViewportInv.y)).r); + } + + float delta = abs(depth_occluder - depth_min); + + if (gl_FragCoord.z < (depth_occluder + delta) && gl_FragCoord.z > depth_occluder) { + gl_FragDepth = depth_occluder; + } + else { + gl_FragDepth = gl_FragCoord.z; + } +# endif #endif } diff --git a/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl b/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl index 001c128e4ac..3fefe2cc0bf 100644 --- a/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl @@ -110,19 +110,22 @@ void main() vec3 V = (is_persp) ? normalize(ViewMatrixInverse[3].xyz - wpos) : ViewMatrixInverse[2].xyz; float facing = dot(wnor, V); + + gl_Position = point_world_to_ndc(wpos); + +#ifndef CUSTOM_DEPTH_BIAS float facing_ratio = clamp(1.0 - facing * facing, 0.0, 1.0); float flip = sign(facing); /* Flip when not facing the normal (i.e.: backfacing). */ float curvature = (1.0 - wd * 0.75); /* Avoid making things worse for curvy areas. */ vec3 wofs = wnor * (facing_ratio * curvature * flip); wofs = normal_world_to_view(wofs); - gl_Position = point_world_to_ndc(wpos); - /* Push vertex half a pixel (maximum) in normal direction. */ gl_Position.xy += wofs.xy * sizeViewportInv.xy * gl_Position.w; /* Push the vertex towards the camera. Helps a bit. */ - gl_Position.z -= facing_ratio * curvature * 1.0e-5 * gl_Position.w; + gl_Position.z -= facing_ratio * curvature * 1.0e-6 * gl_Position.w; +#endif /* Convert to screen position [0..sizeVp]. */ edgeStart = ((gl_Position.xy / gl_Position.w) * 0.5 + 0.5) * sizeViewport.xy; -- cgit v1.2.3