LineArt: Stroke offset towards camera.
Allows the user to turn off in_front option for grease pencil object and offset strokes towards camera to allow depth interaction of the rest of the scene. Reviewed By: Antonio Vazquez (antoniov) Differential Revision: https://developer.blender.org/D12046
This commit is contained in:
parent
52ccb44501
commit
c3ef1c15f5
@ -1323,6 +1323,7 @@ static int object_gpencil_add_exec(bContext *C, wmOperator *op)
|
||||
const bool use_in_front = RNA_boolean_get(op->ptr, "use_in_front");
|
||||
const bool use_lights = RNA_boolean_get(op->ptr, "use_lights");
|
||||
const int stroke_depth_order = RNA_enum_get(op->ptr, "stroke_depth_order");
|
||||
const float stroke_depth_offset = RNA_float_get(op->ptr, "stroke_depth_offset");
|
||||
|
||||
ushort local_view_bits;
|
||||
float loc[3], rot[3];
|
||||
@ -1454,6 +1455,7 @@ static int object_gpencil_add_exec(bContext *C, wmOperator *op)
|
||||
if (stroke_depth_order == GP_DRAWMODE_3D) {
|
||||
gpd->draw_mode = GP_DRAWMODE_3D;
|
||||
}
|
||||
md->stroke_depth_offset = stroke_depth_offset;
|
||||
}
|
||||
|
||||
break;
|
||||
@ -1491,9 +1493,10 @@ static void object_add_ui(bContext *UNUSED(C), wmOperator *op)
|
||||
uiItemR(layout, op->ptr, "use_lights", 0, NULL, ICON_NONE);
|
||||
uiItemR(layout, op->ptr, "use_in_front", 0, NULL, ICON_NONE);
|
||||
bool in_front = RNA_boolean_get(op->ptr, "use_in_front");
|
||||
uiLayout *row = uiLayoutRow(layout, false);
|
||||
uiLayoutSetActive(row, !in_front);
|
||||
uiItemR(row, op->ptr, "stroke_depth_order", 0, NULL, ICON_NONE);
|
||||
uiLayout *col = uiLayoutColumn(layout, false);
|
||||
uiLayoutSetActive(col, !in_front);
|
||||
uiItemR(col, op->ptr, "stroke_depth_offset", 0, NULL, ICON_NONE);
|
||||
uiItemR(col, op->ptr, "stroke_depth_order", 0, NULL, ICON_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1532,9 +1535,18 @@ void OBJECT_OT_gpencil_add(wmOperatorType *ot)
|
||||
ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_object_gpencil_type_items, 0, "Type", "");
|
||||
RNA_def_boolean(ot->srna,
|
||||
"use_in_front",
|
||||
false,
|
||||
"In Front",
|
||||
true,
|
||||
"Show In Front",
|
||||
"Show line art grease pencil in front of everything");
|
||||
RNA_def_float(ot->srna,
|
||||
"stroke_depth_offset",
|
||||
0.05f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
"Stroke Offset",
|
||||
"Stroke offset for the line art modifier",
|
||||
0.0f,
|
||||
0.5f);
|
||||
RNA_def_boolean(
|
||||
ot->srna, "use_lights", false, "Use Lights", "Use lights for this grease pencil object");
|
||||
RNA_def_enum(
|
||||
@ -1543,7 +1555,7 @@ void OBJECT_OT_gpencil_add(wmOperatorType *ot)
|
||||
rna_enum_gpencil_add_stroke_depth_order_items,
|
||||
GP_DRAWMODE_3D,
|
||||
"Stroke Depth Order",
|
||||
"Defines how the strokes are ordered in 3D space for objects not displayed 'In Front'");
|
||||
"Defines how the strokes are ordered in 3D space for objects not displayed 'In Front')");
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@ -160,12 +160,14 @@ static void generateStrokes(GpencilModifierData *md, Depsgraph *depsgraph, Objec
|
||||
|
||||
LineartCache *local_lc = gpd->runtime.lineart_cache;
|
||||
if (!gpd->runtime.lineart_cache) {
|
||||
MOD_lineart_compute_feature_lines(depsgraph, lmd, &gpd->runtime.lineart_cache);
|
||||
MOD_lineart_compute_feature_lines(
|
||||
depsgraph, lmd, &gpd->runtime.lineart_cache, (!(ob->dtx & OB_DRAW_IN_FRONT)));
|
||||
MOD_lineart_destroy_render_data(lmd);
|
||||
}
|
||||
else {
|
||||
if (!(lmd->flags & LRT_GPENCIL_USE_CACHE)) {
|
||||
MOD_lineart_compute_feature_lines(depsgraph, lmd, &local_lc);
|
||||
MOD_lineart_compute_feature_lines(
|
||||
depsgraph, lmd, &local_lc, (!(ob->dtx & OB_DRAW_IN_FRONT)));
|
||||
MOD_lineart_destroy_render_data(lmd);
|
||||
}
|
||||
MOD_lineart_chain_clear_picked_flag(local_lc);
|
||||
@ -210,7 +212,8 @@ static void bakeModifier(Main *UNUSED(bmain),
|
||||
lmd->edge_types_override = lmd->edge_types;
|
||||
lmd->level_end_override = lmd->level_end;
|
||||
|
||||
MOD_lineart_compute_feature_lines(depsgraph, lmd, &gpd->runtime.lineart_cache);
|
||||
MOD_lineart_compute_feature_lines(
|
||||
depsgraph, lmd, &gpd->runtime.lineart_cache, (!(ob->dtx & OB_DRAW_IN_FRONT)));
|
||||
MOD_lineart_destroy_render_data(lmd);
|
||||
}
|
||||
|
||||
@ -412,14 +415,23 @@ static void style_panel_draw(const bContext *UNUSED(C), Panel *panel)
|
||||
static void occlusion_panel_draw(const bContext *UNUSED(C), Panel *panel)
|
||||
{
|
||||
uiLayout *layout = panel->layout;
|
||||
PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, NULL);
|
||||
PointerRNA ob_ptr;
|
||||
PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, &ob_ptr);
|
||||
|
||||
const bool is_baked = RNA_boolean_get(ptr, "is_baked");
|
||||
|
||||
const bool use_multiple_levels = RNA_boolean_get(ptr, "use_multiple_levels");
|
||||
const bool show_in_front = RNA_boolean_get(&ob_ptr, "show_in_front");
|
||||
|
||||
uiLayoutSetPropSep(layout, true);
|
||||
uiLayoutSetEnabled(layout, !is_baked);
|
||||
|
||||
const bool use_multiple_levels = RNA_boolean_get(ptr, "use_multiple_levels");
|
||||
if (!show_in_front) {
|
||||
uiItemL(layout, IFACE_("Object is not in front"), ICON_INFO);
|
||||
}
|
||||
|
||||
layout = uiLayoutColumn(layout, false);
|
||||
uiLayoutSetActive(layout, show_in_front);
|
||||
|
||||
uiItemR(layout, ptr, "use_multiple_levels", 0, IFACE_("Range"), ICON_NONE);
|
||||
|
||||
@ -447,11 +459,14 @@ static bool anything_showing_through(PointerRNA *ptr)
|
||||
static void material_mask_panel_draw_header(const bContext *UNUSED(C), Panel *panel)
|
||||
{
|
||||
uiLayout *layout = panel->layout;
|
||||
PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, NULL);
|
||||
PointerRNA ob_ptr;
|
||||
PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, &ob_ptr);
|
||||
|
||||
const bool is_baked = RNA_boolean_get(ptr, "is_baked");
|
||||
const bool show_in_front = RNA_boolean_get(&ob_ptr, "show_in_front");
|
||||
|
||||
uiLayoutSetEnabled(layout, !is_baked);
|
||||
uiLayoutSetActive(layout, anything_showing_through(ptr));
|
||||
uiLayoutSetActive(layout, (!show_in_front) && anything_showing_through(ptr));
|
||||
|
||||
uiItemR(layout, ptr, "use_material_mask", 0, IFACE_("Material Mask"), ICON_NONE);
|
||||
}
|
||||
@ -654,6 +669,27 @@ static void bake_panel_draw(const bContext *UNUSED(C), Panel *panel)
|
||||
uiItemO(col, NULL, ICON_NONE, "OBJECT_OT_lineart_clear_all");
|
||||
}
|
||||
|
||||
static void composition_panel_draw(const bContext *UNUSED(C), Panel *panel)
|
||||
{
|
||||
PointerRNA ob_ptr;
|
||||
PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, &ob_ptr);
|
||||
|
||||
uiLayout *layout = panel->layout;
|
||||
|
||||
const bool show_in_front = RNA_boolean_get(&ob_ptr, "show_in_front");
|
||||
|
||||
uiLayoutSetPropSep(layout, true);
|
||||
|
||||
if (show_in_front) {
|
||||
uiItemL(layout, IFACE_("Object is shown in front"), ICON_ERROR);
|
||||
}
|
||||
|
||||
uiLayout *row = uiLayoutRow(layout, false);
|
||||
uiLayoutSetActive(row, !show_in_front);
|
||||
|
||||
uiItemR(row, ptr, "stroke_depth_offset", UI_ITEM_R_SLIDER, IFACE_("Depth Offset"), ICON_NONE);
|
||||
}
|
||||
|
||||
static void panelRegister(ARegionType *region_type)
|
||||
{
|
||||
PanelType *panel_type = gpencil_modifier_panel_register(
|
||||
@ -681,6 +717,8 @@ static void panelRegister(ARegionType *region_type)
|
||||
region_type, "chaining", "Chaining", NULL, chaining_panel_draw, panel_type);
|
||||
gpencil_modifier_subpanel_register(
|
||||
region_type, "vgroup", "Vertex Weight Transfer", NULL, vgroup_panel_draw, panel_type);
|
||||
gpencil_modifier_subpanel_register(
|
||||
region_type, "composition", "Composition", NULL, composition_panel_draw, panel_type);
|
||||
gpencil_modifier_subpanel_register(
|
||||
region_type, "bake", "Bake", NULL, bake_panel_draw, panel_type);
|
||||
}
|
||||
|
@ -595,13 +595,15 @@ void MOD_lineart_chain_connect(LineartRenderBuffer *rb);
|
||||
void MOD_lineart_chain_discard_short(LineartRenderBuffer *rb, const float threshold);
|
||||
void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshold_rad);
|
||||
void MOD_lineart_smooth_chains(LineartRenderBuffer *rb, float tolerance);
|
||||
void MOD_lineart_chain_offset_towards_camera(LineartRenderBuffer *rb, float dist);
|
||||
|
||||
int MOD_lineart_chain_count(const LineartEdgeChain *ec);
|
||||
void MOD_lineart_chain_clear_picked_flag(LineartCache *lc);
|
||||
|
||||
bool MOD_lineart_compute_feature_lines(struct Depsgraph *depsgraph,
|
||||
struct LineartGpencilModifierData *lmd,
|
||||
LineartCache **cached_result);
|
||||
struct LineartCache **cached_result,
|
||||
bool enable_stroke_offset);
|
||||
|
||||
struct Scene;
|
||||
|
||||
|
@ -926,9 +926,9 @@ void MOD_lineart_chain_clear_picked_flag(LineartCache *lc)
|
||||
|
||||
void MOD_lineart_smooth_chains(LineartRenderBuffer *rb, float tolerance)
|
||||
{
|
||||
LISTBASE_FOREACH (LineartEdgeChain *, rlc, &rb->chains) {
|
||||
LISTBASE_FOREACH (LineartEdgeChain *, ec, &rb->chains) {
|
||||
LineartEdgeChainItem *next_eci;
|
||||
for (LineartEdgeChainItem *eci = rlc->chain.first; eci; eci = next_eci) {
|
||||
for (LineartEdgeChainItem *eci = ec->chain.first; eci; eci = next_eci) {
|
||||
next_eci = eci->next;
|
||||
LineartEdgeChainItem *eci2, *eci3, *eci4;
|
||||
|
||||
@ -944,7 +944,7 @@ void MOD_lineart_smooth_chains(LineartRenderBuffer *rb, float tolerance)
|
||||
if (dist_to_line_segment_v2(eci3->pos, eci->pos, eci2->pos) < tolerance) {
|
||||
/* And if p4 is on the extension of p1-p2 , we remove p3. */
|
||||
if ((eci4 = eci3->next) && (dist_to_line_v2(eci4->pos, eci->pos, eci2->pos) < tolerance)) {
|
||||
BLI_remlink(&rlc->chain, eci3);
|
||||
BLI_remlink(&ec->chain, eci3);
|
||||
next_eci = eci;
|
||||
}
|
||||
}
|
||||
@ -1008,3 +1008,35 @@ void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshol
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MOD_lineart_chain_offset_towards_camera(LineartRenderBuffer *rb, float dist)
|
||||
{
|
||||
float dir[3];
|
||||
float cam[3];
|
||||
float view[3];
|
||||
float view_clamp[3];
|
||||
copy_v3fl_v3db(cam, rb->camera_pos);
|
||||
copy_v3fl_v3db(view, rb->view_vector);
|
||||
if (rb->cam_is_persp) {
|
||||
LISTBASE_FOREACH (LineartEdgeChain *, ec, &rb->chains) {
|
||||
LISTBASE_FOREACH (LineartEdgeChainItem *, eci, &ec->chain) {
|
||||
sub_v3_v3v3(dir, cam, eci->gpos);
|
||||
float orig_len = len_v3(dir);
|
||||
normalize_v3(dir);
|
||||
mul_v3_fl(dir, MIN2(dist, orig_len - rb->near_clip));
|
||||
add_v3_v3(eci->gpos, dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
LISTBASE_FOREACH (LineartEdgeChain *, ec, &rb->chains) {
|
||||
LISTBASE_FOREACH (LineartEdgeChainItem *, eci, &ec->chain) {
|
||||
sub_v3_v3v3(dir, cam, eci->gpos);
|
||||
float len_lim = dot_v3v3(view, dir) - rb->near_clip;
|
||||
normalize_v3_v3(view_clamp, view);
|
||||
mul_v3_fl(view_clamp, MIN2(dist, len_lim));
|
||||
add_v3_v3(eci->gpos, view_clamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4076,7 +4076,8 @@ static LineartBoundingArea *lineart_bounding_area_next(LineartBoundingArea *this
|
||||
*/
|
||||
bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph,
|
||||
LineartGpencilModifierData *lmd,
|
||||
LineartCache **cached_result)
|
||||
LineartCache **cached_result,
|
||||
bool enable_stroke_depth_offset)
|
||||
{
|
||||
LineartRenderBuffer *rb;
|
||||
Scene *scene = DEG_get_evaluated_scene(depsgraph);
|
||||
@ -4189,6 +4190,10 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph,
|
||||
MOD_lineart_chain_split_angle(rb, rb->angle_splitting_threshold);
|
||||
}
|
||||
|
||||
if (enable_stroke_depth_offset && lmd->stroke_depth_offset > FLT_EPSILON) {
|
||||
MOD_lineart_chain_offset_towards_camera(rb, lmd->stroke_depth_offset);
|
||||
}
|
||||
|
||||
/* Finally transfer the result list into cache. */
|
||||
memcpy(&lc->chains, &rb->chains, sizeof(ListBase));
|
||||
|
||||
|
@ -118,12 +118,12 @@ static bool bake_strokes(Object *ob,
|
||||
}
|
||||
LineartCache *local_lc = *lc;
|
||||
if (!(*lc)) {
|
||||
MOD_lineart_compute_feature_lines(dg, lmd, lc);
|
||||
MOD_lineart_compute_feature_lines(dg, lmd, lc, (!(ob->dtx & OB_DRAW_IN_FRONT)));
|
||||
MOD_lineart_destroy_render_data(lmd);
|
||||
}
|
||||
else {
|
||||
if (is_first || (!(lmd->flags & LRT_GPENCIL_USE_CACHE))) {
|
||||
MOD_lineart_compute_feature_lines(dg, lmd, &local_lc);
|
||||
MOD_lineart_compute_feature_lines(dg, lmd, &local_lc, (!(ob->dtx & OB_DRAW_IN_FRONT)));
|
||||
MOD_lineart_destroy_render_data(lmd);
|
||||
}
|
||||
MOD_lineart_chain_clear_picked_flag(local_lc);
|
||||
|
@ -319,6 +319,7 @@
|
||||
.angle_splitting_threshold = DEG2RAD(60.0f), \
|
||||
.chaining_image_threshold = 0.001f, \
|
||||
.chain_smooth_tolerance = 0.2f,\
|
||||
.stroke_depth_offset = 0.05,\
|
||||
}
|
||||
|
||||
#define _DNA_DEFAULT_LengthGpencilModifierData \
|
||||
|
@ -1042,7 +1042,6 @@ typedef struct LineartGpencilModifierData {
|
||||
|
||||
/** Strength for smoothing jagged chains. */
|
||||
float chain_smooth_tolerance;
|
||||
int _pad1;
|
||||
|
||||
/* CPU mode */
|
||||
float chaining_image_threshold;
|
||||
@ -1053,6 +1052,9 @@ typedef struct LineartGpencilModifierData {
|
||||
/* #eLineArtGPencilModifierFlags, modifier internal state. */
|
||||
int flags;
|
||||
|
||||
/* Move strokes towards camera to avoid clipping while preserve depth for the viewport. */
|
||||
float stroke_depth_offset;
|
||||
|
||||
/* Runtime data. */
|
||||
|
||||
/* Because we can potentially only compute features lines once per modifier stack (Use Cache), we
|
||||
|
@ -3200,6 +3200,14 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
|
||||
"separate stroke for each overlapping type");
|
||||
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "stroke_depth_offset", PROP_FLOAT, PROP_DISTANCE);
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Stroke Depth Offset",
|
||||
"Move strokes slightly towards the camera to avoid clipping while "
|
||||
"preserve depth for the viewport");
|
||||
RNA_def_property_ui_range(prop, 0.0f, 0.5f, 0.001f, 4);
|
||||
RNA_def_property_update(prop, NC_SCENE, "rna_GpencilModifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "source_type", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, modifier_lineart_source_type);
|
||||
RNA_def_property_ui_text(prop, "Source Type", "Line art stroke source type");
|
||||
|
Loading…
Reference in New Issue
Block a user