Fix T65755 "In Front" (X-Ray) doesn't work with wire objects

We fix by separating the drawing of wire xray objects.

These wire objects gets drawn before normal wires and set the stencil to
0x0 just like the solid counterparts. Also a prepass is done to "dig"
through non-xray solid.
This commit is contained in:
Clément Foucault 2019-06-24 12:42:04 +02:00
parent bf1b00212a
commit e47ce1f2d6
Notes: blender-bot 2023-02-14 02:13:08 +01:00
Referenced by issue #65755, "In Front" (X-Ray) doesn't work with wire objects
3 changed files with 66 additions and 58 deletions

View File

@ -1268,14 +1268,14 @@ void workbench_deferred_draw_scene(WORKBENCH_Data *vedata)
DRW_draw_pass(psl->composite_pass);
}
/* In order to not draw on top of ghost objects, we clear the stencil
* to 0xFF and the ghost object to 0x00 and only draw overlays on top if
* stencil is not 0. */
GPU_framebuffer_bind(dfbl->depth_only_fb);
GPU_framebuffer_clear_stencil(dfbl->depth_only_fb, 0xFF);
/* TODO(fclem): only enable when needed (when there is overlays). */
if (GHOST_ENABLED(psl)) {
/* In order to not draw on top of ghost objects, we clear the stencil
* to 0xFF and the ghost object to 0x00 and only draw overlays on top if
* stencil is not 0. */
GPU_framebuffer_bind(dfbl->depth_only_fb);
GPU_framebuffer_clear_stencil(dfbl->depth_only_fb, 0xFF);
DRWState state = DRW_STATE_DEPTH_EQUAL | DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_ALWAYS;
DRW_pass_state_set(psl->ghost_prepass_pass, state);
DRW_pass_state_set(psl->ghost_prepass_hair_pass, state);

View File

@ -674,7 +674,7 @@ void workbench_forward_draw_background(WORKBENCH_Data *UNUSED(vedata))
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
DRW_stats_group_start("Clear depth");
GPU_framebuffer_bind(dfbl->default_fb);
GPU_framebuffer_clear_depth(dfbl->default_fb, clear_depth);
GPU_framebuffer_clear_depth_stencil(dfbl->default_fb, clear_depth, 0xFF);
DRW_stats_group_end();
}

View File

@ -59,6 +59,8 @@ typedef struct OVERLAY_StorageList {
typedef struct OVERLAY_PassList {
struct DRWPass *face_orientation_pass;
struct DRWPass *face_wireframe_pass;
struct DRWPass *face_wireframe_only_pass;
struct DRWPass *face_wireframe_xray_pass;
} OVERLAY_PassList;
typedef struct OVERLAY_Data {
@ -72,11 +74,12 @@ typedef struct OVERLAY_Data {
typedef struct OVERLAY_PrivateData {
DRWShadingGroup *face_orientation_shgrp;
DRWShadingGroup *face_wires_shgrp;
DRWShadingGroup *face_wires_xray_shgrp;
DRWView *view_wires;
BLI_mempool *wire_color_mempool;
View3DOverlay overlay;
float wire_step_param;
bool ghost_stencil_test;
bool clear_stencil;
bool show_overlays;
} OVERLAY_PrivateData; /* Transient data */
@ -117,7 +120,8 @@ static void overlay_engine_init(void *vedata)
/* Alloc transient pointers */
stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__);
}
stl->g_data->ghost_stencil_test = false;
stl->g_data->clear_stencil = (draw_ctx->v3d->shading.type > OB_SOLID);
const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
@ -169,6 +173,13 @@ static void overlay_engine_init(void *vedata)
stl->g_data->view_wires = DRW_view_create_with_zoffset(draw_ctx->rv3d, 0.5f);
}
static void geometry_shader_uniforms(DRWShadingGroup *shgrp)
{
DRW_shgroup_uniform_float_copy(shgrp, "wireSize", U.pixelsize * 0.5f);
DRW_shgroup_uniform_vec2(shgrp, "viewportSize", DRW_viewport_size_get(), 1);
DRW_shgroup_uniform_vec2(shgrp, "viewportSizeInv", DRW_viewport_invert_size_get(), 1);
}
static void overlay_cache_init(void *vedata)
{
OVERLAY_Data *data = vedata;
@ -215,27 +226,28 @@ static void overlay_cache_init(void *vedata)
{
/* Wireframe */
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS |
DRW_STATE_FIRST_VERTEX_CONVENTION;
float wire_size = U.pixelsize * 0.5f;
const bool use_select = (DRW_state_is_select() || DRW_state_is_depth());
GPUShader *face_wires_sh = use_select ? sh_data->select_wireframe : sh_data->face_wireframe;
psl->face_wireframe_pass = DRW_pass_create("Face Wires", state);
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL |
DRW_STATE_STENCIL_EQUAL | DRW_STATE_FIRST_VERTEX_CONVENTION;
psl->face_wireframe_pass = DRW_pass_create("Wires", state);
g_data->face_wires_shgrp = DRW_shgroup_create(face_wires_sh, psl->face_wireframe_pass);
DRW_shgroup_uniform_float(
g_data->face_wires_shgrp, "wireStepParam", &g_data->wire_step_param, 1);
DRWState state_xray = DRW_STATE_WRITE_DEPTH | DRW_STATE_WRITE_STENCIL |
DRW_STATE_DEPTH_GREATER_EQUAL | DRW_STATE_STENCIL_NEQUAL |
DRW_STATE_FIRST_VERTEX_CONVENTION;
psl->face_wireframe_xray_pass = DRW_pass_create("Wires Only Xray", state_xray);
g_data->face_wires_xray_shgrp = DRW_shgroup_create(face_wires_sh,
psl->face_wireframe_xray_pass);
if (use_select || USE_GEOM_SHADER_WORKAROUND) {
DRW_shgroup_uniform_float_copy(g_data->face_wires_shgrp, "wireSize", wire_size);
DRW_shgroup_uniform_vec2(
g_data->face_wires_shgrp, "viewportSize", DRW_viewport_size_get(), 1);
DRW_shgroup_uniform_vec2(
g_data->face_wires_shgrp, "viewportSizeInv", DRW_viewport_invert_size_get(), 1);
geometry_shader_uniforms(g_data->face_wires_shgrp);
geometry_shader_uniforms(g_data->face_wires_xray_shgrp);
}
if (rv3d->rflag & RV3D_CLIPPING) {
DRW_shgroup_state_enable(g_data->face_wires_shgrp, DRW_STATE_CLIP_PLANES);
DRW_shgroup_state_enable(g_data->face_wires_xray_shgrp, DRW_STATE_CLIP_PLANES);
}
g_data->wire_step_param = stl->g_data->overlay.wireframe_threshold - 254.0f / 255.0f;
@ -383,19 +395,21 @@ static void overlay_cache_populate(void *vedata, Object *ob)
const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d);
const bool all_wires = (ob->dtx & OB_DRAW_ALL_EDGES);
const bool is_wire = (ob->dt < OB_SOLID);
const bool is_xray = (ob->dtx & OB_DRAWXRAY);
const bool use_coloring = (pd->show_overlays && !is_edit_mode && !use_sculpt_pbvh &&
!has_edit_mesh_cage);
const int stencil_mask = (ob->dtx & OB_DRAWXRAY) ? 0x00 : 0xFF;
float *rim_col, *wire_col;
DRWShadingGroup *shgrp = NULL;
overlay_wire_color_get(v3d, pd, ob, use_coloring, &rim_col, &wire_col);
struct GPUBatch *geom;
geom = DRW_cache_object_face_wireframe_get(ob);
if (geom || use_sculpt_pbvh) {
shgrp = DRW_shgroup_create_sub(pd->face_wires_shgrp);
if (is_wire && is_xray) {
shgrp = DRW_shgroup_create_sub(pd->face_wires_xray_shgrp);
}
else {
shgrp = DRW_shgroup_create_sub(pd->face_wires_shgrp);
}
float wire_step_param = 10.0f;
if (!use_sculpt_pbvh) {
@ -404,9 +418,12 @@ static void overlay_cache_populate(void *vedata, Object *ob)
DRW_shgroup_uniform_float_copy(shgrp, "wireStepParam", wire_step_param);
if (!(DRW_state_is_select() || DRW_state_is_depth())) {
DRW_shgroup_stencil_mask(shgrp, stencil_mask);
float *rim_col, *wire_col;
overlay_wire_color_get(v3d, pd, ob, use_coloring, &rim_col, &wire_col);
DRW_shgroup_uniform_vec3(shgrp, "wireColor", wire_col, 1);
DRW_shgroup_uniform_vec3(shgrp, "rimColor", rim_col, 1);
DRW_shgroup_stencil_mask(shgrp,
(is_xray && (is_wire || !pd->clear_stencil)) ? 0x00 : 0xFF);
}
if (use_sculpt_pbvh) {
@ -421,35 +438,6 @@ static void overlay_cache_populate(void *vedata, Object *ob)
(*dupli_data)->shgrp = shgrp;
(*dupli_data)->geom = geom;
}
if (is_wire && shgrp != NULL) {
/* If object is wireframe, don't try to use stencil test. */
DRW_shgroup_state_disable(shgrp, DRW_STATE_STENCIL_EQUAL);
if (ob->dtx & OB_DRAWXRAY) {
DRW_shgroup_state_disable(shgrp, DRW_STATE_DEPTH_LESS_EQUAL);
}
}
else if ((ob->dtx & OB_DRAWXRAY) && shgrp != NULL) {
pd->ghost_stencil_test = true;
}
}
}
}
static void overlay_cache_finish(void *vedata)
{
OVERLAY_Data *data = vedata;
OVERLAY_PassList *psl = data->psl;
OVERLAY_StorageList *stl = data->stl;
const DRWContextState *ctx = DRW_context_state_get();
View3D *v3d = ctx->v3d;
/* only in solid mode */
if (v3d->shading.type == OB_SOLID && !XRAY_FLAG_ENABLED(v3d)) {
if (stl->g_data->ghost_stencil_test) {
DRW_pass_state_add(psl->face_wireframe_pass, DRW_STATE_STENCIL_EQUAL);
}
}
}
@ -464,9 +452,18 @@ static void overlay_draw_scene(void *vedata)
if (DRW_state_is_fbo()) {
GPU_framebuffer_bind(dfbl->default_fb);
/* In material/rendered mode, Stencil has not be rendered correctly.
* Clear it to avoid problems.*/
if (stl->g_data->clear_stencil) {
GPU_framebuffer_clear_stencil(dfbl->default_fb, 0xFF);
}
}
DRW_draw_pass(psl->face_orientation_pass);
/* Do a depth prepass to lower the depth where the xray wire objects can pass through */
DRW_draw_pass(psl->face_wireframe_xray_pass);
/* This is replaced by the next code block */
// MULTISAMPLE_SYNC_ENABLE(dfbl, dtxl);
@ -479,9 +476,20 @@ static void overlay_draw_scene(void *vedata)
GPU_framebuffer_blit(
dfbl->default_fb, 0, dfbl->multisample_fb, 0, GPU_DEPTH_BIT | GPU_STENCIL_BIT);
DRW_stats_query_end();
/* Redo the prepass so we ge nice AA lines. */
DRW_draw_pass(psl->face_wireframe_xray_pass);
}
DRW_view_set_active(stl->g_data->view_wires);
DRW_pass_state_remove(psl->face_wireframe_xray_pass,
DRW_STATE_DEPTH_GREATER_EQUAL | DRW_STATE_STENCIL_NEQUAL);
DRW_pass_state_add(psl->face_wireframe_xray_pass,
DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL |
DRW_STATE_STENCIL_ALWAYS);
DRW_draw_pass(psl->face_wireframe_xray_pass);
DRW_draw_pass(psl->face_wireframe_pass);
DRW_view_set_active(NULL);
@ -519,7 +527,7 @@ DrawEngineType draw_engine_overlay_type = {
&overlay_engine_free,
&overlay_cache_init,
&overlay_cache_populate,
&overlay_cache_finish,
NULL,
NULL,
&overlay_draw_scene,
NULL,