Object Mode: Add stencil test to remove object outlines inside the silouhette.

It also adds nice occluded silouhette information for selected objects that are behind visible objects.
This methods is really heavy because it needs to render the wires twices.
This commit is contained in:
Clément Foucault 2017-03-18 01:55:41 +01:00
parent cddde85f2c
commit 4137f30928
10 changed files with 332 additions and 193 deletions

View File

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

View File

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

View File

@ -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 */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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