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
This commit is contained in:
Clément Foucault 2020-03-26 15:36:15 +01:00
parent 458f50ba73
commit e000dcb849
Notes: blender-bot 2023-11-21 19:25:15 +01:00
Referenced by issue #75958, Blender Crashes when an Object is selected after unchecking OpenGL Depth Picking
Referenced by issue #75112, GPencil – Crash When Selecting 2D Animation
Referenced by issue #75063, Wireframe Drawing Errors
Referenced by issue #74961, wireframe precision
Referenced by issue #73831, orthographic view wireframe regression on small scale mesh ( cm )
Referenced by pull request #114466, Overlay: Wireframe: avoid using custom depth bias with xray enabled
Referenced by commit 14500953ed, Overlay: Wireframe: avoid using custom depth bias with xray enabled
7 changed files with 96 additions and 27 deletions

View File

@ -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;

View File

@ -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);
}

View File

@ -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);

View File

@ -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)

View File

@ -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);
}

View File

@ -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
}

View File

@ -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;