LineArt: Shadow and related functionalities.
This patch includes the full shadow functionality for LineArt: - Light contour and cast shadow lines. - Lit/shaded region selection. - Enclosed light/shadow shape calculation. - Silhouette/anti-silhouette selection. - Intersection priority based on shadow edge identifier. Reviewed By: Sebastian Parborg (zeddb) Differential Revision: https://developer.blender.org/D15109
This commit is contained in:
parent
2ac5b55289
commit
6dd8ceef2a
Notes:
blender-bot
2025-02-14 01:29:06 +00:00
Referenced by issue #98498, LineArt shadow functionality design notes
@ -96,6 +96,12 @@ class COLLECTION_PT_lineart_collection(CollectionButtonsPanel, Panel):
|
||||
if i == 3:
|
||||
row = col.row(align=True)
|
||||
|
||||
row = layout.row(heading="Intersection Priority")
|
||||
row.prop(collection, "use_lineart_intersection_priority", text="")
|
||||
subrow = row.row()
|
||||
subrow.active = collection.use_lineart_intersection_priority
|
||||
subrow.prop(collection, "lineart_intersection_priority", text="")
|
||||
|
||||
|
||||
class COLLECTION_PT_collection_custom_props(CollectionButtonsPanel, PropertyPanel, Panel):
|
||||
_context_path = "collection"
|
||||
|
@ -287,6 +287,12 @@ class MATERIAL_PT_lineart(MaterialButtonsPanel, Panel):
|
||||
row = layout.row(align=True, heading="Custom Occlusion")
|
||||
row.prop(lineart, "mat_occlusion", text="Levels")
|
||||
|
||||
row = layout.row(heading="Intersection Priority")
|
||||
row.prop(lineart, "use_intersection_priority_override", text="")
|
||||
subrow = row.row()
|
||||
subrow.active = lineart.use_intersection_priority_override
|
||||
subrow.prop(lineart, "intersection_priority", text="")
|
||||
|
||||
|
||||
classes = (
|
||||
MATERIAL_MT_context_menu,
|
||||
|
@ -317,6 +317,12 @@ class OBJECT_PT_lineart(ObjectButtonsPanel, Panel):
|
||||
subrow.active = lineart.use_crease_override
|
||||
subrow.prop(lineart, "crease_threshold", slider=True, text="")
|
||||
|
||||
row = layout.row(heading="Intersection Priority")
|
||||
row.prop(lineart, "use_intersection_priority_override", text="")
|
||||
subrow = row.row()
|
||||
subrow.active = lineart.use_intersection_priority_override
|
||||
subrow.prop(lineart, "intersection_priority", text="")
|
||||
|
||||
|
||||
class OBJECT_PT_motion_paths(MotionPathButtonsPanel, Panel):
|
||||
#bl_label = "Object Motion Paths"
|
||||
|
@ -383,6 +383,8 @@ typedef struct GpencilLineartLimitInfo {
|
||||
char min_level;
|
||||
char max_level;
|
||||
short edge_types;
|
||||
char shadow_selection;
|
||||
char silhouette_selection;
|
||||
} GpencilLineartLimitInfo;
|
||||
|
||||
GpencilLineartLimitInfo BKE_gpencil_get_lineart_modifier_limits(const struct Object *ob);
|
||||
|
@ -221,6 +221,9 @@ GpencilLineartLimitInfo BKE_gpencil_get_lineart_modifier_limits(const Object *ob
|
||||
info.max_level = MAX2(info.max_level,
|
||||
(lmd->use_multiple_levels ? lmd->level_end : lmd->level_start));
|
||||
info.edge_types |= lmd->edge_types;
|
||||
info.shadow_selection = MAX2(lmd->shadow_selection, info.shadow_selection);
|
||||
info.silhouette_selection = MAX2(lmd->silhouette_selection, info.silhouette_selection);
|
||||
is_first = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -237,11 +240,15 @@ void BKE_gpencil_set_lineart_modifier_limits(GpencilModifierData *md,
|
||||
lmd->level_start_override = info->min_level;
|
||||
lmd->level_end_override = info->max_level;
|
||||
lmd->edge_types_override = info->edge_types;
|
||||
lmd->shadow_selection_override = info->shadow_selection;
|
||||
lmd->shadow_use_silhouette_override = info->silhouette_selection;
|
||||
}
|
||||
else {
|
||||
lmd->level_start_override = lmd->level_start;
|
||||
lmd->level_end_override = lmd->level_end;
|
||||
lmd->edge_types_override = lmd->edge_types;
|
||||
lmd->shadow_selection_override = lmd->shadow_selection;
|
||||
lmd->shadow_use_silhouette_override = lmd->silhouette_selection;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,6 +40,10 @@ MINLINE void swap_v2_v2(float a[2], float b[2]);
|
||||
MINLINE void swap_v3_v3(float a[3], float b[3]);
|
||||
MINLINE void swap_v4_v4(float a[4], float b[4]);
|
||||
|
||||
MINLINE void swap_v2_v2_db(double a[2], double b[2]);
|
||||
MINLINE void swap_v3_v3_db(double a[3], double b[3]);
|
||||
MINLINE void swap_v4_v4_db(double a[4], double b[4]);
|
||||
|
||||
/* unsigned char */
|
||||
|
||||
MINLINE void copy_v2_v2_uchar(unsigned char r[2], const unsigned char a[2]);
|
||||
|
@ -316,6 +316,27 @@ MINLINE void swap_v4_v4(float a[4], float b[4])
|
||||
SWAP(float, a[3], b[3]);
|
||||
}
|
||||
|
||||
MINLINE void swap_v2_v2_db(double a[2], double b[2])
|
||||
{
|
||||
SWAP(double, a[0], b[0]);
|
||||
SWAP(double, a[1], b[1]);
|
||||
}
|
||||
|
||||
MINLINE void swap_v3_v3_db(double a[3], double b[3])
|
||||
{
|
||||
SWAP(double, a[0], b[0]);
|
||||
SWAP(double, a[1], b[1]);
|
||||
SWAP(double, a[2], b[2]);
|
||||
}
|
||||
|
||||
MINLINE void swap_v4_v4_db(double a[4], double b[4])
|
||||
{
|
||||
SWAP(double, a[0], b[0]);
|
||||
SWAP(double, a[1], b[1]);
|
||||
SWAP(double, a[2], b[2]);
|
||||
SWAP(double, a[3], b[3]);
|
||||
}
|
||||
|
||||
/* float args -> vec */
|
||||
|
||||
MINLINE void copy_v2_fl2(float v[2], float x, float y)
|
||||
|
@ -3126,6 +3126,17 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
|
||||
}
|
||||
}
|
||||
FOREACH_NODETREE_END;
|
||||
|
||||
LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
|
||||
LISTBASE_FOREACH (GpencilModifierData *, gpd, &ob->greasepencil_modifiers) {
|
||||
if (gpd->type == eGpencilModifierType_Lineart) {
|
||||
LineartGpencilModifierData *lmd = (LineartGpencilModifierData *)gpd;
|
||||
lmd->shadow_camera_near = 0.1f;
|
||||
lmd->shadow_camera_far = 200.0f;
|
||||
lmd->shadow_camera_size = 200.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_ATLEAST(bmain, 303, 2)) {
|
||||
|
@ -68,6 +68,7 @@ set(SRC
|
||||
intern/lineart/lineart_cpp_bridge.cc
|
||||
intern/lineart/lineart_cpu.c
|
||||
intern/lineart/lineart_ops.c
|
||||
intern/lineart/lineart_shadow.c
|
||||
intern/lineart/lineart_util.c
|
||||
|
||||
intern/lineart/MOD_lineart.h
|
||||
|
@ -88,6 +88,8 @@ static void generate_strokes_actual(
|
||||
lmd->intersection_mask,
|
||||
lmd->thickness,
|
||||
lmd->opacity,
|
||||
lmd->shadow_selection,
|
||||
lmd->silhouette_selection,
|
||||
lmd->source_vertex_group,
|
||||
lmd->vgname,
|
||||
lmd->flags);
|
||||
@ -193,6 +195,7 @@ static void bakeModifier(Main *UNUSED(bmain),
|
||||
* modifiers in the stack. */
|
||||
lmd->edge_types_override = lmd->edge_types;
|
||||
lmd->level_end_override = lmd->level_end;
|
||||
lmd->shadow_selection_override = lmd->shadow_selection;
|
||||
|
||||
MOD_lineart_compute_feature_lines(
|
||||
depsgraph, lmd, &gpd->runtime.lineart_cache, (!(ob->dtx & OB_DRAW_IN_FRONT)));
|
||||
@ -263,6 +266,10 @@ static void updateDepsgraph(GpencilModifierData *md,
|
||||
DEG_add_object_relation(
|
||||
ctx->node, ctx->scene->camera, DEG_OB_COMP_PARAMETERS, "Line Art Modifier");
|
||||
}
|
||||
if (lmd->light_contour_object) {
|
||||
DEG_add_object_relation(
|
||||
ctx->node, lmd->light_contour_object, DEG_OB_COMP_TRANSFORM, "Line Art Modifier");
|
||||
}
|
||||
}
|
||||
|
||||
static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
|
||||
@ -274,6 +281,7 @@ static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk,
|
||||
|
||||
walk(userData, ob, (ID **)&lmd->source_object, IDWALK_CB_NOP);
|
||||
walk(userData, ob, (ID **)&lmd->source_camera, IDWALK_CB_NOP);
|
||||
walk(userData, ob, (ID **)&lmd->light_contour_object, IDWALK_CB_NOP);
|
||||
}
|
||||
|
||||
static void panel_draw(const bContext *UNUSED(C), Panel *panel)
|
||||
@ -340,31 +348,107 @@ static void edge_types_panel_draw(const bContext *UNUSED(C), Panel *panel)
|
||||
const bool is_baked = RNA_boolean_get(ptr, "is_baked");
|
||||
const bool use_cache = RNA_boolean_get(ptr, "use_cache");
|
||||
const bool is_first = BKE_gpencil_is_first_lineart_in_stack(ob_ptr.data, ptr->data);
|
||||
const bool has_light = RNA_pointer_get(ptr, "light_contour_object").data != NULL;
|
||||
|
||||
uiLayoutSetEnabled(layout, !is_baked);
|
||||
|
||||
uiLayoutSetPropSep(layout, true);
|
||||
|
||||
uiLayout *sub = uiLayoutRow(layout, false);
|
||||
uiLayoutSetActive(sub, has_light);
|
||||
uiItemR(sub, ptr, "shadow_region_filtering", 0, IFACE_("Illumination Filtering"), ICON_NONE);
|
||||
|
||||
uiLayout *col = uiLayoutColumn(layout, true);
|
||||
|
||||
uiItemR(col, ptr, "use_contour", 0, IFACE_("Contour"), ICON_NONE);
|
||||
uiItemR(col, ptr, "use_loose", 0, IFACE_("Loose"), ICON_NONE);
|
||||
uiItemR(col, ptr, "use_material", 0, IFACE_("Material Borders"), ICON_NONE);
|
||||
uiItemR(col, ptr, "use_edge_mark", 0, IFACE_("Edge Marks"), ICON_NONE);
|
||||
uiItemR(col, ptr, "use_intersection", 0, IFACE_("Intersections"), ICON_NONE);
|
||||
sub = uiLayoutRowWithHeading(col, false, IFACE_("Create"));
|
||||
uiItemR(sub, ptr, "use_contour", 0, "", ICON_NONE);
|
||||
|
||||
uiLayout *sub = uiLayoutRowWithHeading(col, false, IFACE_("Crease"));
|
||||
uiLayout *entry = uiLayoutRow(sub, true);
|
||||
uiLayoutSetActive(entry, RNA_boolean_get(ptr, "use_contour"));
|
||||
uiItemR(entry, ptr, "silhouette_filtering", 0, "", ICON_NONE);
|
||||
|
||||
const int silhouette_filtering = RNA_enum_get(ptr, "silhouette_filtering");
|
||||
if (silhouette_filtering != LRT_SILHOUETTE_FILTER_NONE) {
|
||||
uiItemR(entry, ptr, "use_invert_silhouette", 0, "", ICON_ARROW_LEFTRIGHT);
|
||||
}
|
||||
|
||||
sub = uiLayoutRow(col, false);
|
||||
uiItemR(sub, ptr, "use_crease", 0, "", ICON_NONE);
|
||||
uiLayout *entry = uiLayoutRow(sub, false);
|
||||
entry = uiLayoutColumn(sub, false);
|
||||
uiItemL(entry, IFACE_("Crease"), ICON_NONE);
|
||||
uiLayoutSetActive(entry, RNA_boolean_get(ptr, "use_crease") || is_first);
|
||||
if (use_cache && !is_first) {
|
||||
uiItemL(entry, IFACE_("Angle Cached"), ICON_INFO);
|
||||
uiItemL(entry, IFACE_("Crease Angle Cached"), ICON_INFO);
|
||||
}
|
||||
else {
|
||||
uiItemR(entry, ptr, "crease_threshold", UI_ITEM_R_SLIDER, " ", ICON_NONE);
|
||||
uiItemR(entry,
|
||||
ptr,
|
||||
"crease_threshold",
|
||||
UI_ITEM_R_SLIDER | UI_ITEM_R_FORCE_BLANK_DECORATE,
|
||||
IFACE_("Default Angle"),
|
||||
ICON_NONE);
|
||||
}
|
||||
|
||||
uiItemR(layout, ptr, "use_overlap_edge_type_support", 0, IFACE_("Allow Overlap"), ICON_NONE);
|
||||
uiItemR(col, ptr, "use_intersection", 0, IFACE_("Intersections"), ICON_NONE);
|
||||
uiItemR(col, ptr, "use_material", 0, IFACE_("Material Borders"), ICON_NONE);
|
||||
uiItemR(col, ptr, "use_edge_mark", 0, IFACE_("Edge Marks"), ICON_NONE);
|
||||
uiItemR(col, ptr, "use_loose", 0, IFACE_("Loose"), ICON_NONE);
|
||||
|
||||
entry = uiLayoutColumn(col, false);
|
||||
uiLayoutSetActive(entry, has_light);
|
||||
|
||||
sub = uiLayoutRow(entry, false);
|
||||
uiItemR(sub, ptr, "use_light_contour", 0, IFACE_("Light Contour"), ICON_NONE);
|
||||
|
||||
uiItemR(entry, ptr, "use_shadow", 0, IFACE_("Cast Shadow"), ICON_NONE);
|
||||
|
||||
uiItemL(layout, IFACE_("Options"), ICON_NONE);
|
||||
|
||||
sub = uiLayoutColumn(layout, false);
|
||||
if (use_cache && !is_first) {
|
||||
uiItemL(sub, IFACE_("Type overlapping cached"), ICON_INFO);
|
||||
}
|
||||
else {
|
||||
uiItemR(sub,
|
||||
ptr,
|
||||
"use_overlap_edge_type_support",
|
||||
0,
|
||||
IFACE_("Allow Overlapping Types"),
|
||||
ICON_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
static void options_light_reference_draw(const bContext *UNUSED(C), Panel *panel)
|
||||
{
|
||||
uiLayout *layout = panel->layout;
|
||||
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_cache = RNA_boolean_get(ptr, "use_cache");
|
||||
const bool has_light = RNA_pointer_get(ptr, "light_contour_object").data != NULL;
|
||||
const bool is_first = BKE_gpencil_is_first_lineart_in_stack(ob_ptr.data, ptr->data);
|
||||
|
||||
uiLayoutSetPropSep(layout, true);
|
||||
uiLayoutSetEnabled(layout, !is_baked);
|
||||
|
||||
if (use_cache && !is_first) {
|
||||
uiItemL(layout, "Cached from the first line art modifier.", ICON_INFO);
|
||||
return;
|
||||
}
|
||||
|
||||
uiItemR(layout, ptr, "light_contour_object", 0, NULL, ICON_NONE);
|
||||
|
||||
uiLayout *remaining = uiLayoutColumn(layout, false);
|
||||
uiLayoutSetActive(remaining, has_light);
|
||||
|
||||
uiItemR(remaining, ptr, "shadow_camera_size", 0, NULL, ICON_NONE);
|
||||
|
||||
uiLayout *col = uiLayoutColumn(remaining, true);
|
||||
uiItemR(col, ptr, "shadow_camera_near", 0, "Near", ICON_NONE);
|
||||
uiItemR(col, ptr, "shadow_camera_far", 0, "Far", ICON_NONE);
|
||||
|
||||
uiItemR(layout, ptr, "shadow_enclosed_shapes", 0, IFACE_("Eclosed Shapes"), ICON_NONE);
|
||||
}
|
||||
|
||||
static void options_panel_draw(const bContext *UNUSED(C), Panel *panel)
|
||||
@ -584,7 +668,7 @@ static void chaining_panel_draw(const bContext *UNUSED(C), Panel *panel)
|
||||
uiItemR(col, ptr, "use_fuzzy_intersections", 0, NULL, ICON_NONE);
|
||||
uiItemR(col, ptr, "use_fuzzy_all", 0, NULL, ICON_NONE);
|
||||
uiItemR(col, ptr, "use_loose_edge_chain", 0, IFACE_("Loose Edges"), ICON_NONE);
|
||||
uiItemR(col, ptr, "use_loose_as_contour", 0, NULL, ICON_NONE);
|
||||
uiItemR(col, ptr, "use_loose_as_contour", 0, IFACE_("Loose Edges As Contour"), ICON_NONE);
|
||||
uiItemR(col, ptr, "use_detail_preserve", 0, NULL, ICON_NONE);
|
||||
uiItemR(col, ptr, "use_geometry_space_chain", 0, IFACE_("Geometry Space"), ICON_NONE);
|
||||
|
||||
@ -695,6 +779,12 @@ static void panelRegister(ARegionType *region_type)
|
||||
|
||||
gpencil_modifier_subpanel_register(
|
||||
region_type, "edge_types", "Edge Types", NULL, edge_types_panel_draw, panel_type);
|
||||
gpencil_modifier_subpanel_register(region_type,
|
||||
"light_reference",
|
||||
"Light Reference",
|
||||
NULL,
|
||||
options_light_reference_draw,
|
||||
panel_type);
|
||||
gpencil_modifier_subpanel_register(
|
||||
region_type, "geometry", "Geometry Processing", NULL, options_panel_draw, panel_type);
|
||||
PanelType *occlusion_panel = gpencil_modifier_subpanel_register(
|
||||
|
@ -41,6 +41,12 @@ typedef struct LineartTriangle {
|
||||
uint8_t mat_occlusion;
|
||||
uint8_t flags; /* #eLineartTriangleFlags */
|
||||
|
||||
/* target_reference = (obi->obindex | triangle_index) */
|
||||
/* higher 12 bits-------^ ^-----index in object, lower 20 bits */
|
||||
uint32_t target_reference;
|
||||
|
||||
uint8_t intersection_priority;
|
||||
|
||||
/**
|
||||
* Only use single link list, because we don't need to go back in order.
|
||||
* This variable is also reused to store the pointer to adjacent lines of this triangle before
|
||||
@ -66,6 +72,7 @@ typedef enum eLineArtElementNodeFlag {
|
||||
LRT_ELEMENT_IS_ADDITIONAL = (1 << 0),
|
||||
LRT_ELEMENT_BORDER_ONLY = (1 << 1),
|
||||
LRT_ELEMENT_NO_INTERSECTION = (1 << 2),
|
||||
LRT_ELEMENT_INTERSECTION_DATA = (1 << 3),
|
||||
} eLineArtElementNodeFlag;
|
||||
|
||||
typedef struct LineartElementLinkNode {
|
||||
@ -75,52 +82,80 @@ typedef struct LineartElementLinkNode {
|
||||
void *object_ref;
|
||||
eLineArtElementNodeFlag flags;
|
||||
|
||||
/* For edge element link nodes, used for shadow edge matching. */
|
||||
int obindex;
|
||||
|
||||
/** Per object value, always set, if not enabled by #ObjectLineArt, then it's set to global. */
|
||||
float crease_threshold;
|
||||
} LineartElementLinkNode;
|
||||
|
||||
typedef struct LineartEdgeSegment {
|
||||
struct LineartEdgeSegment *next, *prev;
|
||||
/** at==0: left at==1: right (this is in 2D projected space) */
|
||||
double at;
|
||||
/** Occlusion level after "at" point */
|
||||
/** The point after which a property of the segment is changed, e.g. occlusion/material mask etc.
|
||||
* ratio==0: v1 ratio==1: v2 (this is in 2D projected space), */
|
||||
double ratio;
|
||||
/** Occlusion level after "ratio" point */
|
||||
uint8_t occlusion;
|
||||
|
||||
/* Used to filter line art occlusion edges */
|
||||
uint8_t material_mask_bits;
|
||||
|
||||
/* Lit/shaded flag for shadow is stored here.
|
||||
* TODO(Yiming): Transfer material masks from shadow results
|
||||
* onto here so then we can even filter transparent shadows. */
|
||||
uint32_t shadow_mask_bits;
|
||||
} LineartEdgeSegment;
|
||||
|
||||
typedef struct LineartShadowEdge {
|
||||
struct LineartShadowEdge *next, *prev;
|
||||
/* Two end points in framebuffer coordinates viewed from the light source. */
|
||||
double fbc1[4], fbc2[4];
|
||||
double g1[3], g2[3];
|
||||
bool orig1, orig2;
|
||||
struct LineartEdge *e_ref;
|
||||
struct LineartEdge *e_ref_light_contour;
|
||||
struct LineartEdgeSegment *es_ref; /* Only for 3rd stage casting. */
|
||||
ListBase shadow_segments;
|
||||
} LineartShadowEdge;
|
||||
|
||||
enum eLineartShadowSegmentFlag {
|
||||
LRT_SHADOW_CASTED = 1,
|
||||
LRT_SHADOW_FACING_LIGHT = 2,
|
||||
};
|
||||
|
||||
/* Represents a cutting point on a #LineartShadowEdge */
|
||||
typedef struct LineartShadowSegment {
|
||||
struct LineartShadowSegment *next, *prev;
|
||||
/* eLineartShadowSegmentFlag */
|
||||
int flag;
|
||||
/* The point after which a property of the segment is changed. e.g. shadow mask/target_ref etc.
|
||||
* Coordinates in NDC during shadow caluclation but transformed to global linear before cutting
|
||||
* onto edges during the loading stage of the "actual" rendering. */
|
||||
double ratio;
|
||||
/* Left and right pos, because when casting shadows at some point there will be
|
||||
* non-continuous cuts, see #lineart_shadow_edge_cut for detailed explaination. */
|
||||
double fbc1[4], fbc2[4];
|
||||
/* Global position. */
|
||||
double g1[4], g2[4];
|
||||
uint32_t target_reference;
|
||||
uint32_t shadow_mask_bits;
|
||||
} LineartShadowSegment;
|
||||
|
||||
typedef struct LineartVert {
|
||||
double gloc[3];
|
||||
double fbcoord[4];
|
||||
|
||||
/* Scene global index. */
|
||||
int index;
|
||||
|
||||
/**
|
||||
* Intersection data flag is here, when LRT_VERT_HAS_INTERSECTION_DATA is set,
|
||||
* size of the struct is extended to include intersection data.
|
||||
* See #eLineArtVertFlags.
|
||||
*/
|
||||
uint8_t flag;
|
||||
|
||||
} LineartVert;
|
||||
|
||||
typedef struct LineartVertIntersection {
|
||||
struct LineartVert base;
|
||||
/** Use vert index because we only use this to check vertex equal. This way we save 8 Bytes. */
|
||||
int isec1, isec2;
|
||||
struct LineartTriangle *intersecting_with;
|
||||
} LineartVertIntersection;
|
||||
|
||||
typedef enum eLineArtVertFlags {
|
||||
LRT_VERT_HAS_INTERSECTION_DATA = (1 << 0),
|
||||
LRT_VERT_EDGE_USED = (1 << 1),
|
||||
} eLineArtVertFlags;
|
||||
|
||||
typedef struct LineartEdge {
|
||||
struct LineartVert *v1, *v2;
|
||||
|
||||
/** These two variables are also used to specify original edge and segment during 3rd stage
|
||||
* reprojection, So we can easily find out the line which results come from. */
|
||||
struct LineartTriangle *t1, *t2;
|
||||
|
||||
ListBase segments;
|
||||
int8_t min_occ;
|
||||
|
||||
@ -128,6 +163,19 @@ typedef struct LineartEdge {
|
||||
uint16_t flags;
|
||||
uint8_t intersection_mask;
|
||||
|
||||
/** Matches the shadow result, used to determine whether a line is in the shadow or not.
|
||||
* #edge_identifier usages:
|
||||
* - Intersection lines:
|
||||
* ((e->t1->target_reference << 32) | e->t2->target_reference);
|
||||
* - Other lines: LRT_EDGE_IDENTIFIER(obi, e);
|
||||
* - After shadow calculation: (search the shadow result and set reference to that);
|
||||
*/
|
||||
uint64_t edge_identifier;
|
||||
|
||||
/** - Light contour: original_e->t1->target_reference | original_e->t2->target_reference.
|
||||
* - Cast shadow: triangle_projected_onto->target_reference. */
|
||||
uint64_t target_reference;
|
||||
|
||||
/**
|
||||
* Still need this entry because culled lines will not add to object
|
||||
* #LineartElementLinkNode node (known as `eln` internally).
|
||||
@ -146,8 +194,8 @@ typedef struct LineartEdgeChain {
|
||||
float length;
|
||||
|
||||
/** Used when re-connecting and grease-pencil stroke generation. */
|
||||
int8_t picked;
|
||||
int8_t level;
|
||||
uint8_t picked;
|
||||
uint8_t level;
|
||||
|
||||
/** Chain now only contains one type of segments */
|
||||
int type;
|
||||
@ -155,8 +203,10 @@ typedef struct LineartEdgeChain {
|
||||
int loop_id;
|
||||
uint8_t material_mask_bits;
|
||||
uint8_t intersection_mask;
|
||||
uint32_t shadow_mask_bits;
|
||||
|
||||
struct Object *object_ref;
|
||||
struct Object *silhouette_backdrop;
|
||||
} LineartEdgeChain;
|
||||
|
||||
typedef struct LineartEdgeChainItem {
|
||||
@ -170,6 +220,7 @@ typedef struct LineartEdgeChainItem {
|
||||
uint8_t occlusion;
|
||||
uint8_t material_mask_bits;
|
||||
uint8_t intersection_mask;
|
||||
uint32_t shadow_mask_bits;
|
||||
size_t index;
|
||||
} LineartEdgeChainItem;
|
||||
|
||||
@ -201,6 +252,11 @@ enum eLineArtTileRecursiveLimit {
|
||||
#define LRT_TILE_SPLITTING_TRIANGLE_LIMIT 100
|
||||
#define LRT_TILE_EDGE_COUNT_INITIAL 32
|
||||
|
||||
enum eLineartShadowCameraType {
|
||||
LRT_SHADOW_CAMERA_DIRECTIONAL = 1,
|
||||
LRT_SHADOW_CAMERA_POINT = 2,
|
||||
};
|
||||
|
||||
typedef struct LineartPendingEdges {
|
||||
LineartEdge **array;
|
||||
int max;
|
||||
@ -216,6 +272,14 @@ typedef struct LineartData {
|
||||
LineartStaticMemPool render_data_pool;
|
||||
/* A pointer to LineartCache::chain_data_pool, which acts as a cache for edge chains. */
|
||||
LineartStaticMemPool *chain_data_pool;
|
||||
/* Reference to LineartCache::shadow_data_pool, stay available until the final round of line art
|
||||
* calculation is finished. */
|
||||
LineartStaticMemPool *shadow_data_pool;
|
||||
|
||||
/* Storing shadow edge eln, array, and cuts for shadow information, so it's avaliable when line
|
||||
* art runs the second time for occlusion. Either a reference to LineartCache::shadow_data_pool
|
||||
* (shadow stage) or a reference to LineartData::render_data_pool (final stage). */
|
||||
LineartStaticMemPool *edge_data_pool;
|
||||
|
||||
struct _qtree {
|
||||
|
||||
@ -230,7 +294,7 @@ typedef struct LineartData {
|
||||
|
||||
struct LineartBoundingArea *initials;
|
||||
|
||||
uint32_t tile_count;
|
||||
uint32_t initial_tile_count;
|
||||
|
||||
} qtree;
|
||||
|
||||
@ -267,6 +331,14 @@ typedef struct LineartData {
|
||||
bool use_edge_marks;
|
||||
bool use_intersections;
|
||||
bool use_loose;
|
||||
bool use_light_contour;
|
||||
bool use_shadow;
|
||||
bool use_contour_secondary; /* From viewing camera, during shadow calculation. */
|
||||
|
||||
int shadow_selection; /* Needs to be numeric because it's not just on/off. */
|
||||
bool shadow_enclose_shapes;
|
||||
bool shadow_use_silhouette;
|
||||
|
||||
bool fuzzy_intersections;
|
||||
bool fuzzy_everything;
|
||||
bool allow_boundaries;
|
||||
@ -289,13 +361,21 @@ typedef struct LineartData {
|
||||
|
||||
bool chain_preserve_details;
|
||||
|
||||
bool do_shadow_cast;
|
||||
bool light_reference_available;
|
||||
|
||||
/* Keep an copy of these data so when line art is running it's self-contained. */
|
||||
bool cam_is_persp;
|
||||
bool cam_is_persp_secondary; /* "Secondary" ones are from viewing camera (as opposed to shadow
|
||||
camera), during shadow calculation. */
|
||||
float cam_obmat[4][4];
|
||||
float cam_obmat_secondary[4][4];
|
||||
double camera_pos[3];
|
||||
double camera_pos_secondary[3];
|
||||
double active_camera_pos[3]; /* Stroke offset calculation may use active or selected camera. */
|
||||
double near_clip, far_clip;
|
||||
float shift_x, shift_y;
|
||||
|
||||
float crease_threshold;
|
||||
float chaining_image_threshold;
|
||||
float angle_splitting_threshold;
|
||||
@ -303,7 +383,7 @@ typedef struct LineartData {
|
||||
float chain_smooth_tolerance;
|
||||
|
||||
double view_vector[3];
|
||||
|
||||
double view_vector_secondary[3]; /* For shadow. */
|
||||
} conf;
|
||||
|
||||
LineartElementLinkNode *isect_scheduled_up_to;
|
||||
@ -313,22 +393,32 @@ typedef struct LineartData {
|
||||
struct LineartPendingEdges pending_edges;
|
||||
int scheduled_count;
|
||||
|
||||
/* Intermediate shadow results, list of LineartShadowEdge */
|
||||
LineartShadowEdge *shadow_edges;
|
||||
int shadow_edges_count;
|
||||
|
||||
ListBase chains;
|
||||
|
||||
ListBase wasted_cuts;
|
||||
ListBase wasted_shadow_cuts;
|
||||
SpinLock lock_cuts;
|
||||
SpinLock lock_task;
|
||||
|
||||
} LineartData;
|
||||
|
||||
typedef struct LineartCache {
|
||||
/** Separate memory pool for chain data, this goes to the cache, so when we free the main pool,
|
||||
* chains will still be available. */
|
||||
/** Separate memory pool for chain data and shadow, this goes to the cache, so when we free the
|
||||
* main pool, chains and shadows will still be available. */
|
||||
LineartStaticMemPool chain_data_pool;
|
||||
LineartStaticMemPool shadow_data_pool;
|
||||
|
||||
/** A copy of ld->chains so we have that data available after ld has been destroyed. */
|
||||
ListBase chains;
|
||||
|
||||
/** Shadow-computed feature lines from original meshes to be matched with the second load of
|
||||
* meshes thus providing lit/shade info in the second run of line art. */
|
||||
ListBase shadow_elns;
|
||||
|
||||
/** Cache only contains edge types specified in this variable. */
|
||||
uint16_t all_enabled_edge_types;
|
||||
} LineartCache;
|
||||
@ -348,6 +438,14 @@ typedef enum eLineartTriangleFlags {
|
||||
LRT_TRIANGLE_MAT_BACK_FACE_CULLING = (1 << 5),
|
||||
} eLineartTriangleFlags;
|
||||
|
||||
#define LRT_SHADOW_MASK_UNDEFINED 0
|
||||
#define LRT_SHADOW_MASK_LIT (1 << 0)
|
||||
#define LRT_SHADOW_MASK_SHADED (1 << 1)
|
||||
#define LRT_SHADOW_MASK_ENCLOSED_SHAPE (1 << 2)
|
||||
#define LRT_SHADOW_MASK_INHIBITED (1 << 3)
|
||||
#define LRT_SHADOW_SILHOUETTE_ERASED_GROUP (1 << 4)
|
||||
#define LRT_SHADOW_SILHOUETTE_ERASED_OBJECT (1 << 5)
|
||||
|
||||
/**
|
||||
* Controls how many edges a worker thread is processing at one request.
|
||||
* There's no significant performance impact on choosing different values.
|
||||
@ -368,6 +466,14 @@ typedef struct LineartRenderTaskInfo {
|
||||
|
||||
} LineartRenderTaskInfo;
|
||||
|
||||
#define LRT_OBINDEX_SHIFT 20
|
||||
#define LRT_OBINDEX_LOWER 0x0FFFFF /* Lower 20 bits. */
|
||||
#define LRT_OBINDEX_HIGHER 0xFFF00000 /* Higher 12 bits. */
|
||||
#define LRT_EDGE_IDENTIFIER(obi, e) \
|
||||
(((uint64_t)(obi->obindex | (e->v1->index & LRT_OBINDEX_LOWER)) << 32) | \
|
||||
(obi->obindex | (e->v2->index & LRT_OBINDEX_LOWER)))
|
||||
#define LRT_LIGHT_CONTOUR_TARGET 0xFFFFFFFF
|
||||
|
||||
typedef struct LineartObjectInfo {
|
||||
struct LineartObjectInfo *next;
|
||||
struct Object *original_ob;
|
||||
@ -378,8 +484,12 @@ typedef struct LineartObjectInfo {
|
||||
LineartElementLinkNode *v_eln;
|
||||
int usage;
|
||||
uint8_t override_intersection_mask;
|
||||
uint8_t intersection_priority;
|
||||
int global_i_offset;
|
||||
|
||||
/* Shifted LRT_OBINDEX_SHIFT bits to be combined with object triangle index. */
|
||||
int obindex;
|
||||
|
||||
bool free_use_mesh;
|
||||
|
||||
/** NOTE: Data inside #pending_edges are allocated with MEM_xxx call instead of in pool. */
|
||||
@ -394,6 +504,7 @@ typedef struct LineartObjectLoadTaskInfo {
|
||||
LineartObjectInfo *pending;
|
||||
/* Used to spread the load across several threads. This can not overflow. */
|
||||
uint64_t total_faces;
|
||||
ListBase *shadow_elns;
|
||||
} LineartObjectLoadTaskInfo;
|
||||
|
||||
/**
|
||||
@ -466,6 +577,10 @@ typedef struct LineartBoundingArea {
|
||||
#define LRT_DOUBLE_CLOSE_ENOUGH_TRI(a, b) \
|
||||
(((a) + DBL_TRIANGLE_LIM) >= (b) && ((a)-DBL_TRIANGLE_LIM) <= (b))
|
||||
|
||||
#define LRT_CLOSE_LOOSER_v3(a, b) \
|
||||
(LRT_DOUBLE_CLOSE_LOOSER(a[0], b[0]) && LRT_DOUBLE_CLOSE_LOOSER(a[1], b[1]) && \
|
||||
LRT_DOUBLE_CLOSE_LOOSER(a[2], b[2]))
|
||||
|
||||
/* Notes on this function:
|
||||
*
|
||||
* r_ratio: The ratio on segment a1-a2. When r_ratio is very close to zero or one, it
|
||||
@ -478,10 +593,10 @@ typedef struct LineartBoundingArea {
|
||||
* segment a is shared with segment b. If it's a1 then r_ratio is 0, else then r_ratio is 1. This
|
||||
* extra information is needed for line art occlusion stage to work correctly in such cases.
|
||||
*/
|
||||
BLI_INLINE int lineart_intersect_seg_seg(const double *a1,
|
||||
const double *a2,
|
||||
const double *b1,
|
||||
const double *b2,
|
||||
BLI_INLINE int lineart_intersect_seg_seg(const double a1[2],
|
||||
const double a2[2],
|
||||
const double b1[2],
|
||||
const double b2[2],
|
||||
double *r_ratio,
|
||||
bool *r_aligned)
|
||||
{
|
||||
@ -622,6 +737,99 @@ BLI_INLINE int lineart_intersect_seg_seg(const double *a1,
|
||||
#endif
|
||||
}
|
||||
|
||||
/* This is a special convenience function to lineart_intersect_seg_seg which will return true when
|
||||
* the intersection point falls in the range of a1-a2 but not necessarily in the range of b1-b2. */
|
||||
BLI_INLINE int lineart_line_isec_2d_ignore_line2pos(const double a1[2],
|
||||
const double a2[2],
|
||||
const double b1[2],
|
||||
const double b2[2],
|
||||
double *r_a_ratio)
|
||||
{
|
||||
/* The define here is used to check how vector or slope method handles boundary cases. The result
|
||||
* of lim(div->0) and lim(k->0) could both produce some unwanted flickers in line art, the
|
||||
* influence of which is still not fully understood, so keep the switch there for futher
|
||||
* investigations. */
|
||||
#define USE_VECTOR_LINE_INTERSECTION_IGN
|
||||
#ifdef USE_VECTOR_LINE_INTERSECTION_IGN
|
||||
|
||||
/* from isect_line_line_v2_point() */
|
||||
|
||||
double s10[2], s32[2];
|
||||
double div;
|
||||
|
||||
sub_v2_v2v2_db(s10, a2, a1);
|
||||
sub_v2_v2v2_db(s32, b2, b1);
|
||||
|
||||
div = cross_v2v2_db(s10, s32);
|
||||
if (div != 0.0f) {
|
||||
const double u = cross_v2v2_db(a2, a1);
|
||||
const double v = cross_v2v2_db(b2, b1);
|
||||
|
||||
const double rx = ((s32[0] * u) - (s10[0] * v)) / div;
|
||||
const double ry = ((s32[1] * u) - (s10[1] * v)) / div;
|
||||
|
||||
if (fabs(a2[0] - a1[0]) > fabs(a2[1] - a1[1])) {
|
||||
*r_a_ratio = ratiod(a1[0], a2[0], rx);
|
||||
if ((*r_a_ratio) >= -DBL_EDGE_LIM && (*r_a_ratio) <= 1 + DBL_EDGE_LIM) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
*r_a_ratio = ratiod(a1[1], a2[1], ry);
|
||||
if ((*r_a_ratio) >= -DBL_EDGE_LIM && (*r_a_ratio) <= 1 + DBL_EDGE_LIM) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
|
||||
#else
|
||||
double k1, k2;
|
||||
double x;
|
||||
double y;
|
||||
double ratio;
|
||||
double x_diff = (a2[0] - a1[0]);
|
||||
double x_diff2 = (b2[0] - b1[0]);
|
||||
|
||||
if (LRT_DOUBLE_CLOSE_ENOUGH(x_diff, 0)) {
|
||||
if (LRT_DOUBLE_CLOSE_ENOUGH(x_diff2, 0)) {
|
||||
*r_a_ratio = 0;
|
||||
return 0;
|
||||
}
|
||||
double r2 = ratiod(b1[0], b2[0], a1[0]);
|
||||
x = interpd(b2[0], b1[0], r2);
|
||||
y = interpd(b2[1], b1[1], r2);
|
||||
*r_a_ratio = ratio = ratiod(a1[1], a2[1], y);
|
||||
}
|
||||
else {
|
||||
if (LRT_DOUBLE_CLOSE_ENOUGH(x_diff2, 0)) {
|
||||
ratio = ratiod(a1[0], a2[0], b1[0]);
|
||||
x = interpd(a2[0], a1[0], ratio);
|
||||
*r_a_ratio = ratio;
|
||||
}
|
||||
else {
|
||||
k1 = (a2[1] - a1[1]) / x_diff;
|
||||
k2 = (b2[1] - b1[1]) / x_diff2;
|
||||
|
||||
if ((k1 == k2))
|
||||
return 0;
|
||||
|
||||
x = (a1[1] - b1[1] - k1 * a1[0] + k2 * b1[0]) / (k2 - k1);
|
||||
|
||||
ratio = (x - a1[0]) / x_diff;
|
||||
|
||||
*r_a_ratio = ratio;
|
||||
}
|
||||
}
|
||||
|
||||
if (ratio <= 0 || ratio >= 1)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
struct Depsgraph;
|
||||
struct LineartGpencilModifierData;
|
||||
struct LineartData;
|
||||
@ -646,6 +854,7 @@ void MOD_lineart_chain_clip_at_border(LineartData *ld);
|
||||
void MOD_lineart_chain_split_angle(LineartData *ld, float angle_threshold_rad);
|
||||
void MOD_lineart_smooth_chains(LineartData *ld, float tolerance);
|
||||
void MOD_lineart_chain_offset_towards_camera(LineartData *ld, float dist, bool use_custom_camera);
|
||||
void MOD_lineart_chain_find_silhouette_backdrop_objects(LineartData *ld);
|
||||
|
||||
int MOD_lineart_chain_count(const LineartEdgeChain *ec);
|
||||
void MOD_lineart_chain_clear_picked_flag(LineartCache *lc);
|
||||
@ -694,6 +903,8 @@ void MOD_lineart_gpencil_generate(LineartCache *cache,
|
||||
uint8_t intersection_mask,
|
||||
int16_t thickness,
|
||||
float opacity,
|
||||
uint8_t shadow_selection,
|
||||
uint8_t silhouette_mode,
|
||||
const char *source_vgname,
|
||||
const char *vgname,
|
||||
int modifier_flags);
|
||||
|
@ -17,13 +17,16 @@
|
||||
|
||||
#define LRT_OTHER_VERT(e, vt) ((vt) == (e)->v1 ? (e)->v2 : ((vt) == (e)->v2 ? (e)->v1 : NULL))
|
||||
|
||||
struct Object;
|
||||
|
||||
/* Get a connected line, only for lines who has the exact given vert, or (in the case of
|
||||
* intersection lines) who has a vert that has the exact same position. */
|
||||
static LineartEdge *lineart_line_get_connected(LineartBoundingArea *ba,
|
||||
LineartVert *vt,
|
||||
LineartVert **new_vt,
|
||||
int match_flag,
|
||||
uint8_t match_isec_mask)
|
||||
uint8_t match_isec_mask,
|
||||
struct Object *match_isec_object)
|
||||
{
|
||||
for (int i = 0; i < ba->line_count; i++) {
|
||||
LineartEdge *n_e = ba->linked_lines[i];
|
||||
@ -46,6 +49,9 @@ static LineartEdge *lineart_line_get_connected(LineartBoundingArea *ba,
|
||||
}
|
||||
|
||||
if (n_e->flags & LRT_EDGE_FLAG_INTERSECTION) {
|
||||
if (n_e->object_ref != match_isec_object) {
|
||||
continue;
|
||||
}
|
||||
if (vt->fbcoord[0] == n_e->v1->fbcoord[0] && vt->fbcoord[1] == n_e->v1->fbcoord[1]) {
|
||||
*new_vt = LRT_OTHER_VERT(n_e, n_e->v1);
|
||||
return n_e;
|
||||
@ -87,12 +93,13 @@ static bool lineart_point_overlapping(LineartEdgeChainItem *eci,
|
||||
|
||||
static LineartEdgeChainItem *lineart_chain_append_point(LineartData *ld,
|
||||
LineartEdgeChain *ec,
|
||||
float *fbcoord,
|
||||
float *gpos,
|
||||
float *normal,
|
||||
float fbcoord[4],
|
||||
float gpos[3],
|
||||
float normal[3],
|
||||
uint8_t type,
|
||||
int level,
|
||||
uint8_t material_mask_bits,
|
||||
uint32_t shadow_mask_bits,
|
||||
size_t index)
|
||||
{
|
||||
LineartEdgeChainItem *eci;
|
||||
@ -105,6 +112,7 @@ static LineartEdgeChainItem *lineart_chain_append_point(LineartData *ld,
|
||||
old_eci->line_type = type;
|
||||
old_eci->occlusion = level;
|
||||
old_eci->material_mask_bits = material_mask_bits;
|
||||
old_eci->shadow_mask_bits = shadow_mask_bits;
|
||||
return old_eci;
|
||||
}
|
||||
|
||||
@ -117,6 +125,7 @@ static LineartEdgeChainItem *lineart_chain_append_point(LineartData *ld,
|
||||
eci->line_type = type & LRT_EDGE_FLAG_ALL_TYPE;
|
||||
eci->occlusion = level;
|
||||
eci->material_mask_bits = material_mask_bits;
|
||||
eci->shadow_mask_bits = shadow_mask_bits;
|
||||
BLI_addtail(&ec->chain, eci);
|
||||
|
||||
return eci;
|
||||
@ -124,12 +133,13 @@ static LineartEdgeChainItem *lineart_chain_append_point(LineartData *ld,
|
||||
|
||||
static LineartEdgeChainItem *lineart_chain_prepend_point(LineartData *ld,
|
||||
LineartEdgeChain *ec,
|
||||
float *fbcoord,
|
||||
float *gpos,
|
||||
float *normal,
|
||||
float fbcoord[4],
|
||||
float gpos[3],
|
||||
float normal[3],
|
||||
uint8_t type,
|
||||
int level,
|
||||
uint8_t material_mask_bits,
|
||||
uint32_t shadow_mask_bits,
|
||||
size_t index)
|
||||
{
|
||||
LineartEdgeChainItem *eci;
|
||||
@ -147,6 +157,7 @@ static LineartEdgeChainItem *lineart_chain_prepend_point(LineartData *ld,
|
||||
eci->line_type = type & LRT_EDGE_FLAG_ALL_TYPE;
|
||||
eci->occlusion = level;
|
||||
eci->material_mask_bits = material_mask_bits;
|
||||
eci->shadow_mask_bits = shadow_mask_bits;
|
||||
BLI_addhead(&ec->chain, eci);
|
||||
|
||||
return eci;
|
||||
@ -160,6 +171,7 @@ void MOD_lineart_chain_feature_lines(LineartData *ld)
|
||||
LineartEdgeSegment *es;
|
||||
int last_occlusion;
|
||||
uint8_t last_transparency;
|
||||
uint32_t last_shadow;
|
||||
/* Used when converting from double. */
|
||||
float use_fbcoord[4];
|
||||
float use_gpos[3];
|
||||
@ -219,9 +231,10 @@ void MOD_lineart_chain_feature_lines(LineartData *ld)
|
||||
e->flags,
|
||||
es->occlusion,
|
||||
es->material_mask_bits,
|
||||
es->shadow_mask_bits,
|
||||
e->v1->index);
|
||||
while (ba && (new_e = lineart_line_get_connected(
|
||||
ba, new_vt, &new_vt, e->flags, e->intersection_mask))) {
|
||||
ba, new_vt, &new_vt, e->flags, ec->intersection_mask, ec->object_ref))) {
|
||||
new_e->flags |= LRT_EDGE_FLAG_CHAIN_PICKED;
|
||||
|
||||
if (new_e->t1 || new_e->t2) {
|
||||
@ -243,8 +256,8 @@ void MOD_lineart_chain_feature_lines(LineartData *ld)
|
||||
for (es = new_e->segments.last; es; es = es->prev) {
|
||||
double gpos[3], lpos[3];
|
||||
double *lfb = new_e->v1->fbcoord, *rfb = new_e->v2->fbcoord;
|
||||
double global_at = lfb[3] * es->at / (es->at * lfb[3] + (1 - es->at) * rfb[3]);
|
||||
interp_v3_v3v3_db(lpos, new_e->v1->fbcoord, new_e->v2->fbcoord, es->at);
|
||||
double global_at = lfb[3] * es->ratio / (es->ratio * lfb[3] + (1 - es->ratio) * rfb[3]);
|
||||
interp_v3_v3v3_db(lpos, new_e->v1->fbcoord, new_e->v2->fbcoord, es->ratio);
|
||||
interp_v3_v3v3_db(gpos, new_e->v1->gloc, new_e->v2->gloc, global_at);
|
||||
use_fbcoord[3] = interpf(new_e->v2->fbcoord[3], new_e->v1->fbcoord[3], global_at);
|
||||
POS_TO_FLOAT(lpos, gpos)
|
||||
@ -256,21 +269,24 @@ void MOD_lineart_chain_feature_lines(LineartData *ld)
|
||||
new_e->flags,
|
||||
es->occlusion,
|
||||
es->material_mask_bits,
|
||||
es->shadow_mask_bits,
|
||||
new_e->v1->index);
|
||||
last_occlusion = es->occlusion;
|
||||
last_transparency = es->material_mask_bits;
|
||||
last_shadow = es->shadow_mask_bits;
|
||||
}
|
||||
}
|
||||
else if (new_vt == new_e->v2) {
|
||||
es = new_e->segments.first;
|
||||
last_occlusion = es->occlusion;
|
||||
last_transparency = es->material_mask_bits;
|
||||
last_shadow = es->shadow_mask_bits;
|
||||
es = es->next;
|
||||
for (; es; es = es->next) {
|
||||
double gpos[3], lpos[3];
|
||||
double *lfb = new_e->v1->fbcoord, *rfb = new_e->v2->fbcoord;
|
||||
double global_at = lfb[3] * es->at / (es->at * lfb[3] + (1 - es->at) * rfb[3]);
|
||||
interp_v3_v3v3_db(lpos, new_e->v1->fbcoord, new_e->v2->fbcoord, es->at);
|
||||
double global_at = lfb[3] * es->ratio / (es->ratio * lfb[3] + (1 - es->ratio) * rfb[3]);
|
||||
interp_v3_v3v3_db(lpos, new_e->v1->fbcoord, new_e->v2->fbcoord, es->ratio);
|
||||
interp_v3_v3v3_db(gpos, new_e->v1->gloc, new_e->v2->gloc, global_at);
|
||||
use_fbcoord[3] = interpf(new_e->v2->fbcoord[3], new_e->v1->fbcoord[3], global_at);
|
||||
POS_TO_FLOAT(lpos, gpos)
|
||||
@ -282,9 +298,11 @@ void MOD_lineart_chain_feature_lines(LineartData *ld)
|
||||
new_e->flags,
|
||||
last_occlusion,
|
||||
last_transparency,
|
||||
last_shadow,
|
||||
new_e->v2->index);
|
||||
last_occlusion = es->occlusion;
|
||||
last_transparency = es->material_mask_bits;
|
||||
last_shadow = es->shadow_mask_bits;
|
||||
}
|
||||
VERT_COORD_TO_FLOAT(new_e->v2);
|
||||
lineart_chain_prepend_point(ld,
|
||||
@ -295,6 +313,7 @@ void MOD_lineart_chain_feature_lines(LineartData *ld)
|
||||
new_e->flags,
|
||||
last_occlusion,
|
||||
last_transparency,
|
||||
last_shadow,
|
||||
new_e->v2->index);
|
||||
}
|
||||
ba = MOD_lineart_get_bounding_area(ld, new_vt->fbcoord[0], new_vt->fbcoord[1]);
|
||||
@ -318,13 +337,14 @@ void MOD_lineart_chain_feature_lines(LineartData *ld)
|
||||
/* Step 2: Adding all cuts from the given line, so we can continue connecting the right side
|
||||
* of the line. */
|
||||
es = e->segments.first;
|
||||
last_occlusion = ((LineartEdgeSegment *)es)->occlusion;
|
||||
last_transparency = ((LineartEdgeSegment *)es)->material_mask_bits;
|
||||
last_occlusion = es->occlusion;
|
||||
last_transparency = es->material_mask_bits;
|
||||
last_shadow = es->shadow_mask_bits;
|
||||
for (es = es->next; es; es = es->next) {
|
||||
double gpos[3], lpos[3];
|
||||
double *lfb = e->v1->fbcoord, *rfb = e->v2->fbcoord;
|
||||
double global_at = lfb[3] * es->at / (es->at * lfb[3] + (1 - es->at) * rfb[3]);
|
||||
interp_v3_v3v3_db(lpos, e->v1->fbcoord, e->v2->fbcoord, es->at);
|
||||
double global_at = lfb[3] * es->ratio / (es->ratio * lfb[3] + (1 - es->ratio) * rfb[3]);
|
||||
interp_v3_v3v3_db(lpos, e->v1->fbcoord, e->v2->fbcoord, es->ratio);
|
||||
interp_v3_v3v3_db(gpos, e->v1->gloc, e->v2->gloc, global_at);
|
||||
use_fbcoord[3] = interpf(e->v2->fbcoord[3], e->v1->fbcoord[3], global_at);
|
||||
POS_TO_FLOAT(lpos, gpos)
|
||||
@ -336,9 +356,11 @@ void MOD_lineart_chain_feature_lines(LineartData *ld)
|
||||
e->flags,
|
||||
es->occlusion,
|
||||
es->material_mask_bits,
|
||||
es->shadow_mask_bits,
|
||||
e->v1->index);
|
||||
last_occlusion = es->occlusion;
|
||||
last_transparency = es->material_mask_bits;
|
||||
last_shadow = es->shadow_mask_bits;
|
||||
}
|
||||
VERT_COORD_TO_FLOAT(e->v2)
|
||||
lineart_chain_append_point(ld,
|
||||
@ -349,13 +371,14 @@ void MOD_lineart_chain_feature_lines(LineartData *ld)
|
||||
e->flags,
|
||||
last_occlusion,
|
||||
last_transparency,
|
||||
last_shadow,
|
||||
e->v2->index);
|
||||
|
||||
/* Step 3: grow right. */
|
||||
ba = MOD_lineart_get_bounding_area(ld, e->v2->fbcoord[0], e->v2->fbcoord[1]);
|
||||
new_vt = e->v2;
|
||||
while (ba && (new_e = lineart_line_get_connected(
|
||||
ba, new_vt, &new_vt, e->flags, e->intersection_mask))) {
|
||||
ba, new_vt, &new_vt, e->flags, ec->intersection_mask, ec->object_ref))) {
|
||||
new_e->flags |= LRT_EDGE_FLAG_CHAIN_PICKED;
|
||||
|
||||
if (new_e->t1 || new_e->t2) {
|
||||
@ -381,18 +404,21 @@ void MOD_lineart_chain_feature_lines(LineartData *ld)
|
||||
es = new_e->segments.last;
|
||||
last_occlusion = es->occlusion;
|
||||
last_transparency = es->material_mask_bits;
|
||||
last_shadow = es->shadow_mask_bits;
|
||||
/* Fix leading vertex occlusion. */
|
||||
eci->occlusion = last_occlusion;
|
||||
eci->material_mask_bits = last_transparency;
|
||||
eci->shadow_mask_bits = last_shadow;
|
||||
for (es = new_e->segments.last; es; es = es->prev) {
|
||||
double gpos[3], lpos[3];
|
||||
double *lfb = new_e->v1->fbcoord, *rfb = new_e->v2->fbcoord;
|
||||
double global_at = lfb[3] * es->at / (es->at * lfb[3] + (1 - es->at) * rfb[3]);
|
||||
interp_v3_v3v3_db(lpos, new_e->v1->fbcoord, new_e->v2->fbcoord, es->at);
|
||||
double global_at = lfb[3] * es->ratio / (es->ratio * lfb[3] + (1 - es->ratio) * rfb[3]);
|
||||
interp_v3_v3v3_db(lpos, new_e->v1->fbcoord, new_e->v2->fbcoord, es->ratio);
|
||||
interp_v3_v3v3_db(gpos, new_e->v1->gloc, new_e->v2->gloc, global_at);
|
||||
use_fbcoord[3] = interpf(new_e->v2->fbcoord[3], new_e->v1->fbcoord[3], global_at);
|
||||
last_occlusion = es->prev ? es->prev->occlusion : last_occlusion;
|
||||
last_transparency = es->prev ? es->prev->material_mask_bits : last_transparency;
|
||||
last_shadow = es->prev ? es->prev->shadow_mask_bits : last_shadow;
|
||||
POS_TO_FLOAT(lpos, gpos)
|
||||
lineart_chain_append_point(ld,
|
||||
ec,
|
||||
@ -402,6 +428,7 @@ void MOD_lineart_chain_feature_lines(LineartData *ld)
|
||||
new_e->flags,
|
||||
last_occlusion,
|
||||
last_transparency,
|
||||
last_shadow,
|
||||
new_e->v1->index);
|
||||
}
|
||||
}
|
||||
@ -409,14 +436,16 @@ void MOD_lineart_chain_feature_lines(LineartData *ld)
|
||||
es = new_e->segments.first;
|
||||
last_occlusion = es->occlusion;
|
||||
last_transparency = es->material_mask_bits;
|
||||
last_shadow = es->shadow_mask_bits;
|
||||
eci->occlusion = last_occlusion;
|
||||
eci->material_mask_bits = last_transparency;
|
||||
eci->shadow_mask_bits = last_shadow;
|
||||
es = es->next;
|
||||
for (; es; es = es->next) {
|
||||
double gpos[3], lpos[3];
|
||||
double *lfb = new_e->v1->fbcoord, *rfb = new_e->v2->fbcoord;
|
||||
double global_at = lfb[3] * es->at / (es->at * lfb[3] + (1 - es->at) * rfb[3]);
|
||||
interp_v3_v3v3_db(lpos, new_e->v1->fbcoord, new_e->v2->fbcoord, es->at);
|
||||
double global_at = lfb[3] * es->ratio / (es->ratio * lfb[3] + (1 - es->ratio) * rfb[3]);
|
||||
interp_v3_v3v3_db(lpos, new_e->v1->fbcoord, new_e->v2->fbcoord, es->ratio);
|
||||
interp_v3_v3v3_db(gpos, new_e->v1->gloc, new_e->v2->gloc, global_at);
|
||||
use_fbcoord[3] = interpf(new_e->v2->fbcoord[3], new_e->v1->fbcoord[3], global_at);
|
||||
POS_TO_FLOAT(lpos, gpos)
|
||||
@ -428,9 +457,11 @@ void MOD_lineart_chain_feature_lines(LineartData *ld)
|
||||
new_e->flags,
|
||||
es->occlusion,
|
||||
es->material_mask_bits,
|
||||
es->shadow_mask_bits,
|
||||
new_e->v2->index);
|
||||
last_occlusion = es->occlusion;
|
||||
last_transparency = es->material_mask_bits;
|
||||
last_shadow = es->shadow_mask_bits;
|
||||
}
|
||||
VERT_COORD_TO_FLOAT(new_e->v2)
|
||||
lineart_chain_append_point(ld,
|
||||
@ -441,6 +472,7 @@ void MOD_lineart_chain_feature_lines(LineartData *ld)
|
||||
new_e->flags,
|
||||
last_occlusion,
|
||||
last_transparency,
|
||||
last_shadow,
|
||||
new_e->v2->index);
|
||||
}
|
||||
ba = MOD_lineart_get_bounding_area(ld, new_vt->fbcoord[0], new_vt->fbcoord[1]);
|
||||
@ -509,7 +541,7 @@ static void lineart_bounding_area_link_point_recursive(LineartData *ld,
|
||||
{
|
||||
if (root->child == NULL) {
|
||||
LineartChainRegisterEntry *cre = lineart_list_append_pointer_pool_sized(
|
||||
&root->linked_chains, &ld->render_data_pool, ec, sizeof(LineartChainRegisterEntry));
|
||||
&root->linked_chains, ld->chain_data_pool, ec, sizeof(LineartChainRegisterEntry));
|
||||
|
||||
cre->eci = eci;
|
||||
|
||||
@ -565,6 +597,7 @@ static bool lineart_chain_fix_ambiguous_segments(LineartEdgeChain *ec,
|
||||
|
||||
int fixed_occ = last_matching_eci->occlusion;
|
||||
uint8_t fixed_mask = last_matching_eci->material_mask_bits;
|
||||
uint32_t fixed_shadow = last_matching_eci->shadow_mask_bits;
|
||||
|
||||
LineartEdgeChainItem *can_skip_to = NULL;
|
||||
LineartEdgeChainItem *last_eci = last_matching_eci;
|
||||
@ -579,7 +612,8 @@ static bool lineart_chain_fix_ambiguous_segments(LineartEdgeChain *ec,
|
||||
if (eci->occlusion < fixed_occ) {
|
||||
break;
|
||||
}
|
||||
if (eci->material_mask_bits == fixed_mask && eci->occlusion == fixed_occ) {
|
||||
if (eci->material_mask_bits == fixed_mask && eci->occlusion == fixed_occ &&
|
||||
eci->shadow_mask_bits == fixed_shadow) {
|
||||
can_skip_to = eci;
|
||||
}
|
||||
}
|
||||
@ -589,12 +623,14 @@ static bool lineart_chain_fix_ambiguous_segments(LineartEdgeChain *ec,
|
||||
LineartEdgeChainItem *next_eci;
|
||||
for (LineartEdgeChainItem *eci = last_matching_eci->next; eci != can_skip_to; eci = next_eci) {
|
||||
next_eci = eci->next;
|
||||
if (eci->material_mask_bits == fixed_mask && eci->occlusion == fixed_occ) {
|
||||
if (eci->material_mask_bits == fixed_mask && eci->occlusion == fixed_occ &&
|
||||
eci->shadow_mask_bits == fixed_shadow) {
|
||||
continue;
|
||||
}
|
||||
if (preserve_details) {
|
||||
eci->material_mask_bits = fixed_mask;
|
||||
eci->occlusion = fixed_occ;
|
||||
eci->shadow_mask_bits = fixed_shadow;
|
||||
}
|
||||
else {
|
||||
BLI_remlink(&ec->chain, eci);
|
||||
@ -628,11 +664,14 @@ void MOD_lineart_chain_split_for_fixed_occlusion(LineartData *ld)
|
||||
LineartEdgeChainItem *first_eci = (LineartEdgeChainItem *)ec->chain.first;
|
||||
int fixed_occ = first_eci->occlusion;
|
||||
uint8_t fixed_mask = first_eci->material_mask_bits;
|
||||
uint32_t fixed_shadow = first_eci->shadow_mask_bits;
|
||||
ec->level = fixed_occ;
|
||||
ec->material_mask_bits = fixed_mask;
|
||||
ec->shadow_mask_bits = fixed_shadow;
|
||||
for (eci = first_eci->next; eci; eci = next_eci) {
|
||||
next_eci = eci->next;
|
||||
if (eci->occlusion != fixed_occ || eci->material_mask_bits != fixed_mask) {
|
||||
if (eci->occlusion != fixed_occ || eci->material_mask_bits != fixed_mask ||
|
||||
eci->shadow_mask_bits != fixed_shadow) {
|
||||
if (next_eci) {
|
||||
if (lineart_point_overlapping(next_eci, eci->pos[0], eci->pos[1], 1e-5)) {
|
||||
continue;
|
||||
@ -649,6 +688,7 @@ void MOD_lineart_chain_split_for_fixed_occlusion(LineartData *ld)
|
||||
/* Set the same occlusion level for the end vertex, so when further connection is needed
|
||||
* the backwards occlusion info is also correct. */
|
||||
eci->occlusion = fixed_occ;
|
||||
eci->shadow_mask_bits = fixed_shadow;
|
||||
eci->material_mask_bits = fixed_mask;
|
||||
/* No need to split at the last point anyway. */
|
||||
break;
|
||||
@ -670,6 +710,7 @@ void MOD_lineart_chain_split_for_fixed_occlusion(LineartData *ld)
|
||||
eci->line_type,
|
||||
fixed_occ,
|
||||
fixed_mask,
|
||||
fixed_shadow,
|
||||
eci->index);
|
||||
new_ec->object_ref = ec->object_ref;
|
||||
new_ec->type = ec->type;
|
||||
@ -677,8 +718,10 @@ void MOD_lineart_chain_split_for_fixed_occlusion(LineartData *ld)
|
||||
ec = new_ec;
|
||||
fixed_occ = eci->occlusion;
|
||||
fixed_mask = eci->material_mask_bits;
|
||||
fixed_shadow = eci->shadow_mask_bits;
|
||||
ec->level = fixed_occ;
|
||||
ec->material_mask_bits = fixed_mask;
|
||||
ec->shadow_mask_bits = fixed_shadow;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -749,6 +792,7 @@ static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartData *ld,
|
||||
int occlusion,
|
||||
uint8_t material_mask_bits,
|
||||
uint8_t isec_mask,
|
||||
uint32_t shadow_mask,
|
||||
int loop_id,
|
||||
float dist,
|
||||
float *result_new_len,
|
||||
@ -779,7 +823,7 @@ static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartData *ld,
|
||||
}
|
||||
if (cre->ec == ec || (!cre->ec->chain.first) || (cre->ec->level != occlusion) ||
|
||||
(cre->ec->material_mask_bits != material_mask_bits) ||
|
||||
(cre->ec->intersection_mask != isec_mask)) {
|
||||
(cre->ec->intersection_mask != isec_mask) || (cre->ec->shadow_mask_bits != shadow_mask)) {
|
||||
continue;
|
||||
}
|
||||
if (!ld->conf.fuzzy_everything) {
|
||||
@ -826,6 +870,7 @@ static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartData *ld,
|
||||
occlusion, \
|
||||
material_mask_bits, \
|
||||
isec_mask, \
|
||||
shadow_mask, \
|
||||
loop_id, \
|
||||
dist, \
|
||||
&adjacent_new_len, \
|
||||
@ -856,8 +901,9 @@ void MOD_lineart_chain_connect(LineartData *ld)
|
||||
LineartChainRegisterEntry *closest_cre_l, *closest_cre_r, *closest_cre;
|
||||
float dist = ld->conf.chaining_image_threshold;
|
||||
float dist_l, dist_r;
|
||||
int occlusion, reverse_main, loop_id;
|
||||
uint8_t material_mask_bits, isec_mask;
|
||||
int reverse_main, loop_id;
|
||||
uint8_t occlusion, material_mask_bits, isec_mask;
|
||||
uint32_t shadow_mask;
|
||||
ListBase swap = {0};
|
||||
|
||||
if (ld->conf.chaining_image_threshold < 0.0001) {
|
||||
@ -871,7 +917,7 @@ void MOD_lineart_chain_connect(LineartData *ld)
|
||||
|
||||
while ((ec = BLI_pophead(&swap)) != NULL) {
|
||||
ec->next = ec->prev = NULL;
|
||||
if (ec->picked) {
|
||||
if (ec->picked || ec->chain.first == ec->chain.last) {
|
||||
continue;
|
||||
}
|
||||
BLI_addtail(&ld->chains, ec);
|
||||
@ -884,6 +930,7 @@ void MOD_lineart_chain_connect(LineartData *ld)
|
||||
occlusion = ec->level;
|
||||
material_mask_bits = ec->material_mask_bits;
|
||||
isec_mask = ec->intersection_mask;
|
||||
shadow_mask = ec->shadow_mask_bits;
|
||||
|
||||
eci_l = ec->chain.first;
|
||||
eci_r = ec->chain.last;
|
||||
@ -896,6 +943,7 @@ void MOD_lineart_chain_connect(LineartData *ld)
|
||||
occlusion,
|
||||
material_mask_bits,
|
||||
isec_mask,
|
||||
shadow_mask,
|
||||
loop_id,
|
||||
dist,
|
||||
&dist_l,
|
||||
@ -907,6 +955,7 @@ void MOD_lineart_chain_connect(LineartData *ld)
|
||||
occlusion,
|
||||
material_mask_bits,
|
||||
isec_mask,
|
||||
shadow_mask,
|
||||
loop_id,
|
||||
dist,
|
||||
&dist_r,
|
||||
@ -1072,20 +1121,22 @@ static LineartEdgeChainItem *lineart_chain_create_crossing_point(LineartData *ld
|
||||
LineartEdgeChainItem *eci_outside)
|
||||
{
|
||||
float isec[2];
|
||||
float LU[2] = {-1.0f, 1.0f}, LB[2] = {-1.0f, -1.0f}, RU[2] = {1.0f, 1.0f}, RB[2] = {1.0f, -1.0f};
|
||||
/* l: left, r: right, b: bottom, u: top. */
|
||||
float ref_lu[2] = {-1.0f, 1.0f}, ref_lb[2] = {-1.0f, -1.0f}, ref_ru[2] = {1.0f, 1.0f},
|
||||
ref_rb[2] = {1.0f, -1.0f};
|
||||
bool found = false;
|
||||
LineartEdgeChainItem *eci2 = eci_outside, *eci1 = eci_inside;
|
||||
if (eci2->pos[0] < -1.0f) {
|
||||
found = (isect_seg_seg_v2_point(eci1->pos, eci2->pos, LU, LB, isec) > 0);
|
||||
found = (isect_seg_seg_v2_point(eci1->pos, eci2->pos, ref_lu, ref_lb, isec) > 0);
|
||||
}
|
||||
if (!found && eci2->pos[0] > 1.0f) {
|
||||
found = (isect_seg_seg_v2_point(eci1->pos, eci2->pos, RU, RB, isec) > 0);
|
||||
found = (isect_seg_seg_v2_point(eci1->pos, eci2->pos, ref_ru, ref_rb, isec) > 0);
|
||||
}
|
||||
if (!found && eci2->pos[1] < -1.0f) {
|
||||
found = (isect_seg_seg_v2_point(eci1->pos, eci2->pos, LB, RB, isec) > 0);
|
||||
found = (isect_seg_seg_v2_point(eci1->pos, eci2->pos, ref_lb, ref_rb, isec) > 0);
|
||||
}
|
||||
if (!found && eci2->pos[1] > 1.0f) {
|
||||
found = (isect_seg_seg_v2_point(eci1->pos, eci2->pos, LU, RU, isec) > 0);
|
||||
found = (isect_seg_seg_v2_point(eci1->pos, eci2->pos, ref_lu, ref_ru, isec) > 0);
|
||||
}
|
||||
|
||||
if (UNLIKELY(!found)) {
|
||||
@ -1126,7 +1177,7 @@ void MOD_lineart_chain_clip_at_border(LineartData *ld)
|
||||
LineartEdgeChainItem *first_eci = (LineartEdgeChainItem *)ec->chain.first;
|
||||
is_inside = LRT_ECI_INSIDE(first_eci) ? true : false;
|
||||
if (!is_inside) {
|
||||
ec->picked = true;
|
||||
ec->picked = 1;
|
||||
}
|
||||
for (eci = first_eci->next; eci; eci = next_eci) {
|
||||
next_eci = eci->next;
|
||||
@ -1219,6 +1270,7 @@ void MOD_lineart_chain_split_angle(LineartData *ld, float angle_threshold_rad)
|
||||
eci->line_type,
|
||||
ec->level,
|
||||
eci->material_mask_bits,
|
||||
eci->shadow_mask_bits,
|
||||
eci->index);
|
||||
new_ec->object_ref = ec->object_ref;
|
||||
new_ec->type = ec->type;
|
||||
@ -1226,6 +1278,7 @@ void MOD_lineart_chain_split_angle(LineartData *ld, float angle_threshold_rad)
|
||||
new_ec->loop_id = ec->loop_id;
|
||||
new_ec->intersection_mask = ec->intersection_mask;
|
||||
new_ec->material_mask_bits = ec->material_mask_bits;
|
||||
new_ec->shadow_mask_bits = ec->shadow_mask_bits;
|
||||
ec = new_ec;
|
||||
}
|
||||
}
|
||||
@ -1270,3 +1323,19 @@ void MOD_lineart_chain_offset_towards_camera(LineartData *ld, float dist, bool u
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MOD_lineart_chain_find_silhouette_backdrop_objects(LineartData *ld)
|
||||
{
|
||||
LISTBASE_FOREACH (LineartEdgeChain *, ec, &ld->chains) {
|
||||
if (ec->type == LRT_EDGE_FLAG_CONTOUR &&
|
||||
ec->shadow_mask_bits & LRT_SHADOW_SILHOUETTE_ERASED_GROUP) {
|
||||
uint32_t target = ec->shadow_mask_bits & LRT_OBINDEX_HIGHER;
|
||||
LineartElementLinkNode *eln = lineart_find_matching_eln(&ld->geom.line_buffer_pointers,
|
||||
target);
|
||||
if (!eln) {
|
||||
continue;
|
||||
}
|
||||
ec->silhouette_backdrop = eln->object_ref;
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -66,14 +66,16 @@ int lineart_count_intersection_segment_count(struct LineartData *ld);
|
||||
void lineart_count_and_print_render_buffer_memory(struct LineartData *ld);
|
||||
|
||||
#define LRT_ITER_ALL_LINES_BEGIN \
|
||||
LineartEdge *e; \
|
||||
for (int i = 0; i < ld->pending_edges.next; i++) { \
|
||||
e = ld->pending_edges.array[i];
|
||||
{ \
|
||||
LineartEdge *e; \
|
||||
for (int __i = 0; __i < ld->pending_edges.next; __i++) { \
|
||||
e = ld->pending_edges.array[__i];
|
||||
|
||||
#define LRT_ITER_ALL_LINES_NEXT ; /* Doesn't do anything now with new array setup. */
|
||||
|
||||
#define LRT_ITER_ALL_LINES_END \
|
||||
LRT_ITER_ALL_LINES_NEXT \
|
||||
} \
|
||||
}
|
||||
|
||||
#define LRT_BOUND_AREA_CROSSES(b1, b2) \
|
||||
@ -83,11 +85,94 @@ void lineart_count_and_print_render_buffer_memory(struct LineartData *ld);
|
||||
* performance under current algorithm. */
|
||||
#define LRT_BA_ROWS 10
|
||||
|
||||
#define LRT_EDGE_BA_MARCHING_BEGIN(fb1, fb2) \
|
||||
double x = fb1[0], y = fb1[1]; \
|
||||
LineartBoundingArea *ba = lineart_edge_first_bounding_area(ld, fb1, fb2); \
|
||||
LineartBoundingArea *nba = ba; \
|
||||
double k = (fb2[1] - fb1[1]) / (fb2[0] - fb1[0] + 1e-30); \
|
||||
int positive_x = (fb2[0] - fb1[0]) > 0 ? 1 : (fb2[0] == fb1[0] ? 0 : -1); \
|
||||
int positive_y = (fb2[1] - fb1[1]) > 0 ? 1 : (fb2[1] == fb1[1] ? 0 : -1); \
|
||||
while (nba)
|
||||
|
||||
#define LRT_EDGE_BA_MARCHING_NEXT(fb1, fb2) \
|
||||
/* Marching along `e->v1` to `e->v2`, searching each possible bounding areas it may touch. */ \
|
||||
nba = lineart_bounding_area_next(nba, fb1, fb2, x, y, k, positive_x, positive_y, &x, &y);
|
||||
|
||||
#define LRT_EDGE_BA_MARCHING_END
|
||||
|
||||
void lineart_main_occlusion_begin(struct LineartData *ld);
|
||||
void lineart_main_cull_triangles(struct LineartData *ld, bool clip_far);
|
||||
void lineart_main_free_adjacent_data(struct LineartData *ld);
|
||||
void lineart_main_perspective_division(struct LineartData *ld);
|
||||
void lineart_main_discard_out_of_frame_edges(struct LineartData *ld);
|
||||
void lineart_main_load_geometries(struct Depsgraph *depsgraph,
|
||||
struct Scene *scene,
|
||||
struct Object *camera,
|
||||
struct LineartData *ld,
|
||||
bool allow_duplicates,
|
||||
bool do_shadow_casting,
|
||||
struct ListBase *shadow_elns);
|
||||
void lineart_main_get_view_vector(struct LineartData *ld);
|
||||
void lineart_main_bounding_area_make_initial(struct LineartData *ld);
|
||||
void lineart_main_bounding_areas_connect_post(struct LineartData *ld);
|
||||
void lineart_main_clear_linked_edges(struct LineartData *ld);
|
||||
void lineart_main_link_lines(struct LineartData *ld);
|
||||
void lineart_main_add_triangles(struct LineartData *ld);
|
||||
bool lineart_main_try_generate_shadow(struct Depsgraph *depsgraph,
|
||||
struct Scene *scene,
|
||||
struct LineartData *original_ld,
|
||||
struct LineartGpencilModifierData *lmd,
|
||||
struct LineartStaticMemPool *shadow_data_pool,
|
||||
struct LineartElementLinkNode **r_veln,
|
||||
struct LineartElementLinkNode **r_eeln,
|
||||
struct ListBase *r_calculated_edges_eln_list,
|
||||
struct LineartData **r_shadow_ld_if_reproject);
|
||||
void lineart_main_make_enclosed_shapes(struct LineartData *ld, struct LineartData *shadow_ld);
|
||||
void lineart_main_transform_and_add_shadow(struct LineartData *ld,
|
||||
struct LineartElementLinkNode *veln,
|
||||
struct LineartElementLinkNode *eeln);
|
||||
|
||||
LineartElementLinkNode *lineart_find_matching_eln(struct ListBase *shadow_elns, int obindex);
|
||||
LineartEdge *lineart_find_matching_edge(struct LineartElementLinkNode *shadow_eln,
|
||||
uint64_t edge_identifier);
|
||||
void lineart_register_shadow_cuts(struct LineartData *ld,
|
||||
struct LineartEdge *e,
|
||||
struct LineartEdge *shadow_edge);
|
||||
void lineart_register_intersection_shadow_cuts(struct LineartData *ld,
|
||||
struct ListBase *shadow_elns);
|
||||
|
||||
bool lineart_edge_from_triangle(const struct LineartTriangle *tri,
|
||||
const struct LineartEdge *e,
|
||||
bool allow_overlapping_edges);
|
||||
LineartBoundingArea *lineart_edge_first_bounding_area(struct LineartData *ld,
|
||||
double *fbcoord1,
|
||||
double *fbcoord2);
|
||||
LineartBoundingArea *lineart_bounding_area_next(struct LineartBoundingArea *_this,
|
||||
double *fbcoord1,
|
||||
double *fbcoord2,
|
||||
double x,
|
||||
double y,
|
||||
double k,
|
||||
int positive_x,
|
||||
int positive_y,
|
||||
double *next_x,
|
||||
double *next_y);
|
||||
void lineart_edge_cut(struct LineartData *ld,
|
||||
struct LineartEdge *e,
|
||||
double start,
|
||||
double end,
|
||||
uchar material_mask_bits,
|
||||
uchar mat_occlusion,
|
||||
uint32_t shadow_bits);
|
||||
void lineart_add_edge_to_array(struct LineartPendingEdges *pe, struct LineartEdge *e);
|
||||
void lineart_finalize_object_edge_array_reserve(struct LineartPendingEdges *pe, int count);
|
||||
void lineart_destroy_render_data_keep_init(struct LineartData *ld);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void lineart_sort_adjacent_items(LineartAdjacentEdge *ai, int length);
|
||||
void lineart_sort_adjacent_items(struct LineartAdjacentEdge *ai, int length);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -132,6 +132,8 @@ static bool bake_strokes(Object *ob,
|
||||
lmd->intersection_mask,
|
||||
lmd->thickness,
|
||||
lmd->opacity,
|
||||
lmd->shadow_selection,
|
||||
lmd->silhouette_selection,
|
||||
lmd->source_vertex_group,
|
||||
lmd->vgname,
|
||||
lmd->flags);
|
||||
|
1414
source/blender/gpencil_modifiers/intern/lineart/lineart_shadow.c
Normal file
1414
source/blender/gpencil_modifiers/intern/lineart/lineart_shadow.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -40,6 +40,7 @@ enum eCollectionLineArt_Usage {
|
||||
|
||||
enum eCollectionLineArt_Flags {
|
||||
COLLECTION_LRT_USE_INTERSECTION_MASK = (1 << 0),
|
||||
COLLECTION_LRT_USE_INTERSECTION_PRIORITY = (1 << 1),
|
||||
};
|
||||
|
||||
typedef struct Collection {
|
||||
@ -62,7 +63,8 @@ typedef struct Collection {
|
||||
short lineart_usage; /* eCollectionLineArt_Usage */
|
||||
unsigned char lineart_flags; /* eCollectionLineArt_Flags */
|
||||
unsigned char lineart_intersection_mask;
|
||||
char _pad[6];
|
||||
unsigned char lineart_intersection_priority;
|
||||
char _pad[5];
|
||||
|
||||
int16_t color_tag;
|
||||
|
||||
|
@ -296,7 +296,7 @@
|
||||
|
||||
#define _DNA_DEFAULT_LineartGpencilModifierData \
|
||||
{ \
|
||||
.edge_types = LRT_EDGE_FLAG_ALL_TYPE, \
|
||||
.edge_types = LRT_EDGE_FLAG_INIT_TYPE, \
|
||||
.thickness = 25, \
|
||||
.opacity = 1.0f, \
|
||||
.flags = LRT_GPENCIL_MATCH_OUTPUT_VGROUP, \
|
||||
@ -306,7 +306,12 @@
|
||||
/* Do not split by default, this is for better chaining quality. */ \
|
||||
.angle_splitting_threshold = 0.0f, \
|
||||
.chaining_image_threshold = 0.001f, \
|
||||
.chain_smooth_tolerance = 0.2f,\
|
||||
.stroke_depth_offset = 0.05,\
|
||||
.chain_smooth_tolerance = 0.0f,\
|
||||
.overscan = 0.1f,\
|
||||
.shadow_camera_near = 0.1f, \
|
||||
.shadow_camera_far = 200.0f, \
|
||||
.shadow_camera_size = 200.0f, \
|
||||
.stroke_depth_offset = 0.05,\
|
||||
}
|
||||
|
||||
|
@ -998,6 +998,18 @@ typedef enum eLineartGpencilModifierSource {
|
||||
LRT_SOURCE_SCENE = 2,
|
||||
} eLineartGpencilModifierSource;
|
||||
|
||||
typedef enum eLineartGpencilModifierShadowFilter {
|
||||
LRT_SHADOW_FILTER_NONE = 0,
|
||||
LRT_SHADOW_FILTER_LIT = 1,
|
||||
LRT_SHADOW_FILTER_SHADED = 2,
|
||||
} eLineartGpencilModifierShadowFilter;
|
||||
|
||||
typedef enum eLineartGpencilModifierSilhouetteFilter {
|
||||
LRT_SILHOUETTE_FILTER_NONE = 0,
|
||||
LRT_SILHOUETTE_FILTER_GROUP = (1 << 0),
|
||||
LRT_SILHOUETTE_FILTER_INDIVIDUAL = (1 << 1),
|
||||
} eLineartGpencilModifierSilhouetteFilter;
|
||||
|
||||
/* This enum is for modifier internal state only. */
|
||||
typedef enum eLineArtGPencilModifierFlags {
|
||||
/* These two moved to #eLineartMainFlags to keep consistent with flag variable purpose. */
|
||||
@ -1008,6 +1020,7 @@ typedef enum eLineArtGPencilModifierFlags {
|
||||
LRT_GPENCIL_USE_CACHE = (1 << 4),
|
||||
LRT_GPENCIL_OFFSET_TOWARDS_CUSTOM_CAMERA = (1 << 5),
|
||||
LRT_GPENCIL_INVERT_COLLECTION = (1 << 6),
|
||||
LRT_GPENCIL_INVERT_SILHOUETTE_FILTER = (1 << 7),
|
||||
} eLineArtGPencilModifierFlags;
|
||||
|
||||
typedef enum eLineartGpencilMaskSwitches {
|
||||
@ -1024,8 +1037,7 @@ struct LineartCache;
|
||||
typedef struct LineartGpencilModifierData {
|
||||
GpencilModifierData modifier;
|
||||
|
||||
/** Line type enable flags, bits in #eLineartEdgeFlag. */
|
||||
short edge_types;
|
||||
uint16_t edge_types; /* line type enable flags, bits in eLineartEdgeFlag */
|
||||
|
||||
/** Object or Collection, from #eLineartGpencilModifierSource. */
|
||||
char source_type;
|
||||
@ -1035,6 +1047,7 @@ typedef struct LineartGpencilModifierData {
|
||||
short level_end;
|
||||
|
||||
struct Object *source_camera;
|
||||
struct Object *light_contour_object;
|
||||
|
||||
struct Object *source_object;
|
||||
struct Collection *source_collection;
|
||||
@ -1049,14 +1062,19 @@ typedef struct LineartGpencilModifierData {
|
||||
char source_vertex_group[64];
|
||||
char vgname[64];
|
||||
|
||||
/**
|
||||
* Camera focal length is divided by `1 + overscan`, before calculation, which give a wider FOV,
|
||||
* this doesn't change coordinates range internally (-1, 1), but makes the calculated frame
|
||||
/* Camera focal length is divided by (1 + overscan), before caluclation, which give a wider FOV,
|
||||
* this doesn't change coordinates range internally (-1, 1), but makes the caluclated frame
|
||||
* bigger than actual output. This is for the easier shifting calculation. A value of 0.5 means
|
||||
* the "internal" focal length become 2/3 of the actual camera.
|
||||
*/
|
||||
* the "internal" focal length become 2/3 of the actual camera. */
|
||||
float overscan;
|
||||
|
||||
/* Values for point light and directional (sun) light. */
|
||||
/* For point light, fov always gonna be 120 deg horizontal, with 3 "cameras" covering 360 deg. */
|
||||
float shadow_camera_fov;
|
||||
float shadow_camera_size;
|
||||
float shadow_camera_near;
|
||||
float shadow_camera_far;
|
||||
|
||||
float opacity;
|
||||
short thickness;
|
||||
|
||||
@ -1064,7 +1082,9 @@ typedef struct LineartGpencilModifierData {
|
||||
unsigned char material_mask_bits;
|
||||
unsigned char intersection_mask;
|
||||
|
||||
char _pad[3];
|
||||
unsigned char shadow_selection;
|
||||
unsigned char silhouette_selection;
|
||||
char _pad[1];
|
||||
|
||||
/** `0..1` range for cosine angle */
|
||||
float crease_threshold;
|
||||
@ -1078,7 +1098,7 @@ typedef struct LineartGpencilModifierData {
|
||||
/* CPU mode */
|
||||
float chaining_image_threshold;
|
||||
|
||||
/* Ported from SceneLineArt flags. */
|
||||
/* eLineartMainFlags, for one time calculation. */
|
||||
int calculation_flags;
|
||||
|
||||
/* #eLineArtGPencilModifierFlags, modifier internal state. */
|
||||
@ -1095,6 +1115,10 @@ typedef struct LineartGpencilModifierData {
|
||||
char level_start_override;
|
||||
char level_end_override;
|
||||
short edge_types_override;
|
||||
char shadow_selection_override;
|
||||
char shadow_use_silhouette_override;
|
||||
|
||||
char _pad2[6];
|
||||
|
||||
struct LineartCache *cache;
|
||||
/* Keep a pointer to the render buffer so we can call destroy from ModifierData. */
|
||||
|
@ -38,6 +38,8 @@ typedef enum eLineartMainFlags {
|
||||
LRT_USE_BACK_FACE_CULLING = (1 << 19),
|
||||
LRT_USE_IMAGE_BOUNDARY_TRIMMING = (1 << 20),
|
||||
LRT_CHAIN_PRESERVE_DETAILS = (1 << 22),
|
||||
LRT_SHADOW_ENCLOSED_SHAPES = (1 << 23),
|
||||
LRT_SHADOW_USE_SILHOUETTE = (1 << 24),
|
||||
} eLineartMainFlags;
|
||||
|
||||
typedef enum eLineartEdgeFlag {
|
||||
@ -47,14 +49,19 @@ typedef enum eLineartEdgeFlag {
|
||||
LRT_EDGE_FLAG_MATERIAL = (1 << 3),
|
||||
LRT_EDGE_FLAG_INTERSECTION = (1 << 4),
|
||||
LRT_EDGE_FLAG_LOOSE = (1 << 5),
|
||||
LRT_EDGE_FLAG_LIGHT_CONTOUR = (1 << 6),
|
||||
/* LRT_EDGE_FLAG_FOR_FUTURE = (1 << 7), */
|
||||
/**
|
||||
* It's a legacy limit of 8 bits for feature lines that come from original mesh edges. It should
|
||||
* not be needed in current object loading scheme, but might still be relevant if we are to
|
||||
* implement edit-mesh loading, so don't exceed 8 bits just yet.
|
||||
*/
|
||||
LRT_EDGE_FLAG_CHAIN_PICKED = (1 << 8),
|
||||
LRT_EDGE_FLAG_CLIPPED = (1 << 9),
|
||||
/* It's a legacy limit of 8 bits for feature lines that come from original mesh edges. It should
|
||||
not be needed in current object loading scheme, but might still be relevant if we are to
|
||||
impelment EditMesh loading, so don't exceed 8 bits just yet. */
|
||||
LRT_EDGE_FLAG_PROJECTED_SHADOW = (1 << 8),
|
||||
/* To determine an edge to be occluded from the front or back face it's lying on. */
|
||||
LRT_EDGE_FLAG_SHADOW_FACING_LIGHT = (1 << 9),
|
||||
/** Also used as discarded line mark. */
|
||||
LRT_EDGE_FLAG_CHAIN_PICKED = (1 << 10),
|
||||
LRT_EDGE_FLAG_CLIPPED = (1 << 11),
|
||||
/** Used to specify contor from viewing camera when computing shadows. */
|
||||
LRT_EDGE_FLAG_CONTOUR_SECONDARY = (1 << 12),
|
||||
/** Limited to 16 bits for the entire thing. */
|
||||
|
||||
/** For object loading code to use only. */
|
||||
@ -63,4 +70,6 @@ typedef enum eLineartEdgeFlag {
|
||||
LRT_EDGE_FLAG_NEXT_IS_DUPLICATION = (1 << 15),
|
||||
} eLineartEdgeFlag;
|
||||
|
||||
#define LRT_EDGE_FLAG_ALL_TYPE 0x3f
|
||||
#define LRT_EDGE_FLAG_ALL_TYPE 0x01ff
|
||||
#define LRT_EDGE_FLAG_INIT_TYPE 0x37 /* Without material & light contour */
|
||||
#define LRT_EDGE_FLAG_TYPE_MAX_BITS 7
|
||||
|
@ -150,14 +150,15 @@ typedef struct MaterialLineArt {
|
||||
/** Maximum 255 levels of equivalent occlusion. */
|
||||
unsigned char mat_occlusion;
|
||||
|
||||
unsigned char _pad[2];
|
||||
unsigned char intersection_priority;
|
||||
|
||||
char _pad;
|
||||
} MaterialLineArt;
|
||||
|
||||
typedef enum eMaterialLineArtFlags {
|
||||
LRT_MATERIAL_MASK_ENABLED = (1 << 0),
|
||||
|
||||
/* Deprecated, kept for versioning code. */
|
||||
LRT_MATERIAL_CUSTOM_OCCLUSION_EFFECTIVENESS = (1 << 1),
|
||||
LRT_MATERIAL_CUSTOM_INTERSECTION_PRIORITY = (1 << 2),
|
||||
} eMaterialLineArtFlags;
|
||||
|
||||
typedef struct Material {
|
||||
|
@ -215,6 +215,10 @@ typedef struct ObjectLineArt {
|
||||
|
||||
/** if OBJECT_LRT_OWN_CREASE is set */
|
||||
float crease_threshold;
|
||||
|
||||
unsigned char intersection_priority;
|
||||
|
||||
char _pad[7];
|
||||
} ObjectLineArt;
|
||||
|
||||
/**
|
||||
@ -231,6 +235,7 @@ enum eObjectLineArt_Usage {
|
||||
|
||||
enum eObjectLineArt_Flags {
|
||||
OBJECT_LRT_OWN_CREASE = (1 << 0),
|
||||
OBJECT_LRT_OWN_INTERSECTION_PRIORITY = (1 << 1),
|
||||
};
|
||||
|
||||
typedef struct Object {
|
||||
|
@ -549,6 +549,22 @@ void RNA_def_collections(BlenderRNA *brna)
|
||||
prop, "Masks", "Intersection generated by this collection will have this mask value");
|
||||
RNA_def_property_update(prop, NC_SCENE, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "lineart_intersection_priority", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 0, 255);
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Intersection Priority",
|
||||
"The intersection line will be included into the object with the "
|
||||
"higher intersection priority value");
|
||||
RNA_def_property_update(prop, NC_SCENE, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "use_lineart_intersection_priority", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_default(prop, 0);
|
||||
RNA_def_property_boolean_sdna(
|
||||
prop, NULL, "lineart_flags", COLLECTION_LRT_USE_INTERSECTION_PRIORITY);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Use Intersection Priority", "Assign intersection priority value for this collection");
|
||||
RNA_def_property_update(prop, NC_SCENE, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "color_tag", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "color_tag");
|
||||
RNA_def_property_enum_funcs(
|
||||
|
@ -3196,6 +3196,20 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
static const EnumPropertyItem modifier_lineart_shadow_region_filtering[] = {
|
||||
{LRT_SHADOW_FILTER_NONE, "NONE", 0, "None", ""},
|
||||
{LRT_SHADOW_FILTER_LIT, "LIT", 0, "Lit", ""},
|
||||
{LRT_SHADOW_FILTER_SHADED, "SHADED", 0, "Shaded", ""},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
static const EnumPropertyItem modifier_lineart_silhouette_filtering[] = {
|
||||
{LRT_SILHOUETTE_FILTER_NONE, "NONE", 0, "Contour", ""},
|
||||
{LRT_SILHOUETTE_FILTER_GROUP, "GROUP", 0, "Silhouette", ""},
|
||||
{LRT_SILHOUETTE_FILTER_INDIVIDUAL, "INDIVIDUAL", 0, "Individual Silhouette", ""},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
srna = RNA_def_struct(brna, "LineartGpencilModifier", "GpencilModifier");
|
||||
RNA_def_struct_ui_text(
|
||||
srna, "Line Art Modifier", "Generate line art strokes from selected source");
|
||||
@ -3208,7 +3222,7 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_USE_CUSTOM_CAMERA);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Use Custom Camera", "Use custom camera instead of the active camera");
|
||||
RNA_def_property_update(prop, NC_SCENE, "rna_GpencilModifier_update");
|
||||
RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
|
||||
|
||||
prop = RNA_def_property(srna, "use_fuzzy_intersections", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_INTERSECTION_AS_CONTOUR);
|
||||
@ -3250,8 +3264,11 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
|
||||
prop = RNA_def_property(srna, "crease_threshold", PROP_FLOAT, PROP_ANGLE);
|
||||
RNA_def_property_range(prop, 0, DEG2RAD(180.0f));
|
||||
RNA_def_property_ui_range(prop, 0.0f, DEG2RAD(180.0f), 0.01f, 1);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Crease Threshold", "Angles smaller than this will be treated as creases");
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Crease Threshold",
|
||||
"Angles smaller than this will be treated as creases. Crease angle "
|
||||
"priority: object line art crease override > mesh auto smooth angle > "
|
||||
"line art default crease.");
|
||||
RNA_def_property_update(prop, NC_SCENE, "rna_GpencilModifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "split_angle", PROP_FLOAT, PROP_ANGLE);
|
||||
@ -3367,6 +3384,14 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
|
||||
prop, "Camera Object", "Use specified camera object for generating line art");
|
||||
RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
|
||||
|
||||
prop = RNA_def_property(srna, "light_contour_object", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
|
||||
RNA_def_property_struct_type(prop, "Object");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Light Object", "Use this light object to generate light contour");
|
||||
RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_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");
|
||||
@ -3417,6 +3442,41 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(prop, "Use Intersection", "Generate strokes from intersections");
|
||||
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "use_light_contour", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "edge_types", LRT_EDGE_FLAG_LIGHT_CONTOUR);
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Use Light Contour",
|
||||
"Generate light/shadow separation lines from a reference light object");
|
||||
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "use_shadow", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "edge_types", LRT_EDGE_FLAG_PROJECTED_SHADOW);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Use Shadow", "Project contour lines using a light shource object");
|
||||
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "shadow_region_filtering", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "shadow_selection");
|
||||
RNA_def_property_enum_items(prop, modifier_lineart_shadow_region_filtering);
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Shadow Region Filtering",
|
||||
"Select feature lines that comes from lit or shaded regions. Will not "
|
||||
"affect cast shadow and light contour since they are at the border");
|
||||
RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
|
||||
|
||||
prop = RNA_def_property(srna, "shadow_enclosed_shapes", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_SHADOW_ENCLOSED_SHAPES);
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Shadow Enclosed Shapes",
|
||||
"Reproject visible lines again to get enclosed shadow shapes");
|
||||
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "silhouette_filtering", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "silhouette_selection");
|
||||
RNA_def_property_enum_items(prop, modifier_lineart_silhouette_filtering);
|
||||
RNA_def_property_ui_text(prop, "Silhouette Filtering", "Select contour or silhouette");
|
||||
RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
|
||||
|
||||
prop = RNA_def_property(srna, "use_multiple_levels", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "use_multiple_levels", 0);
|
||||
RNA_def_property_ui_text(
|
||||
@ -3558,6 +3618,27 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
|
||||
"different occlusion levels than when disabled");
|
||||
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "shadow_camera_near", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_ui_text(prop, "Shadow Camera Near", "Near clipping distance of shadow camera");
|
||||
RNA_def_property_ui_range(prop, 0.0f, 500.0f, 0.1f, 2);
|
||||
RNA_def_property_range(prop, 0.0f, 10000.0f);
|
||||
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "shadow_camera_far", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_ui_text(prop, "Shadow Camera Far", "Far clipping distance of shadow camera");
|
||||
RNA_def_property_ui_range(prop, 0.0f, 500.0f, 0.1f, 2);
|
||||
RNA_def_property_range(prop, 0.0f, 10000.0f);
|
||||
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "shadow_camera_size", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Shadow Camera Size",
|
||||
"This value represent the \"Orthographic Scale\" of an ortho camera."
|
||||
"If the camera is put at the lamps position with this scale, it will "
|
||||
"represent the coverage of the shadow \"camera\" ");
|
||||
RNA_def_property_ui_range(prop, 0.0f, 500.0f, 0.1f, 2);
|
||||
RNA_def_property_range(prop, 0.0f, 10000.0f);
|
||||
|
||||
prop = RNA_def_property(srna, "use_invert_collection", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flags", LRT_GPENCIL_INVERT_COLLECTION);
|
||||
RNA_def_property_ui_text(prop,
|
||||
@ -3565,6 +3646,11 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
|
||||
"Select everything except lines from specified collection");
|
||||
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "use_invert_silhouette", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flags", LRT_GPENCIL_INVERT_SILHOUETTE_FILTER);
|
||||
RNA_def_property_ui_text(prop, "Invert Silhouette Filtering", "Select anti-silhouette lines");
|
||||
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
|
||||
|
||||
RNA_define_lib_overridable(false);
|
||||
}
|
||||
|
||||
|
@ -754,6 +754,22 @@ static void rna_def_material_lineart(BlenderRNA *brna)
|
||||
"Effectiveness",
|
||||
"Faces with this material will behave as if it has set number of layers in occlusion");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialLineArt_update");
|
||||
|
||||
prop = RNA_def_property(srna, "intersection_priority", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 0, 255);
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Intersection Priority",
|
||||
"The intersection line will be included into the object with the "
|
||||
"higher intersection priority value");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialLineArt_update");
|
||||
|
||||
prop = RNA_def_property(srna, "use_intersection_priority_override", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_default(prop, 0);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flags", LRT_MATERIAL_CUSTOM_INTERSECTION_PRIORITY);
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Use Intersection Priority",
|
||||
"Override object and collection intersection priority value");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialLineArt_update");
|
||||
}
|
||||
|
||||
void RNA_def_material(BlenderRNA *brna)
|
||||
|
@ -2950,6 +2950,22 @@ static void rna_def_object_lineart(BlenderRNA *brna)
|
||||
RNA_def_property_ui_range(prop, 0.0f, DEG2RAD(180.0f), 0.01f, 1);
|
||||
RNA_def_property_ui_text(prop, "Crease", "Angles smaller than this will be treated as creases");
|
||||
RNA_def_property_update(prop, 0, "rna_object_lineart_update");
|
||||
|
||||
prop = RNA_def_property(srna, "use_intersection_priority_override", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flags", OBJECT_LRT_OWN_INTERSECTION_PRIORITY);
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Use Intersection Priority",
|
||||
"Use this object's intersection priority to override collection setting");
|
||||
RNA_def_property_update(prop, 0, "rna_object_lineart_update");
|
||||
|
||||
prop = RNA_def_property(srna, "intersection_priority", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 0, 255);
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Intersection Priority",
|
||||
"The intersection line will be included into the object with the "
|
||||
"higher intersection priority value");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_object_lineart_update");
|
||||
}
|
||||
|
||||
static void rna_def_object_visibility(StructRNA *srna)
|
||||
|
Loading…
x
Reference in New Issue
Block a user