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:
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
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue