diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 74e772958f5..ec34e710c10 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -115,6 +115,7 @@ data_to_c_simple(modes/shaders/edit_overlay_facefill_vert.glsl SRC) data_to_c_simple(modes/shaders/edit_overlay_facefill_frag.glsl SRC) data_to_c_simple(modes/shaders/edit_normals_vert.glsl SRC) data_to_c_simple(modes/shaders/edit_normals_geom.glsl SRC) +data_to_c_simple(modes/shaders/object_occluded_outline_frag.glsl SRC) list(APPEND INC ) diff --git a/source/blender/draw/engines/clay/clay.c b/source/blender/draw/engines/clay/clay.c index a91027cb314..a40805a50c1 100644 --- a/source/blender/draw/engines/clay/clay.c +++ b/source/blender/draw/engines/clay/clay.c @@ -597,7 +597,11 @@ static DRWShadingGroup *CLAY_object_shgrp_get(Object *ob, CLAY_StorageList *stl, } static DRWShadingGroup *depth_shgrp; +static DRWShadingGroup *depth_shgrp_select; +static DRWShadingGroup *depth_shgrp_active; static DRWShadingGroup *depth_shgrp_cull; +static DRWShadingGroup *depth_shgrp_cull_select; +static DRWShadingGroup *depth_shgrp_cull_active; static void CLAY_cache_init(void) { @@ -607,11 +611,23 @@ static void CLAY_cache_init(void) /* Depth Pass */ { - psl->depth_pass_cull = DRW_pass_create("Depth Pass Cull", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_CULL_BACK); psl->depth_pass = DRW_pass_create("Depth Pass", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS); - - depth_shgrp_cull = DRW_shgroup_create(data.depth_sh, psl->depth_pass_cull); depth_shgrp = DRW_shgroup_create(data.depth_sh, psl->depth_pass); + + depth_shgrp_select = DRW_shgroup_create(data.depth_sh, psl->depth_pass); + DRW_shgroup_state_set(depth_shgrp_select, DRW_STATE_WRITE_STENCIL_SELECT); + + depth_shgrp_active = DRW_shgroup_create(data.depth_sh, psl->depth_pass); + DRW_shgroup_state_set(depth_shgrp_active, DRW_STATE_WRITE_STENCIL_ACTIVE); + + psl->depth_pass_cull = DRW_pass_create("Depth Pass Cull", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_CULL_BACK); + depth_shgrp_cull = DRW_shgroup_create(data.depth_sh, psl->depth_pass_cull); + + depth_shgrp_cull_select = DRW_shgroup_create(data.depth_sh, psl->depth_pass_cull); + DRW_shgroup_state_set(depth_shgrp_cull_select, DRW_STATE_WRITE_STENCIL_SELECT); + + depth_shgrp_cull_active = DRW_shgroup_create(data.depth_sh, psl->depth_pass_cull); + DRW_shgroup_state_set(depth_shgrp_cull_active, DRW_STATE_WRITE_STENCIL_ACTIVE); } /* Clay Pass */ @@ -642,7 +658,13 @@ static void CLAY_cache_populate(Object *ob) geom = DRW_cache_surface_get(ob); /* Depth Prepass */ - DRW_shgroup_call_add((do_cull) ? depth_shgrp_cull : depth_shgrp, geom, ob->obmat); + /* waiting for proper flag */ + // if ((ob->base_flag & BASE_ACTIVE) != 0) + // DRW_shgroup_call_add((do_cull) ? depth_shgrp_cull_active : depth_shgrp_active, geom, ob->obmat); + if ((ob->base_flag & BASE_SELECTED) != 0) + DRW_shgroup_call_add((do_cull) ? depth_shgrp_cull_select : depth_shgrp_select, geom, ob->obmat); + else + DRW_shgroup_call_add((do_cull) ? depth_shgrp_cull : depth_shgrp, geom, ob->obmat); /* Shading */ clay_shgrp = CLAY_object_shgrp_get(ob, stl, psl); diff --git a/source/blender/draw/engines/eevee/eevee.c b/source/blender/draw/engines/eevee/eevee.c index b4b461f583b..c85e35c904d 100644 --- a/source/blender/draw/engines/eevee/eevee.c +++ b/source/blender/draw/engines/eevee/eevee.c @@ -33,11 +33,18 @@ /* *********** STATIC *********** */ static struct { struct GPUShader *default_lit; + struct GPUShader *depth_sh; struct GPUShader *tonemap; } e_data = {NULL}; /* Engine data */ static struct { DRWShadingGroup *default_lit_grp; + DRWShadingGroup *depth_shgrp; + DRWShadingGroup *depth_shgrp_select; + DRWShadingGroup *depth_shgrp_active; + DRWShadingGroup *depth_shgrp_cull; + DRWShadingGroup *depth_shgrp_cull_select; + DRWShadingGroup *depth_shgrp_cull_active; EEVEE_Data *vedata; } g_data = {NULL}; /* Transient data */ @@ -61,6 +68,10 @@ static void EEVEE_engine_init(void) (int)viewport_size[0], (int)viewport_size[1], &tex, 1); + if (!e_data.default_lit) { + e_data.depth_sh = DRW_shader_create_3D_depth_only(); + } + if (!e_data.default_lit) { e_data.default_lit = DRW_shader_create(datatoc_lit_surface_vert_glsl, NULL, datatoc_lit_surface_frag_glsl, "#define MAX_LIGHT 128\n"); } @@ -84,7 +95,27 @@ static void EEVEE_cache_init(void) EEVEE_StorageList *stl = g_data.vedata->stl; { - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS; + psl->depth_pass = DRW_pass_create("Depth Pass", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS); + g_data.depth_shgrp = DRW_shgroup_create(e_data.depth_sh, psl->depth_pass); + + g_data.depth_shgrp_select = DRW_shgroup_create(e_data.depth_sh, psl->depth_pass); + DRW_shgroup_state_set(g_data.depth_shgrp_select, DRW_STATE_WRITE_STENCIL_SELECT); + + g_data.depth_shgrp_active = DRW_shgroup_create(e_data.depth_sh, psl->depth_pass); + DRW_shgroup_state_set(g_data.depth_shgrp_active, DRW_STATE_WRITE_STENCIL_ACTIVE); + + psl->depth_pass_cull = DRW_pass_create("Depth Pass Cull", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_CULL_BACK); + g_data.depth_shgrp_cull = DRW_shgroup_create(e_data.depth_sh, psl->depth_pass_cull); + + g_data.depth_shgrp_cull_select = DRW_shgroup_create(e_data.depth_sh, psl->depth_pass_cull); + DRW_shgroup_state_set(g_data.depth_shgrp_cull_select, DRW_STATE_WRITE_STENCIL_SELECT); + + g_data.depth_shgrp_cull_active = DRW_shgroup_create(e_data.depth_sh, psl->depth_pass_cull); + DRW_shgroup_state_set(g_data.depth_shgrp_cull_active, DRW_STATE_WRITE_STENCIL_ACTIVE); + } + + { + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_EQUAL; psl->pass = DRW_pass_create("Default Light Pass", state); g_data.default_lit_grp = DRW_shgroup_create(e_data.default_lit, psl->pass); @@ -112,8 +143,19 @@ static void EEVEE_cache_populate(Object *ob) EEVEE_StorageList *stl = g_data.vedata->stl; if (ob->type == OB_MESH) { + CollectionEngineSettings *ces_mode_ob = BKE_object_collection_engine_get(ob, COLLECTION_MODE_OBJECT, ""); + bool do_cull = BKE_collection_engine_property_value_get_bool(ces_mode_ob, "show_backface_culling"); struct Batch *geom = DRW_cache_surface_get(ob); + /* Depth Prepass */ + /* waiting for proper flag */ + // if ((ob->base_flag & BASE_ACTIVE) != 0) + // DRW_shgroup_call_add((do_cull) ? depth_shgrp_cull_active : depth_shgrp_active, geom, ob->obmat); + if ((ob->base_flag & BASE_SELECTED) != 0) + DRW_shgroup_call_add((do_cull) ? g_data.depth_shgrp_cull_select : g_data.depth_shgrp_select, geom, ob->obmat); + else + DRW_shgroup_call_add((do_cull) ? g_data.depth_shgrp_cull : g_data.depth_shgrp, geom, ob->obmat); + DRW_shgroup_call_add(g_data.default_lit_grp, geom, ob->obmat); } else if (ob->type == OB_LAMP) { @@ -146,8 +188,10 @@ static void EEVEE_draw_scene(void) /* Clear Depth */ /* TODO do background */ float clearcol[4] = {0.0f, 0.0f, 0.0f, 1.0f}; - DRW_framebuffer_clear(true, true, clearcol, 1.0f); + DRW_framebuffer_clear(true, true, true, clearcol, 1.0f); + DRW_draw_pass(psl->depth_pass); + DRW_draw_pass(psl->depth_pass_cull); DRW_draw_pass(psl->pass); /* Restore default framebuffer */ diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 4e966757718..4d8f697cc64 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -27,6 +27,8 @@ struct Object; /* keep it under MAX_PASSES */ typedef struct EEVEE_PassList { + struct DRWPass *depth_pass; + struct DRWPass *depth_pass_cull; struct DRWPass *pass; struct DRWPass *tonemap; } EEVEE_PassList; diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index 470f061ebef..0fcfa50f480 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -161,7 +161,7 @@ typedef struct DRWFboTexture { void DRW_framebuffer_init(struct GPUFrameBuffer **fb, int width, int height, DRWFboTexture textures[MAX_FBO_TEX], int texnbr); void DRW_framebuffer_bind(struct GPUFrameBuffer *fb); -void DRW_framebuffer_clear(bool color, bool depth, float clear_col[4], float clear_depth); +void DRW_framebuffer_clear(bool color, bool depth, bool stencil, float clear_col[4], float clear_depth); void DRW_framebuffer_texture_attach(struct GPUFrameBuffer *fb, struct GPUTexture *tex, int slot); void DRW_framebuffer_texture_detach(struct GPUTexture *tex); void DRW_framebuffer_blit(struct GPUFrameBuffer *fb_read, struct GPUFrameBuffer *fb_write, bool depth); @@ -190,6 +190,11 @@ typedef enum { DRW_STATE_STIPPLE_3 = (1 << 11), DRW_STATE_STIPPLE_4 = (1 << 12), DRW_STATE_BLEND = (1 << 13), + + DRW_STATE_WRITE_STENCIL_SELECT = (1 << 14), + DRW_STATE_WRITE_STENCIL_ACTIVE = (1 << 15), + DRW_STATE_TEST_STENCIL_SELECT = (1 << 16), + DRW_STATE_TEST_STENCIL_ACTIVE = (1 << 17), } DRWState; DRWShadingGroup *DRW_shgroup_create(struct GPUShader *shader, DRWPass *pass); @@ -230,7 +235,6 @@ typedef enum { void DRW_viewport_init(const bContext *C); void DRW_viewport_matrix_get(float mat[4][4], DRWViewportMatrixType type); -void DRW_viewport_engine_data_set(const char *engine_name, void *fbl, void *txl, void *psl, void *stl); void *DRW_viewport_engine_data_get(const char *engine_name); float *DRW_viewport_size_get(void); float *DRW_viewport_screenvecs_get(void); diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 26ab09fe487..6b7fe00dba1 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -148,7 +148,7 @@ struct DRWShadingGroup { struct GPUShader *shader; /* Shader to bind */ struct DRWInterface *interface; /* Uniforms pointers */ ListBase calls; /* DRWCall or DRWDynamicCall depending of type*/ - int state; /* State changes for this batch only */ + DRWState state; /* State changes for this batch only */ int type; Batch *instance_geom; /* Geometry to instance */ @@ -163,6 +163,12 @@ enum { DRW_SHG_INSTANCE, }; +/* only 16 bits long */ +enum { + STENCIL_SELECT = (1 << 0), + STENCIL_ACTIVE = (1 << 1), +}; + /* Render State */ static struct DRWGlobalState { /* Rendering state */ @@ -730,38 +736,127 @@ void DRW_pass_free(DRWPass *pass) /* ****************************************** DRAW ******************************************/ #ifdef WITH_CLAY_ENGINE -/* Only alter the state (does not reset it like set_state() ) */ -static void shgroup_set_state(DRWShadingGroup *shgroup) +static void set_state(DRWState flag, const bool reset) { - if (shgroup->state) { - /* Blend */ - if (shgroup->state & DRW_STATE_BLEND) { - glEnable(GL_BLEND); + /* TODO Keep track of the state and only revert what is needed */ + + if (reset) { + /* Depth Write */ + if (flag & DRW_STATE_WRITE_DEPTH) + glDepthMask(GL_TRUE); + else + glDepthMask(GL_FALSE); + + /* Color Write */ + if (flag & DRW_STATE_WRITE_COLOR) + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + else + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + + /* Backface Culling */ + if (flag & DRW_STATE_CULL_BACK || + flag & DRW_STATE_CULL_FRONT) + { + glEnable(GL_CULL_FACE); + + if (flag & DRW_STATE_CULL_BACK) + glCullFace(GL_BACK); + else if (flag & DRW_STATE_CULL_FRONT) + glCullFace(GL_FRONT); + } + else { + glDisable(GL_CULL_FACE); } - /* Wire width */ - if (shgroup->state & DRW_STATE_WIRE) { - glLineWidth(1.0f); - } - else if (shgroup->state & DRW_STATE_WIRE_LARGE) { - glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f); - } + /* Depht Test */ + if (flag & (DRW_STATE_DEPTH_LESS | DRW_STATE_DEPTH_EQUAL | DRW_STATE_DEPTH_GREATER)) + { + glEnable(GL_DEPTH_TEST); - /* Line Stipple */ - if (shgroup->state & DRW_STATE_STIPPLE_2) { - setlinestyle(2); + if (flag & DRW_STATE_DEPTH_LESS) + glDepthFunc(GL_LEQUAL); + else if (flag & DRW_STATE_DEPTH_EQUAL) + glDepthFunc(GL_EQUAL); + else if (flag & DRW_STATE_DEPTH_GREATER) + glDepthFunc(GL_GREATER); } - else if (shgroup->state & DRW_STATE_STIPPLE_3) { - setlinestyle(3); - } - else if (shgroup->state & DRW_STATE_STIPPLE_4) { - setlinestyle(4); + else { + glDisable(GL_DEPTH_TEST); } + } - if (shgroup->state & DRW_STATE_POINT) { - GPU_enable_program_point_size(); - glPointSize(5.0f); + /* Wire Width */ + if (flag & DRW_STATE_WIRE) { + glLineWidth(1.0f); + } + else if (flag & DRW_STATE_WIRE_LARGE) { + glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f); + } + + /* Points Size */ + if (flag & DRW_STATE_POINT) { + GPU_enable_program_point_size(); + glPointSize(5.0f); + } + else if (reset) { + GPU_disable_program_point_size(); + } + + /* Blending (all buffer) */ + if (flag & DRW_STATE_BLEND) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + else if (reset) { + glDisable(GL_BLEND); + } + + /* Line Stipple */ + if (flag & DRW_STATE_STIPPLE_2) { + setlinestyle(2); + } + else if (flag & DRW_STATE_STIPPLE_3) { + setlinestyle(3); + } + else if (flag & DRW_STATE_STIPPLE_4) { + setlinestyle(4); + } + else if (reset) { + setlinestyle(0); + } + + /* Stencil */ + if (flag & (DRW_STATE_WRITE_STENCIL_SELECT | DRW_STATE_WRITE_STENCIL_ACTIVE | + DRW_STATE_TEST_STENCIL_SELECT | DRW_STATE_TEST_STENCIL_ACTIVE)) + { + glEnable(GL_STENCIL_TEST); + + /* Stencil Write */ + if (flag & DRW_STATE_WRITE_STENCIL_SELECT) { + glStencilMask(STENCIL_SELECT); + glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); + glStencilFunc(GL_ALWAYS, 0xFF, STENCIL_SELECT); } + else if (flag & DRW_STATE_WRITE_STENCIL_ACTIVE) { + glStencilMask(STENCIL_ACTIVE); + glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); + glStencilFunc(GL_ALWAYS, 0xFF, STENCIL_ACTIVE); + } + /* Stencil Test */ + else if (flag & DRW_STATE_TEST_STENCIL_SELECT) { + glStencilMask(0x00); /* disable write */ + glStencilFunc(GL_NOTEQUAL, 0xFF, STENCIL_SELECT); + } + else if (flag & DRW_STATE_TEST_STENCIL_ACTIVE) { + glStencilMask(0x00); /* disable write */ + glStencilFunc(GL_NOTEQUAL, 0xFF, STENCIL_ACTIVE); + } + } + else if (reset) { + /* disable write & test */ + glStencilMask(0x00); + glStencilFunc(GL_ALWAYS, 1, 0xFF); + glDisable(GL_STENCIL_TEST); } } @@ -867,7 +962,9 @@ static void draw_shgroup(DRWShadingGroup *shgroup) shgroup_dynamic_batch_from_calls(shgroup); } - shgroup_set_state(shgroup); + if (shgroup->state != 0) { + set_state(shgroup->state, false); + } /* Binding Uniform */ /* Don't check anything, Interface should already contain the least uniform as possible */ @@ -936,103 +1033,13 @@ static void draw_shgroup(DRWShadingGroup *shgroup) } } -static void set_state(short flag) -{ - /* TODO Keep track of the state and only revert what is needed */ - - /* Depth Write */ - if (flag & DRW_STATE_WRITE_DEPTH) - glDepthMask(GL_TRUE); - else - glDepthMask(GL_FALSE); - - /* Color Write */ - if (flag & DRW_STATE_WRITE_COLOR) - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - else - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - - /* Backface Culling */ - if (flag & DRW_STATE_CULL_BACK || - flag & DRW_STATE_CULL_FRONT) - { - - glEnable(GL_CULL_FACE); - - if (flag & DRW_STATE_CULL_BACK) - glCullFace(GL_BACK); - else if (flag & DRW_STATE_CULL_FRONT) - glCullFace(GL_FRONT); - } - else { - glDisable(GL_CULL_FACE); - } - - /* Depht Test */ - if (flag & (DRW_STATE_DEPTH_LESS | DRW_STATE_DEPTH_EQUAL | DRW_STATE_DEPTH_GREATER)) - { - - glEnable(GL_DEPTH_TEST); - - if (flag & DRW_STATE_DEPTH_LESS) - glDepthFunc(GL_LEQUAL); - else if (flag & DRW_STATE_DEPTH_EQUAL) - glDepthFunc(GL_EQUAL); - else if (flag & DRW_STATE_DEPTH_GREATER) - glDepthFunc(GL_GREATER); - } - else { - glDisable(GL_DEPTH_TEST); - } - - /* Wire Width */ - if (flag & DRW_STATE_WIRE) { - glLineWidth(1.0f); - } - else if (flag & DRW_STATE_WIRE_LARGE) { - glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f); - } - - /* Points Size */ - if (flag & DRW_STATE_POINT) { - GPU_enable_program_point_size(); - glPointSize(5.0f); - } - else { - GPU_disable_program_point_size(); - } - - /* Blending (all buffer) */ - if (flag & DRW_STATE_BLEND) { - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - } - else { - glDisable(GL_BLEND); - } - - /* Line Stipple */ - if (flag & DRW_STATE_STIPPLE_2) { - setlinestyle(2); - } - else if (flag & DRW_STATE_STIPPLE_3) { - setlinestyle(3); - } - else if (flag & DRW_STATE_STIPPLE_4) { - setlinestyle(4); - } - else { - setlinestyle(0); - } -} - void DRW_draw_pass(DRWPass *pass) { /* Start fresh */ DST.shader = NULL; DST.tex_bind_id = 0; - set_state(pass->state); + set_state(pass->state, true); BLI_listbase_clear(&DST.bound_texs); for (DRWShadingGroup *shgroup = pass->shgroups.first; shgroup; shgroup = shgroup->next) { @@ -1089,7 +1096,7 @@ void DRW_state_reset(void) state |= DRW_STATE_WRITE_DEPTH; state |= DRW_STATE_WRITE_COLOR; state |= DRW_STATE_DEPTH_LESS; - set_state(state); + set_state(state, true); } #else @@ -1230,7 +1237,7 @@ void DRW_framebuffer_bind(struct GPUFrameBuffer *fb) GPU_framebuffer_bind(fb); } -void DRW_framebuffer_clear(bool color, bool depth, float clear_col[4], float clear_depth) +void DRW_framebuffer_clear(bool color, bool depth, bool stencil, float clear_col[4], float clear_depth) { if (color) { glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); @@ -1240,8 +1247,12 @@ void DRW_framebuffer_clear(bool color, bool depth, float clear_col[4], float cle glDepthMask(GL_TRUE); glClearDepth(clear_depth); } + if (stencil) { + glStencilMask(0xFF); + } glClear(((color) ? GL_COLOR_BUFFER_BIT : 0) | - ((depth) ? GL_DEPTH_BUFFER_BIT : 0)); + ((depth) ? GL_DEPTH_BUFFER_BIT : 0) | + ((stencil) ? GL_STENCIL_BUFFER_BIT : 0)); } void DRW_framebuffer_texture_attach(struct GPUFrameBuffer *fb, GPUTexture *tex, int slot) diff --git a/source/blender/draw/intern/draw_view.c b/source/blender/draw/intern/draw_view.c index 4d813124118..747cc84a9cd 100644 --- a/source/blender/draw/intern/draw_view.c +++ b/source/blender/draw/intern/draw_view.c @@ -549,12 +549,13 @@ void DRW_draw_background(void) /* Just to make sure */ glDepthMask(GL_TRUE); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glStencilMask(0xFF); if (UI_GetThemeValue(TH_SHOW_BACK_GRAD)) { /* Gradient background Color */ gpuMatrixBegin3D(); /* TODO: finish 2D API */ - glClear(GL_DEPTH_BUFFER_BIT); + glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); VertexFormat *format = immVertexFormat(); unsigned pos = add_attrib(format, "pos", COMP_F32, 2, KEEP_FLOAT); @@ -583,7 +584,7 @@ void DRW_draw_background(void) else { /* Solid background Color */ UI_ThemeClearColorAlpha(TH_HIGH_GRAD, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); } } diff --git a/source/blender/draw/modes/edit_mesh_mode.c b/source/blender/draw/modes/edit_mesh_mode.c index 40404b2daff..b0e1dc1d022 100644 --- a/source/blender/draw/modes/edit_mesh_mode.c +++ b/source/blender/draw/modes/edit_mesh_mode.c @@ -396,7 +396,7 @@ static void EDIT_MESH_draw_scene(void) /* Render wires on a separate framebuffer */ DRW_framebuffer_bind(fbl->occlude_wire_fb); - DRW_framebuffer_clear(true, true, clearcol, 1.0f); + DRW_framebuffer_clear(true, true, false, clearcol, 1.0f); DRW_draw_pass(psl->normals); DRW_draw_pass(psl->edit_face_occluded); diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c index ecfde38f5be..8cb09a4e14f 100644 --- a/source/blender/draw/modes/object_mode.c +++ b/source/blender/draw/modes/object_mode.c @@ -46,7 +46,8 @@ typedef struct OBJECT_PassList { struct DRWPass *non_meshes; struct DRWPass *ob_center; - struct DRWPass *wire_outline; + struct DRWPass *outlines; + struct DRWPass *outlines_transp; struct DRWPass *bone_solid; struct DRWPass *bone_wire; } OBJECT_PassList; @@ -108,10 +109,48 @@ static DRWShadingGroup *camera_clip_points; static DRWShadingGroup *camera_mist; static DRWShadingGroup *camera_mist_points; +/* Outlines */ +static DRWShadingGroup *outlines_active; +static DRWShadingGroup *outlines_active_group; +static DRWShadingGroup *outlines_select; +static DRWShadingGroup *outlines_select_group; +static DRWShadingGroup *outlines_transform; +static DRWShadingGroup *outlines_transp_select; +static DRWShadingGroup *outlines_transp_select_group; +static DRWShadingGroup *outlines_transp_active; +static DRWShadingGroup *outlines_transp_active_group; +static DRWShadingGroup *outlines_transp_transform; + extern GlobalsUboStorage ts; static OBJECT_Data *vedata; +static struct GPUShader *outline_sh = NULL; + +extern char datatoc_object_occluded_outline_frag_glsl[]; + +static void OBJECT_engine_init(void) +{ + if (!outline_sh) { + outline_sh = DRW_shader_create_3D(datatoc_object_occluded_outline_frag_glsl, NULL); + } +} + +static void OBJECT_engine_free(void) +{ + if (outline_sh) + DRW_shader_free(outline_sh); +} + +static DRWShadingGroup *shgroup_outline(DRWPass *pass, int state_flag, const float col[4], struct GPUShader *sh) +{ + DRWShadingGroup *grp = DRW_shgroup_create(sh, pass); + DRW_shgroup_uniform_vec4(grp, "color", col, 1); + DRW_shgroup_state_set(grp, state_flag); + + return grp; +} + static void OBJECT_cache_init(void) { /* DRW_viewport_engine_data_get is rather slow, better not do it on every objects */ @@ -119,11 +158,38 @@ static void OBJECT_cache_init(void) OBJECT_PassList *psl = vedata->psl; { - /* This pass can draw mesh outlines and/or fancy wireframe */ - /* Fancy wireframes are not meant to be occluded (without Z offset) */ - /* Outlines and Fancy Wires use the same VBO */ - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_BLEND; - psl->wire_outline = DRW_pass_create("Wire + Outlines Pass", state); + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_WIRE_LARGE; + psl->outlines = DRW_pass_create("Outlines Pass", state); + + struct GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR); + + /* Select */ + outlines_select = shgroup_outline(psl->outlines, DRW_STATE_TEST_STENCIL_SELECT, ts.colorSelect, sh); + outlines_select_group = shgroup_outline(psl->outlines, DRW_STATE_TEST_STENCIL_SELECT, ts.colorGroupActive, sh); + + /* Transform */ + outlines_transform = shgroup_outline(psl->outlines, DRW_STATE_TEST_STENCIL_SELECT, ts.colorTransform, sh); + + /* Active */ + outlines_active = shgroup_outline(psl->outlines, DRW_STATE_TEST_STENCIL_ACTIVE, ts.colorActive, sh); + outlines_active_group = shgroup_outline(psl->outlines, DRW_STATE_TEST_STENCIL_ACTIVE, ts.colorGroupActive, sh); + } + + { + /* FIXME doing a 2nd pass is suboptimal, but waiting for a nice outline solution it does the job*/ + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_GREATER | DRW_STATE_WIRE_LARGE; + psl->outlines_transp = DRW_pass_create("See-through Outlines Pass", state); + + /* Select */ + outlines_transp_select = shgroup_outline(psl->outlines_transp, DRW_STATE_TEST_STENCIL_SELECT, ts.colorSelect, outline_sh); + outlines_transp_select_group = shgroup_outline(psl->outlines_transp, DRW_STATE_TEST_STENCIL_SELECT, ts.colorGroupActive, outline_sh); + + /* Transform */ + outlines_transp_transform = shgroup_outline(psl->outlines_transp, DRW_STATE_TEST_STENCIL_SELECT, ts.colorTransform, outline_sh); + + /* Active */ + outlines_transp_active = shgroup_outline(psl->outlines_transp, DRW_STATE_TEST_STENCIL_ACTIVE, ts.colorActive, outline_sh); + outlines_transp_active_group = shgroup_outline(psl->outlines_transp, DRW_STATE_TEST_STENCIL_ACTIVE, ts.colorGroupActive, outline_sh); } { @@ -280,55 +346,6 @@ static void OBJECT_cache_init(void) } } -static void DRW_shgroup_wire_outline(Object *ob, const bool do_wire, const bool do_outline) -{ - struct GPUShader *sh; - OBJECT_PassList *psl = vedata->psl; - struct Batch *geom = DRW_cache_wire_outline_get(ob); - - float *color; - DRW_object_wire_theme_get(ob, &color); - - bool is_perps = DRW_viewport_is_persp_get(); - static bool bTrue = true; - static bool bFalse = false; - - /* Note (TODO) : this requires cache to be discarded on ortho/perp switch - * It may be preferable (or not depending on performance implication) - * to introduce a shader uniform switch */ - if (is_perps) { - sh = GPU_shader_get_builtin_shader(GPU_SHADER_EDGES_FRONT_BACK_PERSP); - } - else { - sh = GPU_shader_get_builtin_shader(GPU_SHADER_EDGES_FRONT_BACK_ORTHO); - } - - if (do_wire) { - bool *bFront = (do_wire) ? &bTrue : &bFalse; - bool *bBack = (do_wire) ? &bTrue : &bFalse; - - DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->wire_outline); - DRW_shgroup_state_set(grp, DRW_STATE_WIRE); - DRW_shgroup_uniform_vec4(grp, "frontColor", color, 1); - DRW_shgroup_uniform_vec4(grp, "backColor", color, 1); - DRW_shgroup_uniform_bool(grp, "drawFront", bFront, 1); - DRW_shgroup_uniform_bool(grp, "drawBack", bBack, 1); - DRW_shgroup_uniform_bool(grp, "drawSilhouette", &bFalse, 1); - DRW_shgroup_call_add(grp, geom, ob->obmat); - } - - if (do_outline) { - DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->wire_outline); - DRW_shgroup_state_set(grp, DRW_STATE_WIRE_LARGE); - DRW_shgroup_uniform_vec4(grp, "silhouetteColor", color, 1); - DRW_shgroup_uniform_bool(grp, "drawFront", &bFalse, 1); - DRW_shgroup_uniform_bool(grp, "drawBack", &bFalse, 1); - DRW_shgroup_uniform_bool(grp, "drawSilhouette", &bTrue, 1); - - DRW_shgroup_call_add(grp, geom, ob->obmat); - } -} - static void DRW_shgroup_lamp(Object *ob) { Lamp *la = ob->data; @@ -563,17 +580,38 @@ static void OBJECT_cache_populate(Object *ob) const struct bContext *C = DRW_get_context(); Scene *scene = CTX_data_scene(C); - CollectionEngineSettings *ces_mode_ob = BKE_object_collection_engine_get(ob, COLLECTION_MODE_OBJECT, ""); + //CollectionEngineSettings *ces_mode_ob = BKE_object_collection_engine_get(ob, COLLECTION_MODE_OBJECT, ""); - bool do_wire = BKE_collection_engine_property_value_get_bool(ces_mode_ob, "show_wire"); - bool do_outlines = ((ob->base_flag & BASE_SELECTED) != 0) || do_wire; + //bool do_wire = BKE_collection_engine_property_value_get_bool(ces_mode_ob, "show_wire"); + bool do_outlines = ((ob->base_flag & BASE_SELECTED) != 0); switch (ob->type) { case OB_MESH: { Object *obedit = scene->obedit; + int theme_id = DRW_object_wire_theme_get(ob, NULL); if (ob != obedit) { - DRW_shgroup_wire_outline(ob, do_wire, do_outlines); + if (do_outlines) { + struct Batch *geom = DRW_cache_wire_outline_get(ob); + switch (theme_id) { + case TH_ACTIVE: + DRW_shgroup_call_add(outlines_active, geom, ob->obmat); + DRW_shgroup_call_add(outlines_transp_active, geom, ob->obmat); + break; + case TH_SELECT: + DRW_shgroup_call_add(outlines_select, geom, ob->obmat); + DRW_shgroup_call_add(outlines_transp_select, geom, ob->obmat); + break; + case TH_GROUP_ACTIVE: + DRW_shgroup_call_add(outlines_select_group, geom, ob->obmat); + DRW_shgroup_call_add(outlines_transp_select_group, geom, ob->obmat); + break; + case TH_TRANSFORM: + DRW_shgroup_call_add(outlines_transform, geom, ob->obmat); + DRW_shgroup_call_add(outlines_transp_transform, geom, ob->obmat); + break; + } + } } } break; @@ -612,9 +650,10 @@ static void OBJECT_draw_scene(void) OBJECT_Data *ved = DRW_viewport_engine_data_get("ObjectMode"); OBJECT_PassList *psl = ved->psl; + DRW_draw_pass(psl->outlines_transp); + DRW_draw_pass(psl->outlines); DRW_draw_pass(psl->bone_wire); DRW_draw_pass(psl->bone_solid); - DRW_draw_pass(psl->wire_outline); DRW_draw_pass(psl->non_meshes); DRW_draw_pass(psl->ob_center); } @@ -629,8 +668,8 @@ void OBJECT_collection_settings_create(CollectionEngineSettings *ces) DrawEngineType draw_engine_object_type = { NULL, NULL, N_("ObjectMode"), - NULL, - NULL, + &OBJECT_engine_init, + &OBJECT_engine_free, &OBJECT_cache_init, &OBJECT_cache_populate, NULL, diff --git a/source/blender/draw/modes/shaders/object_occluded_outline_frag.glsl b/source/blender/draw/modes/shaders/object_occluded_outline_frag.glsl new file mode 100644 index 00000000000..cd9f43e6c4e --- /dev/null +++ b/source/blender/draw/modes/shaders/object_occluded_outline_frag.glsl @@ -0,0 +1,15 @@ + +out vec4 FragColor; + +uniform vec4 color; + +void main() +{ + /* Checkerboard pattern */ + /* 0 | 1 + * 1 | 0 */ + if ((((int(gl_FragCoord.x) & 0x1) + (int(gl_FragCoord.y) & 0x1)) & 0x1) != 0) + discard; + + FragColor = vec4(color.rgb * 0.5, 1.0); +}