[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