GP: New Blend Layers functionality

Now it's possible define the blend mode between layers including the option to clamp the layer using underlying layers.

Also a new Simplify option has been added to disable blend layers.
This commit is contained in:
Antonioya 2018-11-26 18:12:39 +01:00
parent c0816cd03b
commit 99f7934e19
14 changed files with 427 additions and 64 deletions

@ -135,13 +135,22 @@ class DATA_PT_gpencil_datapanel(Panel):
col.template_list("GPENCIL_UL_layer", "", gpd, "layers", gpd.layers, "active_index",
rows=layer_rows, reverse=True)
gpl = context.active_gpencil_layer
if gpl:
srow = col.row(align=True)
srow.prop(gpl, "blend_mode", text="Blend")
srow = col.row(align=True)
srow.prop(gpl, "opacity", text="Opacity", slider=True)
srow.prop(gpl, "clamp_layer", text="",
icon='MOD_MASK' if gpl.clamp_layer else 'ONIONSKIN_OFF')
col = row.column()
sub = col.column(align=True)
sub.operator("gpencil.layer_add", icon='ADD', text="")
sub.operator("gpencil.layer_remove", icon='REMOVE', text="")
gpl = context.active_gpencil_layer
if gpl:
sub.menu("GPENCIL_MT_layer_specials", icon='DOWNARROW_HLT', text="")
@ -158,10 +167,6 @@ class DATA_PT_gpencil_datapanel(Panel):
sub.operator("gpencil.layer_isolate", icon='LOCKED', text="").affect_visibility = False
sub.operator("gpencil.layer_isolate", icon='RESTRICT_VIEW_ON', text="").affect_visibility = True
row = layout.row(align=True)
if gpl:
row.prop(gpl, "opacity", text="Opacity", slider=True)
class DATA_PT_gpencil_layer_optionpanel(LayerDataButtonsPanel, Panel):
bl_space_type = 'PROPERTIES'

@ -766,7 +766,6 @@ class AnnotationDataPanel:
layout.prop(tool_settings, "annotation_thickness", text="Thickness")
if gpl:
# layout.prop(gpl, "opacity", text="Opacity", slider=True)
# Full-Row - Frame Locking (and Delete Frame)
row = layout.row(align=True)
row.active = not gpl.lock
@ -873,6 +872,10 @@ class GPENCIL_UL_layer(UIList):
row.prop(gpl, "info", text="", emboss=False)
row = layout.row(align=True)
row.prop(gpl, "clamp_layer", text="",
icon='MOD_MASK' if gpl.clamp_layer else 'ONIONSKIN_OFF',
emboss=False)
row.prop(gpl, "lock", text="", emboss=False)
row.prop(gpl, "hide", text="", emboss=False)
subrow = row.row(align=True)

@ -650,6 +650,7 @@ class RENDER_PT_simplify_greasepencil(RenderButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
rd = context.scene.render
@ -659,8 +660,8 @@ class RENDER_PT_simplify_greasepencil(RenderButtonsPanel, Panel):
col.prop(rd, "simplify_gpencil_onplay", text="Playback Only")
col.prop(rd, "simplify_gpencil_view_modifier", text="Modifiers")
col.prop(rd, "simplify_gpencil_shader_fx", text="ShaderFX")
col.prop(rd, "simplify_gpencil_blend", text="Layers Blending")
col = layout.column(align=True)
col.prop(rd, "simplify_gpencil_view_fill")
sub = col.column()
sub.active = rd.simplify_gpencil_view_fill

@ -516,6 +516,16 @@ class TOPBAR_PT_gpencil_layers(Panel):
col.template_list("GPENCIL_UL_layer", "", gpd, "layers", gpd.layers, "active_index",
rows=layer_rows, reverse=True)
gpl = context.active_gpencil_layer
if gpl:
srow = col.row(align=True)
srow.prop(gpl, "blend_mode", text="Blend")
srow = col.row(align=True)
srow.prop(gpl, "opacity", text="Opacity", slider=True)
srow.prop(gpl, "clamp_layer", text="",
icon='MOD_MASK' if gpl.clamp_layer else 'ONIONSKIN_OFF')
col = row.column()
sub = col.column(align=True)
@ -539,10 +549,6 @@ class TOPBAR_PT_gpencil_layers(Panel):
sub.operator("gpencil.layer_isolate", icon='LOCKED', text="").affect_visibility = False
sub.operator("gpencil.layer_isolate", icon='HIDE_OFF', text="").affect_visibility = True
row = layout.row(align=True)
if gpl:
row.prop(gpl, "opacity", text="Opacity", slider=True)
class TOPBAR_MT_editor_menus(Menu):
bl_idname = "TOPBAR_MT_editor_menus"

@ -327,6 +327,7 @@ data_to_c_simple(engines/gpencil/shaders/gpencil_stroke_geom.glsl SRC)
data_to_c_simple(engines/gpencil/shaders/gpencil_stroke_frag.glsl SRC)
data_to_c_simple(engines/gpencil/shaders/gpencil_zdepth_mix_frag.glsl SRC)
data_to_c_simple(engines/gpencil/shaders/gpencil_simple_mix_frag.glsl SRC)
data_to_c_simple(engines/gpencil/shaders/gpencil_blend_frag.glsl SRC)
data_to_c_simple(engines/gpencil/shaders/gpencil_point_vert.glsl SRC)
data_to_c_simple(engines/gpencil/shaders/gpencil_point_geom.glsl SRC)
data_to_c_simple(engines/gpencil/shaders/gpencil_point_frag.glsl SRC)

@ -83,8 +83,12 @@ tGPencilObjectCache *gpencil_object_cache_add(
cache_elem->pixfactor = cache_elem->gpd->pixfactor;
cache_elem->shader_fx = ob_orig->shader_fx;
cache_elem->init_grp = NULL;
cache_elem->end_grp = NULL;
/* shgrp array */
cache_elem->tot_layers = 0;
int totgpl = BLI_listbase_count(&cache_elem->gpd->layers);
if (totgpl > 0) {
cache_elem->shgrp_array = MEM_callocN(sizeof(tGPencilObjectCache_shgrp) * totgpl, __func__);
}
/* calculate zdepth from point of view */
float zdepth = 0.0;

@ -244,13 +244,15 @@ static void gpencil_stroke_2d_flat(const bGPDspoint *points, int totpoints, floa
}
/* recalc the internal geometry caches for fill and uvs */
static void DRW_gpencil_recalc_geometry_caches(Object *ob, MaterialGPencilStyle *gp_style, bGPDstroke *gps)
static void DRW_gpencil_recalc_geometry_caches(
Object *ob, bGPDlayer *gpl, MaterialGPencilStyle *gp_style, bGPDstroke *gps)
{
if (gps->flag & GP_STROKE_RECALC_CACHES) {
/* Calculate triangles cache for filling area (must be done only after changes) */
if ((gps->tot_triangles == 0) || (gps->triangles == NULL)) {
if ((gps->totpoints > 2) &&
((gp_style->fill_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gp_style->fill_style > 0)))
((gp_style->fill_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH) ||
(gp_style->fill_style > 0) || (gpl->blend_mode != eGplBlendMode_Normal)))
{
DRW_gpencil_triangulate_stroke_fill(ob, gps);
}
@ -559,7 +561,9 @@ static void gpencil_add_fill_vertexdata(
/* set color using material, tint color and opacity */
interp_v3_v3v3(tfill, gps->runtime.tmp_fill_rgba, tintcolor, tintcolor[3]);
tfill[3] = gps->runtime.tmp_fill_rgba[3] * opacity;
if ((tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gp_style->fill_style > 0)) {
if ((tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) ||
(gp_style->fill_style > 0) ||
(gpl->blend_mode != eGplBlendMode_Normal)) {
if (cache->is_dirty) {
const float *color;
if (!onion) {
@ -581,7 +585,8 @@ static void gpencil_add_fill_vertexdata(
/* add to list of groups */
if (old_len < cache->b_fill.vbo_len) {
cache->grp_cache = gpencil_group_cache_add(
cache->grp_cache, gpl, gpf, gps, eGpencilBatchGroupType_Fill, onion,
cache->grp_cache, gpl, gpf, gps,
eGpencilBatchGroupType_Fill, onion,
cache->b_fill.vbo_len,
&cache->grp_size, &cache->grp_used);
}
@ -637,7 +642,8 @@ static void gpencil_add_stroke_vertexdata(
/* add to list of groups */
if (old_len < cache->b_stroke.vbo_len) {
cache->grp_cache = gpencil_group_cache_add(
cache->grp_cache, gpl, gpf, gps, eGpencilBatchGroupType_Stroke, onion,
cache->grp_cache, gpl, gpf, gps,
eGpencilBatchGroupType_Stroke, onion,
cache->b_stroke.vbo_len,
&cache->grp_size, &cache->grp_used);
}
@ -687,7 +693,8 @@ static void gpencil_add_editpoints_vertexdata(
/* add to list of groups */
cache->grp_cache = gpencil_group_cache_add(
cache->grp_cache, gpl, gpf, gps, eGpencilBatchGroupType_Edlin, false,
cache->grp_cache, gpl, gpf, gps,
eGpencilBatchGroupType_Edlin, false,
cache->b_edlin.vbo_len,
&cache->grp_size, &cache->grp_used);
}
@ -699,7 +706,8 @@ static void gpencil_add_editpoints_vertexdata(
/* add to list of groups */
cache->grp_cache = gpencil_group_cache_add(
cache->grp_cache, gpl, gpf, gps, eGpencilBatchGroupType_Edit, false,
cache->grp_cache, gpl, gpf, gps,
eGpencilBatchGroupType_Edit, false,
cache->b_edit.vbo_len,
&cache->grp_size, &cache->grp_used);
}
@ -771,13 +779,14 @@ static void gpencil_draw_strokes(
/* be sure recalc all cache in source stroke to avoid recalculation when frame change
* and improve fps */
if (src_gps) {
DRW_gpencil_recalc_geometry_caches(ob, gp_style, src_gps);
DRW_gpencil_recalc_geometry_caches(ob, gpl, gp_style, src_gps);
}
/* if the fill has any value, it's considered a fill and is not drawn if simplify fill is enabled */
if ((stl->storage->simplify_fill) && (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_REMOVE_FILL_LINE)) {
if ((gp_style->fill_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH) ||
(gp_style->fill_style > GP_STYLE_FILL_STYLE_SOLID))
(gp_style->fill_style > GP_STYLE_FILL_STYLE_SOLID) ||
(gpl->blend_mode != eGplBlendMode_Normal))
{
GP_SET_SRC_GPS(src_gps);
continue;
@ -798,9 +807,14 @@ static void gpencil_draw_strokes(
}
}
/* hide any blend layer */
if ((!stl->storage->simplify_blend) ||
(gpl->blend_mode == eGplBlendMode_Normal))
{
/* fill */
if ((gp_style->flag & GP_STYLE_FILL_SHOW) &&
(!stl->storage->simplify_fill))
(!stl->storage->simplify_fill) &&
((gps->flag & GP_STROKE_NOFILL) == 0))
{
gpencil_add_fill_vertexdata(
cache, ob, gpl, derived_gpf, gps,
@ -808,13 +822,15 @@ static void gpencil_draw_strokes(
}
/* stroke */
if ((gp_style->flag & GP_STYLE_STROKE_SHOW) &&
(gp_style->stroke_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH))
((gp_style->stroke_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH) ||
(gpl->blend_mode == eGplBlendMode_Normal)))
{
gpencil_add_stroke_vertexdata(
cache, ob, gpl, derived_gpf, gps,
opacity, tintcolor, false, custonion);
}
}
}
/* edit points (only in edit mode and not play animation not render) */
if ((draw_ctx->obact == ob) && (src_gps) &&
@ -1253,12 +1269,21 @@ static void DRW_gpencil_create_batches(GpencilBatchCache *cache)
/* create all shading groups */
static void DRW_gpencil_shgroups_create(
GPENCIL_e_data *e_data, void *vedata,
Object *ob, bGPdata *gpd,
Object *ob,
GpencilBatchCache *cache, tGPencilObjectCache *cache_ob)
{
GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
bGPdata *gpd = (bGPdata *)ob->data;
GpencilBatchGroup *elm = NULL;
DRWShadingGroup *shgrp = NULL;
tGPencilObjectCache_shgrp *array_elm = NULL;
bGPDlayer *gpl = NULL;
bGPDlayer *gpl_prev = NULL;
int idx = 0;
bool tag_first = false;
int start_stroke = 0;
int start_point = 0;
@ -1266,12 +1291,28 @@ static void DRW_gpencil_shgroups_create(
int start_edit = 0;
int start_edlin = 0;
cache_ob->init_grp = NULL;
cache_ob->end_grp = NULL;
for (int i = 0; i < cache->grp_used; i++) {
GpencilBatchGroup *elm = &cache->grp_cache[i];
bGPDlayer *gpl = elm->gpl;
elm = &cache->grp_cache[i];
array_elm = &cache_ob->shgrp_array[idx];
/* save last group when change */
if (gpl_prev == NULL) {
gpl_prev = elm->gpl;
tag_first = true;
}
else {
if (elm->gpl != gpl_prev)
{
/* first layer is always blend Normal */
array_elm->mode = idx == 0 ? eGplBlendMode_Normal: gpl->blend_mode;
array_elm->end_shgrp = shgrp;
gpl_prev = elm->gpl;
tag_first = true;
idx++;
}
}
gpl = elm->gpl;
bGPDframe *gpf = elm->gpf;
bGPDstroke *gps = elm->gps;
MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
@ -1365,14 +1406,22 @@ static void DRW_gpencil_shgroups_create(
}
}
/* save first group */
if ((shgrp != NULL) && (cache_ob->init_grp == NULL)) {
cache_ob->init_grp = shgrp;
if ((shgrp != NULL) && (tag_first)) {
array_elm = &cache_ob->shgrp_array[idx];
array_elm->mode = idx == 0 ? eGplBlendMode_Normal: gpl->blend_mode;
array_elm->clamp_layer = gpl->flag & GP_LAYER_USE_MASK;
array_elm->blend_opacity = gpl->opacity;
array_elm->init_shgrp = shgrp;
cache_ob->tot_layers++;
tag_first = false;
}
}
/* save last group */
if (shgrp != NULL) {
cache_ob->end_grp = shgrp;
array_elm->mode = idx == 0 ? eGplBlendMode_Normal : gpl->blend_mode;
array_elm->end_shgrp = shgrp;
}
}
/* populate a datablock for multiedit (no onions, no modifiers) */
@ -1425,7 +1474,7 @@ void DRW_gpencil_populate_multiedit(
/* create batchs and shading groups */
DRW_gpencil_create_batches(cache);
DRW_gpencil_shgroups_create(e_data, vedata, ob, gpd, cache, cache_ob);
DRW_gpencil_shgroups_create(e_data, vedata, ob, cache, cache_ob);
cache->is_dirty = false;
}
@ -1465,7 +1514,7 @@ void DRW_gpencil_populate_datablock(
/* if object is duplicate, only create shading groups */
if (cache_ob->is_dup_ob) {
DRW_gpencil_shgroups_create(e_data, vedata, ob, gpd, cache, cache_ob);
DRW_gpencil_shgroups_create(e_data, vedata, ob, cache, cache_ob);
return;
}
@ -1481,8 +1530,9 @@ void DRW_gpencil_populate_datablock(
/* draw normal strokes */
for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
/* don't draw layer if hidden */
if (gpl->flag & GP_LAYER_HIDE)
if (gpl->flag & GP_LAYER_HIDE) {
continue;
}
/* filter view layer to gp layers in the same view layer (for compo) */
if ((stl->storage->is_render) && (gpl->viewlayername[0] != '\0')) {
@ -1560,7 +1610,7 @@ void DRW_gpencil_populate_datablock(
/* create batchs and shading groups */
DRW_gpencil_create_batches(cache);
DRW_gpencil_shgroups_create(e_data, vedata, ob, gpd, cache, cache_ob);
DRW_gpencil_shgroups_create(e_data, vedata, ob, cache, cache_ob);
cache->is_dirty = false;
}
@ -1574,9 +1624,8 @@ void DRW_gpencil_populate_particles(GPENCIL_e_data *e_data, void *vedata)
tGPencilObjectCache *cache_ob = &stl->g_data->gp_object_cache[i];
Object *ob = cache_ob->ob;
if (cache_ob->is_dup_ob) {
bGPdata *gpd = (bGPdata *)ob->data;
GpencilBatchCache *cache = ob->runtime.gpencil_cache;
DRW_gpencil_shgroups_create(e_data, vedata, ob, gpd, cache, cache_ob);
DRW_gpencil_shgroups_create(e_data, vedata, ob, cache, cache_ob);
}
}
}

@ -64,6 +64,7 @@ extern char datatoc_gpencil_paper_frag_glsl[];
extern char datatoc_gpencil_edit_point_vert_glsl[];
extern char datatoc_gpencil_edit_point_geom_glsl[];
extern char datatoc_gpencil_edit_point_frag_glsl[];
extern char datatoc_gpencil_blend_frag_glsl[];
/* *********** STATIC *********** */
static GPENCIL_e_data e_data = {NULL}; /* Engine data */
@ -221,6 +222,11 @@ static void GPENCIL_create_shaders(void)
e_data.gpencil_simple_fullscreen_sh = DRW_shader_create_fullscreen(datatoc_gpencil_simple_mix_frag_glsl, NULL);
}
/* blend */
if (!e_data.gpencil_blend_fullscreen_sh) {
e_data.gpencil_blend_fullscreen_sh = DRW_shader_create_fullscreen(datatoc_gpencil_blend_frag_glsl, NULL);
}
/* shaders for use when drawing */
if (!e_data.gpencil_background_sh) {
e_data.gpencil_background_sh = DRW_shader_create_fullscreen(datatoc_gpencil_background_frag_glsl, NULL);
@ -266,6 +272,7 @@ static void GPENCIL_engine_free(void)
DRW_SHADER_FREE_SAFE(e_data.gpencil_edit_point_sh);
DRW_SHADER_FREE_SAFE(e_data.gpencil_fullscreen_sh);
DRW_SHADER_FREE_SAFE(e_data.gpencil_simple_fullscreen_sh);
DRW_SHADER_FREE_SAFE(e_data.gpencil_blend_fullscreen_sh);
DRW_SHADER_FREE_SAFE(e_data.gpencil_background_sh);
DRW_SHADER_FREE_SAFE(e_data.gpencil_paper_sh);
@ -371,6 +378,7 @@ void GPENCIL_cache_init(void *vedata)
stl->storage->simplify_fill = GP_SIMPLIFY_FILL(scene, stl->storage->is_playing);
stl->storage->simplify_modif = GP_SIMPLIFY_MODIF(scene, stl->storage->is_playing);
stl->storage->simplify_fx = GP_SIMPLIFY_FX(scene, stl->storage->is_playing);
stl->storage->simplify_blend = GP_SIMPLIFY_BLEND(scene, stl->storage->is_playing);
/* save pixsize */
stl->storage->pixsize = DRW_viewport_pixelsize_get();
@ -485,6 +493,20 @@ void GPENCIL_cache_init(void *vedata)
stl->g_data->shgrps_grid = DRW_shgroup_create(e_data.gpencil_line_sh, psl->grid_pass);
}
/* blend layers pass */
psl->blend_pass = DRW_pass_create(
"GPencil Blend Layers Pass",
DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
DRWShadingGroup *blend_shgrp = DRW_shgroup_create(e_data.gpencil_blend_fullscreen_sh, psl->blend_pass);
DRW_shgroup_call_add(blend_shgrp, quad, NULL);
DRW_shgroup_uniform_texture_ref(blend_shgrp, "strokeColor", &e_data.temp_color_tx_a);
DRW_shgroup_uniform_texture_ref(blend_shgrp, "strokeDepth", &e_data.temp_depth_tx_a);
DRW_shgroup_uniform_texture_ref(blend_shgrp, "blendColor", &e_data.temp_color_tx_fx);
DRW_shgroup_uniform_texture_ref(blend_shgrp, "blendDepth", &e_data.temp_depth_tx_fx);
DRW_shgroup_uniform_int(blend_shgrp, "mode", &stl->storage->blend_mode, 1);
DRW_shgroup_uniform_int(blend_shgrp, "clamp_layer", &stl->storage->clamp_layer, 1);
DRW_shgroup_uniform_float(blend_shgrp, "blend_opacity", &stl->storage->blend_opacity, 1);
/* create effects passes */
if (!stl->storage->simplify_fx) {
GPENCIL_create_fx_passes(psl);
@ -639,12 +661,40 @@ static void gpencil_free_obj_runtime(GPENCIL_StorageList *stl)
tGPencilObjectCache *cache_ob = &stl->g_data->gp_object_cache[i];
bGPdata *gpd = cache_ob->gpd;
gpd->flag &= ~GP_DATA_CACHE_IS_DIRTY;
/* free shgrp array */
cache_ob->tot_layers = 0;
MEM_SAFE_FREE(cache_ob->shgrp_array);
}
/* free the cache itself */
MEM_SAFE_FREE(stl->g_data->gp_object_cache);
}
static void gpencil_draw_pass_range(
GPENCIL_FramebufferList *fbl, GPENCIL_StorageList *stl,
GPENCIL_PassList *psl, GPENCIL_TextureList *txl,
GPUFrameBuffer *fb,
DRWShadingGroup *init_shgrp, DRWShadingGroup *end_shgrp, bool multi)
{
if (init_shgrp == NULL) {
return;
}
/* previews don't use AA */
if ((!stl->storage->is_mat_preview) && (multi)) {
MULTISAMPLE_GP_SYNC_ENABLE(stl->storage->multisamples, fbl);
}
DRW_draw_pass_subset(
psl->stroke_pass, init_shgrp, end_shgrp);
if ((!stl->storage->is_mat_preview) && (multi)) {
MULTISAMPLE_GP_SYNC_DISABLE(stl->storage->multisamples, fbl, fb, txl);
}
}
/* draw scene */
void GPENCIL_draw_scene(void *ved)
{
@ -657,6 +707,10 @@ void GPENCIL_draw_scene(void *ved)
GPENCIL_TextureList *txl = ((GPENCIL_Data *)vedata)->txl;
tGPencilObjectCache *cache_ob;
tGPencilObjectCache_shgrp *array_elm = NULL;
DRWShadingGroup *init_shgrp = NULL;
DRWShadingGroup *end_shgrp = NULL;
const float clearcol[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
const DRWContextState *draw_ctx = DRW_context_state_get();
@ -712,7 +766,7 @@ void GPENCIL_draw_scene(void *ved)
for (int i = 0; i < stl->g_data->gp_cache_used; i++) {
cache_ob = &stl->g_data->gp_object_cache[i];
bGPdata *gpd = cache_ob->gpd;
init_shgrp = NULL;
/* Render stroke in separated framebuffer */
GPU_framebuffer_bind(fbl->temp_fb_a);
GPU_framebuffer_clear_color_depth(fbl->temp_fb_a, clearcol, 1.0f);
@ -720,19 +774,67 @@ void GPENCIL_draw_scene(void *ved)
/* Stroke Pass:
* draw only a subset that usually starts with a fill and ends with stroke
*/
if (cache_ob->init_grp) {
/* previews don't use AA */
if (!stl->storage->is_mat_preview) {
MULTISAMPLE_GP_SYNC_ENABLE(stl->storage->multisamples, fbl);
bool use_blend = false;
if (cache_ob->tot_layers > 0) {
for (int e = 0; e < cache_ob->tot_layers; e++) {
bool is_last = e == cache_ob->tot_layers - 1 ? true : false;
array_elm = &cache_ob->shgrp_array[e];
if (((array_elm->mode == eGplBlendMode_Normal) &&
(!use_blend) && (!array_elm->clamp_layer)) ||
( e == 0))
{
if (init_shgrp == NULL) {
init_shgrp = array_elm->init_shgrp;
}
end_shgrp = array_elm->end_shgrp;
}
else {
use_blend = true;
/* draw pending groups */
gpencil_draw_pass_range(
fbl, stl, psl, txl, fbl->temp_fb_a,
init_shgrp, end_shgrp, is_last);
/* draw current group in separated texture */
init_shgrp = array_elm->init_shgrp;
end_shgrp = array_elm->end_shgrp;
GPU_framebuffer_bind(fbl->temp_fb_fx);
GPU_framebuffer_clear_color_depth(fbl->temp_fb_fx, clearcol, 1.0f);
gpencil_draw_pass_range(
fbl, stl, psl, txl, fbl->temp_fb_fx,
init_shgrp, end_shgrp,
is_last);
/* Blend A texture and FX texture */
GPU_framebuffer_bind(fbl->temp_fb_b);
GPU_framebuffer_clear_color_depth(fbl->temp_fb_b, clearcol, 1.0f);
stl->storage->blend_mode = array_elm->mode;
stl->storage->clamp_layer = (int)array_elm->clamp_layer;
stl->storage->blend_opacity = array_elm->blend_opacity;
DRW_draw_pass(psl->blend_pass);
/* Copy B texture to A texture to follow loop */
e_data.input_depth_tx = e_data.temp_depth_tx_b;
e_data.input_color_tx = e_data.temp_color_tx_b;
GPU_framebuffer_bind(fbl->temp_fb_a);
GPU_framebuffer_clear_color_depth(fbl->temp_fb_a, clearcol, 1.0f);
DRW_draw_pass(psl->mix_pass_noblend);
/* prepare next group */
init_shgrp = NULL;
}
DRW_draw_pass_subset(
psl->stroke_pass, cache_ob->init_grp, cache_ob->end_grp);
}
/* last group */
gpencil_draw_pass_range(
fbl, stl, psl, txl, fbl->temp_fb_a,
init_shgrp, end_shgrp,
true);
}
if (!stl->storage->is_mat_preview) {
MULTISAMPLE_GP_SYNC_DISABLE(stl->storage->multisamples, fbl, fbl->temp_fb_a, txl);
}
}
/* Current buffer drawing */
if ((!is_render) && (cache_ob->is_dup_ob == false)) {
DRW_draw_pass(psl->drawing_pass);

@ -54,17 +54,23 @@ struct RenderLayer;
#define GP_SIMPLIFY_FILL(scene, playing) ((GP_SIMPLIFY_ONPLAY(playing) && (GP_SIMPLIFY(scene)) && (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_FILL)))
#define GP_SIMPLIFY_MODIF(scene, playing) ((GP_SIMPLIFY_ONPLAY(playing) && (GP_SIMPLIFY(scene)) && (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_MODIFIER)))
#define GP_SIMPLIFY_FX(scene, playing) ((GP_SIMPLIFY_ONPLAY(playing) && (GP_SIMPLIFY(scene)) && (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_FX)))
#define GP_SIMPLIFY_BLEND(scene, playing) ((GP_SIMPLIFY_ONPLAY(playing) && (GP_SIMPLIFY(scene)) && (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_BLEND)))
#define GP_IS_CAMERAVIEW ((rv3d != NULL) && (rv3d->persp == RV3D_CAMOB && v3d->camera))
/* *********** OBJECTS CACHE *********** */
typedef struct tGPencilObjectCache_shgrp {
int mode;
bool clamp_layer;
float blend_opacity;
DRWShadingGroup *init_shgrp;
DRWShadingGroup *end_shgrp;
} tGPencilObjectCache_shgrp;
/* used to save gpencil object data for drawing */
typedef struct tGPencilObjectCache {
struct Object *ob;
struct bGPdata *gpd;
DRWShadingGroup *init_grp;
DRWShadingGroup *end_grp;
int idx; /*original index, can change after sort */
/* effects */
@ -90,6 +96,11 @@ typedef struct tGPencilObjectCache {
/* GPU data size */
int tot_vertex;
int tot_triangles;
/* Save shader groups by layer */
int tot_layers;
tGPencilObjectCache_shgrp *shgrp_array;
} tGPencilObjectCache;
/* *********** LISTS *********** */
@ -127,10 +138,15 @@ typedef struct GPENCIL_Storage {
int tonemapping;
short multisamples;
int blend_mode;
int clamp_layer;
float blend_opacity;
/* simplify settings*/
bool simplify_fill;
bool simplify_modif;
bool simplify_fx;
bool simplify_blend;
/* Render Matrices and data */
float persmat[4][4], persinv[4][4];
@ -158,6 +174,7 @@ typedef struct GPENCIL_PassList {
struct DRWPass *background_pass;
struct DRWPass *paper_pass;
struct DRWPass *grid_pass;
struct DRWPass *blend_pass;
/* effects */
struct DRWPass *fx_shader_pass;
@ -232,6 +249,7 @@ typedef struct GPENCIL_e_data {
struct GPUShader *gpencil_drawing_fill_sh;
struct GPUShader *gpencil_fullscreen_sh;
struct GPUShader *gpencil_simple_fullscreen_sh;
struct GPUShader *gpencil_blend_fullscreen_sh;
struct GPUShader *gpencil_background_sh;
struct GPUShader *gpencil_paper_sh;

@ -0,0 +1,130 @@
in vec4 uvcoordsvar;
out vec4 FragColor;
uniform sampler2D strokeColor;
uniform sampler2D strokeDepth;
uniform sampler2D blendColor;
uniform sampler2D blendDepth;
uniform int mode;
uniform int clamp_layer;
uniform float blend_opacity;
#define ON 1
#define OFF 0
#define MODE_NORMAL 0
#define MODE_OVERLAY 1
#define MODE_ADD 2
#define MODE_SUB 3
#define MODE_MULTIPLY 4
#define MODE_DIVIDE 5
float overlay_color(float a, float b)
{
float rtn;
if (a < 0.5) {
rtn = 2.0 * a * b;
}
else {
rtn = 1.0 - 2.0 * (1.0 - a) * (1.0 - b);
}
return rtn;
}
vec4 get_blend_color(int mode, vec4 src_color, vec4 blend_color)
{
vec4 mix_color = blend_color;
vec4 outcolor;
if (mix_color.a == 0) {
outcolor = src_color;
}
else if (mode == MODE_OVERLAY) {
mix_color.rgb = mix_color.rgb * mix_color.a * blend_opacity;
outcolor.r = overlay_color(src_color.r, mix_color.r);
outcolor.g = overlay_color(src_color.g, mix_color.g);
outcolor.b = overlay_color(src_color.b, mix_color.b);
outcolor.a = src_color.a;
}
else if (mode == MODE_ADD){
mix_color.rgb = mix_color.rgb * mix_color.a * blend_opacity;
outcolor = src_color + mix_color;
outcolor.a = src_color.a;
}
else if (mode == MODE_SUB){
outcolor = src_color - mix_color;
outcolor.a = clamp(src_color.a - (mix_color.a * blend_opacity), 0.0, 1.0);
}
else if (mode == MODE_MULTIPLY) {
mix_color.rgb = mix_color.rgb * mix_color.a * blend_opacity;
outcolor = src_color * mix_color;
outcolor.a = src_color.a;
}
else if (mode == MODE_DIVIDE) {
mix_color.rgb = mix_color.rgb * mix_color.a * blend_opacity;
outcolor = src_color / mix_color;
outcolor.a = src_color.a;
}
else {
outcolor = mix_color * blend_opacity;;
outcolor.a = src_color.a;
}
return outcolor;
}
void main()
{
vec4 outcolor;
ivec2 uv = ivec2(gl_FragCoord.xy);
vec4 stroke_color = texelFetch(strokeColor, uv, 0).rgba;
float stroke_depth = texelFetch(strokeDepth, uv, 0).r;
vec4 mix_color = texelFetch(blendColor, uv, 0).rgba;
float mix_depth = texelFetch(blendDepth, uv, 0).r;
/* premult alpha factor to remove double blend effects */
if (stroke_color.a > 0) {
stroke_color = vec4(vec3(stroke_color.rgb / stroke_color.a), stroke_color.a);
}
if (mix_color.a > 0) {
mix_color = vec4(vec3(mix_color.rgb / mix_color.a), mix_color.a);
}
/* Normal mode */
if (mode == MODE_NORMAL) {
if (stroke_color.a > 0) {
if (mix_color.a > 0) {
FragColor = vec4(mix(stroke_color.rgb, mix_color.rgb, mix_color.a), stroke_color.a);
gl_FragDepth = mix_depth;
}
else {
FragColor = stroke_color;
gl_FragDepth = stroke_depth;
}
}
else {
if (clamp_layer == ON) {
discard;
}
else {
FragColor = mix_color;
gl_FragDepth = mix_depth;
}
}
return;
}
/* if not using mask, return mix color */
if ((stroke_color.a == 0) && (clamp_layer == OFF)) {
FragColor = mix_color;
gl_FragDepth = mix_depth;
return;
}
/* apply blend mode */
FragColor = get_blend_color(mode, stroke_color, mix_color);
gl_FragDepth = stroke_depth;
}

@ -269,6 +269,9 @@ typedef struct bGPDlayer {
float opacity; /* Opacity of the layer */
char viewlayername[64]; /* Name of the layer used to filter render output */
int blend_mode; /* blend modes */
char pad_[4];
bGPDlayer_Runtime runtime;
} bGPDlayer;
@ -292,6 +295,8 @@ typedef enum eGPDlayer_Flag {
GP_LAYER_VOLUMETRIC = (1 << 10),
/* Unlock color */
GP_LAYER_UNLOCK_COLOR = (1 << 12),
/* Mask Layer */
GP_LAYER_USE_MASK = (1 << 13),
} eGPDlayer_Flag;
/* bGPDlayer->onion_flag */
@ -300,6 +305,16 @@ typedef enum eGPDlayer_OnionFlag {
GP_LAYER_ONIONSKIN = (1 << 0),
} eGPDlayer_OnionFlag;
/* layer blend_mode */
typedef enum eGPLayerBlendModes {
eGplBlendMode_Normal = 0,
eGplBlendMode_Overlay = 1,
eGplBlendMode_Add = 2,
eGplBlendMode_Subtract = 3,
eGplBlendMode_Multiply = 4,
eGplBlendMode_Divide = 5,
} eGPLayerBlendModes;
/* ***************************************** */
/* GP Datablock */

@ -2144,7 +2144,9 @@ typedef enum eGPencil_SimplifyFlags {
/* Remove fill external line */
SIMPLIFY_GPENCIL_REMOVE_FILL_LINE = (1 << 4),
/* Simplify Shader FX */
SIMPLIFY_GPENCIL_FX = (1 << 5)
SIMPLIFY_GPENCIL_FX = (1 << 5),
/* Simplify layer blending */
SIMPLIFY_GPENCIL_BLEND = (1 << 6),
} eGPencil_SimplifyFlags;
/* ToolSettings.gpencil_*_align - Stroke Placement mode flags */

@ -78,6 +78,15 @@ const EnumPropertyItem rna_enum_gplayer_move_type_items[] = {
{0, NULL, 0, NULL, NULL}
};
static const EnumPropertyItem rna_enum_layer_blend_modes_items[] = {
{eGplBlendMode_Normal, "NORMAL", 0, "Normal", "" },
{eGplBlendMode_Overlay, "OVERLAY", 0, "Overlay", "" },
{eGplBlendMode_Add, "ADD", 0, "Add", "" },
{eGplBlendMode_Subtract, "SUBTRACT", 0, "Subtract", "" },
{eGplBlendMode_Multiply, "MULTIPLY", 0, "Multiply", "" },
{eGplBlendMode_Divide, "DIVIDE", 0, "Divide", "" },
{0, NULL, 0, NULL, NULL }
};
#endif
#ifdef RNA_RUNTIME
@ -1159,6 +1168,13 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "ViewLayer",
"Only include Layer in this View Layer render output (leave blank to include always)");
/* blend mode */
prop = RNA_def_property(srna, "blend_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "blend_mode");
RNA_def_property_enum_items(prop, rna_enum_layer_blend_modes_items);
RNA_def_property_ui_text(prop, "Blend Mode", "Blend mode");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* Flags */
prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_HIDE);
@ -1184,6 +1200,12 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Lock Material", "Disable Material editing");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
prop = RNA_def_property(srna, "clamp_layer", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_USE_MASK);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(prop, "Clamp Layer",
"Clamp any pixel outside underlying layers drawing");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
/* exposed as layers.active */
#if 0

@ -5344,6 +5344,11 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Simplify Shaders", "Do not apply shader fx");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
prop = RNA_def_property(srna, "simplify_gpencil_blend", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_BLEND);
RNA_def_property_ui_text(prop, "Layers Blending", "Do not display blend layers");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* persistent data */
prop = RNA_def_property(srna, "use_persistent_data", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mode", R_PERSISTENT_DATA);