[Bf-blender-cvs] [a0b953374a9] greasepencil-refactor: GPencil: Refactor: Implement Opacity Masking
Clément Foucault
noreply at git.blender.org
Sun Dec 15 15:10:40 CET 2019
Commit: a0b953374a995183edfe6875ac8fcca493ed9949
Author: Clément Foucault
Date: Sun Dec 15 15:42:11 2019 +0100
Branches: greasepencil-refactor
https://developer.blender.org/rBa0b953374a995183edfe6875ac8fcca493ed9949
GPencil: Refactor: Implement Opacity Masking
This is better than previous implementation but has a higher cost.
We render masked layer to a RGBA16F buffer and we then mask the revealage
and the color in a 2 pass blending.
This could maybe optimized a bit to reduce to 1 blending on recent hardware
but the cost will still be way higher than the stencil method.
On the plus side, there is less code change than with the stencil.
===================================================================
M source/blender/draw/CMakeLists.txt
M source/blender/draw/engines/gpencil/gpencil_cache_utils.c
M source/blender/draw/engines/gpencil/gpencil_engine.c
M source/blender/draw/engines/gpencil/gpencil_engine.h
M source/blender/draw/engines/gpencil/gpencil_shader.c
A source/blender/draw/engines/gpencil/shaders/gpencil_layer_mask_frag.glsl
===================================================================
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index 52476f9a6e2..ecd7f9117a5 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -280,6 +280,7 @@ data_to_c_simple(engines/gpencil/shaders/gpencil_vert.glsl SRC)
data_to_c_simple(engines/gpencil/shaders/gpencil_common_lib.glsl SRC)
data_to_c_simple(engines/gpencil/shaders/gpencil_composite_frag.glsl SRC)
data_to_c_simple(engines/gpencil/shaders/gpencil_layer_blend_frag.glsl SRC)
+data_to_c_simple(engines/gpencil/shaders/gpencil_layer_mask_frag.glsl SRC)
data_to_c_simple(engines/gpencil/shaders/gpencil_depth_merge_frag.glsl SRC)
data_to_c_simple(engines/gpencil/shaders/gpencil_fill_vert.glsl SRC)
diff --git a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
index 00a9b1c05e9..2073b44d284 100644
--- a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
+++ b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
@@ -64,6 +64,24 @@ GPENCIL_tLayer *gpencil_layer_cache_add_new(GPENCIL_PrivateData *pd, Object *ob,
bGPdata *gpd = (bGPdata *)ob->data;
GPENCIL_tLayer *tgp_layer = BLI_memblock_alloc(pd->gp_layer_pool);
+ const bool is_mask = (gpl->flag & GP_LAYER_USE_MASK) != 0;
+ tgp_layer->is_mask = is_mask;
+
+ if (!is_mask) {
+ tgp_layer->is_masked = false;
+ for (bGPDlayer *gpl_m = gpl->next; gpl_m; gpl_m = gpl_m->next) {
+ if (gpl_m->flag & GP_LAYER_USE_MASK) {
+ if (gpl_m->flag & GP_LAYER_HIDE) {
+ /* We don't mask but we dont try to mask with further layers. */
+ }
+ else {
+ tgp_layer->is_masked = true;
+ }
+ break;
+ }
+ }
+ }
+
{
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL;
if (GPENCIL_3D_DRAWMODE(ob, gpd) || pd->draw_depth_only) {
@@ -75,19 +93,39 @@ GPENCIL_tLayer *gpencil_layer_cache_add_new(GPENCIL_PrivateData *pd, Object *ob,
state |= DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_GREATER;
}
- if (!pd->draw_depth_only) {
- if (gpl->flag & GP_LAYER_USE_MASK) {
- state |= DRW_STATE_STENCIL_EQUAL;
- }
- else {
- state |= DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_ALWAYS;
- }
+ if (gpl->flag & GP_LAYER_USE_MASK) {
+ state |= DRW_STATE_STENCIL_EQUAL;
+ }
+ else {
+ state |= DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_ALWAYS;
}
tgp_layer->geom_ps = DRW_pass_create("GPencil Layer", state);
}
- if ((gpl->blend_mode != eGplBlendMode_Regular) || (gpl->opacity < 1.0f)) {
+ if (is_mask) {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_STENCIL_EQUAL | DRW_STATE_BLEND_MUL;
+ tgp_layer->blend_ps = DRW_pass_create("GPencil Mask Layer", state);
+
+ GPUShader *sh = GPENCIL_shader_layer_mask_get(&en_data);
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, tgp_layer->blend_ps);
+ DRW_shgroup_uniform_int_copy(grp, "isFirstPass", true);
+ DRW_shgroup_uniform_float_copy(grp, "maskOpacity", gpl->opacity);
+ DRW_shgroup_uniform_texture_ref(grp, "colorBuf", &pd->color_masked_tx);
+ DRW_shgroup_uniform_texture_ref(grp, "revealBuf", &pd->reveal_masked_tx);
+ DRW_shgroup_uniform_texture_ref(grp, "maskBuf", &pd->reveal_layer_tx);
+ DRW_shgroup_stencil_mask(grp, 0xFF);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+
+ /* We cannot do custom blending on MultiTarget framebuffers.
+ * Workaround by doing 2 passes. */
+ grp = DRW_shgroup_create_sub(grp);
+ DRW_shgroup_state_disable(grp, DRW_STATE_BLEND_MUL);
+ DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ADD_FULL);
+ DRW_shgroup_uniform_int_copy(grp, "isFirstPass", false);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
+ else if ((gpl->blend_mode != eGplBlendMode_Regular) || (gpl->opacity < 1.0f)) {
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_STENCIL_EQUAL;
switch (gpl->blend_mode) {
case eGplBlendMode_Regular:
@@ -122,7 +160,6 @@ GPENCIL_tLayer *gpencil_layer_cache_add_new(GPENCIL_PrivateData *pd, Object *ob,
DRW_shgroup_uniform_texture_ref(grp, "colorBuf", &pd->color_layer_tx);
DRW_shgroup_uniform_texture_ref(grp, "revealBuf", &pd->reveal_layer_tx);
DRW_shgroup_stencil_mask(grp, 0xFF);
- /* TODO only blend pixels that have been rendered. */
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
if (gpl->blend_mode == eGplBlendMode_Overlay) {
@@ -130,10 +167,8 @@ GPENCIL_tLayer *gpencil_layer_cache_add_new(GPENCIL_PrivateData *pd, Object *ob,
* Workaround by doing 2 passes. */
grp = DRW_shgroup_create(sh, tgp_layer->blend_ps);
DRW_shgroup_state_disable(grp, DRW_STATE_BLEND_MUL);
- DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ADD);
+ DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ADD_FULL);
DRW_shgroup_uniform_int_copy(grp, "blendMode", 999);
- DRW_shgroup_uniform_texture_ref(grp, "colorBuf", &pd->color_layer_tx);
- /* TODO only blend pixels that have been rendered. */
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
}
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c
index 767f1a46923..1c0731b289f 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.c
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.c
@@ -355,6 +355,7 @@ static void GPENCIL_engine_free(void)
DRW_SHADER_FREE_SAFE(e_data.gpencil_sh);
DRW_SHADER_FREE_SAFE(e_data.composite_sh);
DRW_SHADER_FREE_SAFE(e_data.layer_blend_sh);
+ DRW_SHADER_FREE_SAFE(e_data.layer_mask_sh);
DRW_SHADER_FREE_SAFE(e_data.depth_merge_sh);
DRW_TEXTURE_FREE_SAFE(e_data.gpencil_blank_texture);
@@ -1045,6 +1046,7 @@ static void GPENCIL_cache_finish_new(void *ved)
if (pd->tobjects.first) {
/* TODO(fclem) Detect use of layers and vfx. */
bool use_layer_fb = true;
+ bool use_mask_fb = true;
bool use_object_fb = false;
const float *size = DRW_viewport_size_get();
@@ -1089,6 +1091,21 @@ static void GPENCIL_cache_finish_new(void *ved)
GPU_ATTACHMENT_TEXTURE(pd->reveal_object_tx),
});
}
+
+ if (use_mask_fb) {
+ /* We need to separate all the masked layer together in order to correctly mix them. */
+ pd->color_masked_tx = DRW_texture_pool_query_2d(
+ size[0], size[1], GPU_RGBA16F, &draw_engine_gpencil_type);
+ pd->reveal_masked_tx = DRW_texture_pool_query_2d(
+ size[0], size[1], GPU_RGBA16F, &draw_engine_gpencil_type);
+
+ GPU_framebuffer_ensure_config(&fbl->masked_fb,
+ {
+ GPU_ATTACHMENT_TEXTURE(pd->depth_tx),
+ GPU_ATTACHMENT_TEXTURE(pd->color_masked_tx),
+ GPU_ATTACHMENT_TEXTURE(pd->reveal_masked_tx),
+ });
+ }
}
}
@@ -1323,6 +1340,8 @@ static void GPENCIL_draw_scene_new(void *ved)
GPU_framebuffer_multi_clear(fbl->gpencil_fb, clear_cols);
for (GPENCIL_tObject *ob = pd->tobjects.first; ob; ob = ob->next) {
+ bool masked_fb_in_use = false;
+
DRW_stats_group_start("GPencil Object");
GPU_framebuffer_bind(fbl->gpencil_fb);
@@ -1338,11 +1357,22 @@ static void GPENCIL_draw_scene_new(void *ved)
GPU_framebuffer_bind(fbl->layer_fb);
GPU_framebuffer_multi_clear(fbl->layer_fb, clear_cols);
}
+ else {
+ GPU_framebuffer_bind((layer->is_masked) ? fbl->masked_fb : fbl->gpencil_fb);
+ if (layer->is_masked && !masked_fb_in_use) {
+ GPU_framebuffer_multi_clear(fbl->masked_fb, clear_cols);
+ masked_fb_in_use = layer->is_masked;
+ }
+ }
DRW_draw_pass(layer->geom_ps);
if (layer->blend_ps) {
- GPU_framebuffer_bind(fbl->gpencil_fb);
+ GPU_framebuffer_bind((layer->is_masked) ? fbl->masked_fb : fbl->gpencil_fb);
+ if (layer->is_masked && !masked_fb_in_use) {
+ GPU_framebuffer_multi_clear(fbl->masked_fb, clear_cols);
+ masked_fb_in_use = layer->is_masked;
+ }
DRW_draw_pass(layer->blend_ps);
}
}
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h
index 7f7d09274eb..68160880d05 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.h
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.h
@@ -180,6 +180,9 @@ typedef struct GPENCIL_tLayer {
DRWPass *geom_ps;
/** Blend pass to composite onto the target buffer (blends modes). NULL if not needed. */
DRWPass *blend_ps;
+ /** Used to identify which layers are masks and which are masked. */
+ bool is_mask;
+ bool is_masked;
} GPENCIL_tLayer;
typedef struct GPENCIL_tObject {
@@ -330,6 +333,7 @@ typedef struct GPENCIL_FramebufferList {
struct GPUFrameBuffer *gpencil_fb;
struct GPUFrameBuffer *layer_fb;
struct GPUFrameBuffer *object_fb;
+ struct GPUFrameBuffer *masked_fb;
} GPENCIL_FramebufferList;
typedef struct GPENCIL_TextureList {
@@ -416,10 +420,12 @@ typedef struct GPENCIL_PrivateData {
GPUTexture *color_tx;
GPUTexture *color_layer_tx;
GPUTexture *color_object_tx;
+ GPUTexture *color_masked_tx;
/* Revealage is 1 - alpha */
GPUTexture *reveal_tx;
GPUTexture *reveal_layer_tx;
GPUTexture *reveal_object_tx;
+ GPUTexture *reveal_masked_tx;
/* Pointer to dtxl->depth */
GPUTexture *scene_depth_tx;
/* Current frame */
@@ -452,6 +458,8 @@ typedef struct GPENCIL_e_data {
struct GPUShader *composite_sh;
/* All layer blend types in one shader! */
struct GPUShader *layer_blend_sh;
+ /* To blend masked layer with other layers. */
+ struct GPUShader *layer_mask_sh;
/* Merge the final object depth to the depth buffer. */
struct GPUShader *depth_merge_sh;
@@ -687,6 +695,7 @@ void gpencil_fx_draw(struct GPENCIL_e_data *e_data,
struct GPUShader *GPENCIL_shader_geometry_get(GPENCIL_e_data *e_data);
struct GPUShader *GPENCIL_shader_composite_get(GPENCIL_e_data *e_data);
struct GPUShader *GPENCIL_sha
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list