Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--release/scripts/startup/bl_ui/properties_data_gpencil.py15
-rw-r--r--release/scripts/startup/bl_ui/properties_grease_pencil_common.py5
-rw-r--r--release/scripts/startup/bl_ui/properties_render.py3
-rw-r--r--release/scripts/startup/bl_ui/space_topbar.py14
-rw-r--r--source/blender/draw/CMakeLists.txt1
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_cache_utils.c8
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_draw_utils.c125
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.c124
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.h22
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_blend_frag.glsl130
-rw-r--r--source/blender/makesdna/DNA_gpencil_types.h15
-rw-r--r--source/blender/makesdna/DNA_scene_types.h4
-rw-r--r--source/blender/makesrna/intern/rna_gpencil.c22
-rw-r--r--source/blender/makesrna/intern/rna_scene.c5
14 files changed, 428 insertions, 65 deletions
diff --git a/release/scripts/startup/bl_ui/properties_data_gpencil.py b/release/scripts/startup/bl_ui/properties_data_gpencil.py
index 949a48ed7f1..558c3c190b6 100644
--- a/release/scripts/startup/bl_ui/properties_data_gpencil.py
+++ b/release/scripts/startup/bl_ui/properties_data_gpencil.py
@@ -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'
diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
index 296e05a709d..b18254a9102 100644
--- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
+++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
@@ -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)
diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py
index 026b306b49e..8cfbb09ad04 100644
--- a/release/scripts/startup/bl_ui/properties_render.py
+++ b/release/scripts/startup/bl_ui/properties_render.py
@@ -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
diff --git a/release/scripts/startup/bl_ui/space_topbar.py b/release/scripts/startup/bl_ui/space_topbar.py
index 4fc2b12e950..a769268bb22 100644
--- a/release/scripts/startup/bl_ui/space_topbar.py
+++ b/release/scripts/startup/bl_ui/space_topbar.py
@@ -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"
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index 05865ba5636..70dfa589cdc 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -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)
diff --git a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
index 15ac3f37add..5478c4a60b9 100644
--- a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
+++ b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
@@ -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;
diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
index c8b70953f87..e4d6fa582b8 100644
--- a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
+++ b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
@@ -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,21 +807,28 @@ static void gpencil_draw_strokes(
}
}
- /* fill */
- if ((gp_style->flag & GP_STYLE_FILL_SHOW) &&
- (!stl->storage->simplify_fill))
+ /* hide any blend layer */
+ if ((!stl->storage->simplify_blend) ||
+ (gpl->blend_mode == eGplBlendMode_Normal))
{
- gpencil_add_fill_vertexdata(
- cache, ob, gpl, derived_gpf, gps,
- opacity, tintcolor, false, custonion);
- }
- /* stroke */
- if ((gp_style->flag & GP_STYLE_STROKE_SHOW) &&
- (gp_style->stroke_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH))
- {
- gpencil_add_stroke_vertexdata(
- cache, ob, gpl, derived_gpf, gps,
- opacity, tintcolor, false, custonion);
+ /* fill */
+ if ((gp_style->flag & GP_STYLE_FILL_SHOW) &&
+ (!stl->storage->simplify_fill) &&
+ ((gps->flag & GP_STROKE_NOFILL) == 0))
+ {
+ gpencil_add_fill_vertexdata(
+ cache, ob, gpl, derived_gpf, gps,
+ opacity, tintcolor, false, custonion);
+ }
+ /* stroke */
+ if ((gp_style->flag & GP_STYLE_STROKE_SHOW) &&
+ ((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);
+ }
}
}
@@ -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);
}
}
}
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c
index 7be06d501f1..a80ad133d09 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.c
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.c
@@ -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);
-
- if (!stl->storage->is_mat_preview) {
- MULTISAMPLE_GP_SYNC_DISABLE(stl->storage->multisamples, fbl, fbl->temp_fb_a, txl);
}
+ /* last group */
+ gpencil_draw_pass_range(
+ fbl, stl, psl, txl, fbl->temp_fb_a,
+ init_shgrp, end_shgrp,
+ true);
}
+
/* Current buffer drawing */
if ((!is_render) && (cache_ob->is_dup_ob == false)) {
DRW_draw_pass(psl->drawing_pass);
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h
index 0fe25ba9f0f..b8b526cb873 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.h
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.h
@@ -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;
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_blend_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_blend_frag.glsl
new file mode 100644
index 00000000000..2ba02beecdb
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_blend_frag.glsl
@@ -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;
+}
diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h
index 8a1bccc6957..cebdc4b29b9 100644
--- a/source/blender/makesdna/DNA_gpencil_types.h
+++ b/source/blender/makesdna/DNA_gpencil_types.h
@@ -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 */
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 7ab4187de1a..e2cfd79ca93 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -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 */
diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c
index 8c11909d022..d6257aa0c1b 100644
--- a/source/blender/makesrna/intern/rna_gpencil.c
+++ b/source/blender/makesrna/intern/rna_gpencil.c
@@ -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
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index eeb48b67d28..9d943dca9ec 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -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);