Merge branch 'blender-v3.3-release'

This commit is contained in:
Howard Trickey 2022-08-06 13:16:34 -04:00
commit fecef2ae74
8 changed files with 89 additions and 144 deletions

View File

@ -437,16 +437,6 @@ static bool nearly_parallel_normalized(const float d1[3], const float d2[3])
return compare_ff(fabsf(direction_dot), 1.0f, BEVEL_EPSILON_ANG_DOT);
}
/**
* calculate the determinant of a matrix formed by three vectors
* \return dot(a, cross(b, c)) = determinant(a, b, c)
*/
static float determinant_v3v3v3(const float a[3], const float b[3], const float c[3])
{
return a[0] * b[1] * c[2] + a[1] * b[2] * c[0] + a[2] * b[0] * c[1] - a[0] * b[2] * c[1] -
a[1] * b[0] * c[2] - a[2] * b[1] * c[0];
}
/* Make a new BoundVert of the given kind, inserting it at the end of the circular linked
* list with entry point bv->boundstart, and return it. */
static BoundVert *add_new_bound_vert(MemArena *mem_arena, VMesh *vm, const float co[3])
@ -4134,114 +4124,44 @@ static VMesh *cubic_subdiv(BevelParams *bp, VMesh *vm_in)
VMesh *vm_out = new_adj_vmesh(bp->mem_arena, n_boundary, ns_out, vm_in->boundstart);
/* First we adjust the boundary vertices of the input mesh, storing in output mesh. */
BoundVert *bndv = vm_in->boundstart;
for (int i = 0; i < n_boundary; i++) {
float co1[3], co2[3], acc[3];
EdgeHalf *e = bndv->elast;
/* Generate tangents. This is hacked together and would ideally be done elsewhere and then only
* used here. */
float tangent[3], tangent2[3], normal[3];
bool convex = true;
bool orthogonal = false;
float stretch = 0.0f;
if (e) {
/* Projection direction is direction of the edge. */
sub_v3_v3v3(tangent, e->e->v1->co, e->e->v2->co);
if (e->is_rev) {
negate_v3(tangent);
}
normalize_v3(tangent);
if (bndv->is_arc_start || bndv->is_patch_start) {
BMFace *face = e->fnext;
if (face) {
copy_v3_v3(normal, face->no);
}
else {
zero_v3(normal);
}
madd_v3_v3v3fl(co2, bndv->profile.middle, normal, 0.1f);
}
if (bndv->is_arc_start || bp->affect_type == BEVEL_AFFECT_VERTICES) {
EdgeHalf *e1 = bndv->next->elast;
BLI_assert(e1);
sub_v3_v3v3(tangent2, e1->e->v1->co, e1->e->v2->co);
if (e1->is_rev) {
negate_v3(tangent2);
}
normalize_v3(tangent2);
convex = determinant_v3v3v3(tangent2, tangent, normal) < 0;
add_v3_v3(tangent2, tangent);
normalize_v3(tangent2);
copy_v3_v3(tangent, tangent2);
}
/* Calculate a factor which determines how much the interpolated mesh is
* going to be stretched out into the direction of the tangent.
* It is currently using the difference along the tangent of the
* central point on the profile and the current center vertex position. */
get_profile_point(bp, &bndv->profile, ns_in2, ns_in, co);
stretch = dot_v3v3(tangent, mesh_vert(vm_in, i, ns_in2, ns_in2)->co) - dot_v3v3(tangent, co);
stretch = fabsf(stretch);
/* Scale the tangent by stretch. The divide by ns_in2 comes from the Levin Paper. */
mul_v3_fl(tangent, stretch / ns_in2);
orthogonal = bndv->is_patch_start;
}
else if (bndv->prev->is_patch_start) {
/* If this is the second edge of a patch and therefore #e is NULL,
* then e->fprev has to be used/not NULL. */
BLI_assert(bndv->prev->elast);
BMFace *face = bndv->prev->elast->fnext;
if (face) {
copy_v3_v3(normal, face->no);
}
else {
zero_v3(normal);
}
orthogonal = true;
}
else {
/** Should only come here from make_cube_corner_adj_vmesh. */
sub_v3_v3v3(co1, mesh_vert(vm_in, i, 0, 0)->co, mesh_vert(vm_in, i, 0, 1)->co);
sub_v3_v3v3(co2, mesh_vert(vm_in, i, 0, 1)->co, mesh_vert(vm_in, i, 0, 2)->co);
cross_v3_v3v3(tangent, co1, co2);
/** The following constant is chosen to best match the old results. */
normalize_v3_length(tangent, 1.5f / ns_out);
}
/** Copy corner vertex. */
copy_v3_v3(mesh_vert(vm_out, i, 0, 0)->co, mesh_vert(vm_in, i, 0, 0)->co);
/** Copy the rest of the boundary vertices. */
for (int k = 1; k < ns_in; k++) {
copy_v3_v3(co, mesh_vert(vm_in, i, 0, k)->co);
copy_v3_v3(co1, mesh_vert(vm_in, i, 0, k - 1)->co);
copy_v3_v3(co2, mesh_vert(vm_in, i, 0, k + 1)->co);
/* Smooth boundary rule. Custom profiles shouldn't be smoothed. */
if (bp->profile_type != BEVEL_PROFILE_CUSTOM) {
float co1[3], co2[3], acc[3];
copy_v3_v3(co1, mesh_vert(vm_in, i, 0, k - 1)->co);
copy_v3_v3(co2, mesh_vert(vm_in, i, 0, k + 1)->co);
add_v3_v3v3(acc, co1, co2);
if (bndv->is_arc_start) {
sub_v3_v3(co1, co);
sub_v3_v3(co2, co);
normalize_v3(co1);
normalize_v3(co2);
add_v3_v3v3(tangent, co1, co2);
/* This is an empirical formula to make the result look good. */
normalize_v3(tangent);
float dot = convex ? fminf(0, dot_v3v3(tangent2, tangent)) : 1.0f;
mul_v3_fl(tangent, stretch / ns_in * dot);
add_v3_v3v3(acc, co1, co2);
madd_v3_v3fl(acc, co, -2.0f);
madd_v3_v3fl(co, acc, -1.0f / 6.0f);
}
else if (orthogonal) {
sub_v3_v3(co1, co);
cross_v3_v3v3(tangent, normal, co1);
/* This is an empirical formula to make the result look good. */
normalize_v3_length(tangent, -bp->offset * 0.7071f / ns_in);
}
mul_v3_fl(co, 2.0f);
madd_v3_v3fl(co, acc, -0.25f);
madd_v3_v3fl(co, mesh_vert(vm_in, i, 1, k)->co, -0.5f);
add_v3_v3(co, tangent);
copy_v3_v3(mesh_vert_canon(vm_out, i, 0, 2 * k)->co, co);
}
}
/* Now adjust odd boundary vertices in output mesh, based on even ones. */
BoundVert *bndv = vm_out->boundstart;
for (int i = 0; i < n_boundary; i++) {
for (int k = 1; k < ns_out; k += 2) {
get_profile_point(bp, &bndv->profile, k, ns_out, co);
/* Smooth if using a non-custom profile. */
if (bp->profile_type != BEVEL_PROFILE_CUSTOM) {
float co1[3], co2[3], acc[3];
copy_v3_v3(co1, mesh_vert_canon(vm_out, i, 0, k - 1)->co);
copy_v3_v3(co2, mesh_vert_canon(vm_out, i, 0, k + 1)->co);
add_v3_v3v3(acc, co1, co2);
madd_v3_v3fl(acc, co, -2.0f);
madd_v3_v3fl(co, acc, -1.0f / 6.0f);
}
copy_v3_v3(mesh_vert_canon(vm_out, i, 0, k)->co, co);
}
bndv = bndv->next;
}
vmesh_copy_equiv_verts(vm_out);
@ -4249,7 +4169,7 @@ static VMesh *cubic_subdiv(BevelParams *bp, VMesh *vm_in)
/* Copy adjusted verts back into vm_in. */
for (int i = 0; i < n_boundary; i++) {
for (int k = 0; k < ns_in; k++) {
copy_v3_v3(mesh_vert_canon(vm_in, i, 0, k)->co, mesh_vert_canon(vm_out, i, 0, 2 * k)->co);
copy_v3_v3(mesh_vert(vm_in, i, 0, k)->co, mesh_vert(vm_out, i, 0, 2 * k)->co);
}
}
@ -4334,7 +4254,7 @@ static VMesh *cubic_subdiv(BevelParams *bp, VMesh *vm_in)
vmesh_copy_equiv_verts(vm_out);
/* The center vertex is special. */
gamma = sabin_gamma(n_boundary) * 0.5f;
gamma = sabin_gamma(n_boundary);
beta = -gamma;
/* Accumulate edge verts in co1, face verts in co2. */
float co1[3], co2[3];

View File

@ -373,19 +373,16 @@ static void edge_types_panel_draw(const bContext *UNUSED(C), Panel *panel)
}
sub = uiLayoutRow(col, false);
uiItemR(sub, ptr, "use_crease", 0, "", ICON_NONE);
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_("Crease Angle Cached"), ICON_INFO);
uiItemR(sub, ptr, "use_crease", 0, IFACE_("Crease (Angle Cached)"), ICON_NONE);
}
else {
uiItemR(entry,
uiItemR(sub, ptr, "use_crease", 0, "", ICON_NONE);
uiItemR(sub,
ptr,
"crease_threshold",
UI_ITEM_R_SLIDER | UI_ITEM_R_FORCE_BLANK_DECORATE,
IFACE_("Default Angle"),
NULL,
ICON_NONE);
}
@ -447,8 +444,6 @@ static void options_light_reference_draw(const bContext *UNUSED(C), Panel *panel
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, "use_shadow_enclosed_shapes", 0, IFACE_("Enclosed Shapes"), ICON_NONE);
}
static void options_panel_draw(const bContext *UNUSED(C), Panel *panel)

View File

@ -440,12 +440,17 @@ typedef enum eLineartTriangleFlags {
} eLineartTriangleFlags;
#define LRT_SHADOW_MASK_UNDEFINED 0
#define LRT_SHADOW_MASK_LIT (1 << 0)
#define LRT_SHADOW_MASK_ILLUMINATED (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)
#define LRT_SHADOW_MASK_ILLUMINATED_SHAPE (1 << 6)
#define LRT_SHADOW_TEST_SHAPE_BITS \
(LRT_SHADOW_MASK_ILLUMINATED | LRT_SHADOW_MASK_SHADED | LRT_SHADOW_MASK_INHIBITED | \
LRT_SHADOW_MASK_ILLUMINATED_SHAPE)
/**
* Controls how many edges a worker thread is processing at one request.

View File

@ -304,13 +304,12 @@ void lineart_edge_cut(LineartData *ld,
/* The enclosed shape flag will override regular lit/shaded
* flags. See LineartEdgeSegment::shadow_mask_bits for details. */
if (shadow_bits == LRT_SHADOW_MASK_ENCLOSED_SHAPE) {
if (seg->shadow_mask_bits & LRT_SHADOW_MASK_LIT || e->flags & LRT_EDGE_FLAG_LIGHT_CONTOUR) {
seg->shadow_mask_bits &= ~LRT_SHADOW_MASK_LIT;
if (seg->shadow_mask_bits & LRT_SHADOW_MASK_ILLUMINATED ||
e->flags & LRT_EDGE_FLAG_LIGHT_CONTOUR) {
seg->shadow_mask_bits |= LRT_SHADOW_MASK_INHIBITED;
}
else if (seg->shadow_mask_bits & LRT_SHADOW_MASK_SHADED) {
seg->shadow_mask_bits &= ~LRT_SHADOW_MASK_SHADED;
seg->shadow_mask_bits |= LRT_SHADOW_MASK_LIT;
seg->shadow_mask_bits |= LRT_SHADOW_MASK_ILLUMINATED_SHAPE;
}
}
else {
@ -3643,7 +3642,8 @@ static LineartData *lineart_create_render_buffer(Scene *scene,
(lmd->light_contour_object != NULL));
ld->conf.shadow_selection = lmd->shadow_selection_override;
ld->conf.shadow_enclose_shapes = (lmd->calculation_flags & LRT_SHADOW_ENCLOSED_SHAPES) != 0;
ld->conf.shadow_enclose_shapes = lmd->shadow_selection_override ==
LRT_SHADOW_FILTER_ILLUMINATED_ENCLOSED_SHAPES;
ld->conf.shadow_use_silhouette = lmd->shadow_use_silhouette_override != 0;
ld->conf.use_back_face_culling = (lmd->calculation_flags & LRT_USE_BACK_FACE_CULLING) != 0;
@ -5227,13 +5227,22 @@ static void lineart_gpencil_generate(LineartCache *cache,
}
if (shaodow_selection) {
if (ec->shadow_mask_bits != LRT_SHADOW_MASK_UNDEFINED) {
/* TODO(@Yiming): Give a behavior option for how to display undefined shadow info. */
if ((shaodow_selection == LRT_SHADOW_FILTER_LIT &&
(!(ec->shadow_mask_bits & LRT_SHADOW_MASK_LIT))) ||
(shaodow_selection == LRT_SHADOW_FILTER_SHADED &&
(!(ec->shadow_mask_bits & LRT_SHADOW_MASK_SHADED)))) {
/* TODO(Yiming): Give a behaviour option for how to display undefined shadow info. */
if ((shaodow_selection == LRT_SHADOW_FILTER_ILLUMINATED &&
(!(ec->shadow_mask_bits & LRT_SHADOW_MASK_ILLUMINATED)))) {
continue;
}
else if ((shaodow_selection == LRT_SHADOW_FILTER_SHADED &&
(!(ec->shadow_mask_bits & LRT_SHADOW_MASK_SHADED)))) {
continue;
}
else if (shaodow_selection == LRT_SHADOW_FILTER_ILLUMINATED_ENCLOSED_SHAPES) {
uint32_t test_bits = ec->shadow_mask_bits & LRT_SHADOW_TEST_SHAPE_BITS;
if ((test_bits != LRT_SHADOW_MASK_ILLUMINATED) &&
(test_bits != (LRT_SHADOW_MASK_SHADED | LRT_SHADOW_MASK_ILLUMINATED_SHAPE))) {
continue;
}
}
}
}
if (silhouette_mode && (ec->type & (LRT_EDGE_FLAG_CONTOUR))) {

View File

@ -109,9 +109,10 @@ void lineart_register_shadow_cuts(LineartData *ld, LineartEdge *e, LineartEdge *
la2 = la2 * e->v2->fbcoord[3] /
(e->v1->fbcoord[3] - la2 * (e->v1->fbcoord[3] - e->v2->fbcoord[3]));
unsigned char shadow_bits = (es->occlusion != 0) ? LRT_SHADOW_MASK_SHADED :
LRT_SHADOW_MASK_LIT;
LRT_SHADOW_MASK_ILLUMINATED;
if (lineart_contour_viewed_from_dark_side(ld, e) && shadow_bits == LRT_SHADOW_MASK_LIT) {
if (lineart_contour_viewed_from_dark_side(ld, e) &&
shadow_bits == LRT_SHADOW_MASK_ILLUMINATED) {
shadow_bits = LRT_SHADOW_MASK_SHADED;
}

View File

@ -999,9 +999,14 @@ typedef enum eLineartGpencilModifierSource {
} eLineartGpencilModifierSource;
typedef enum eLineartGpencilModifierShadowFilter {
/* These options need to be ordered in this way because those latter options requires line art to
run a few extra stages. Having those values set up this way will allow
#BKE_gpencil_get_lineart_modifier_limits() to find out maximum stages needed in multiple
cached line art modifiers. */
LRT_SHADOW_FILTER_NONE = 0,
LRT_SHADOW_FILTER_LIT = 1,
LRT_SHADOW_FILTER_ILLUMINATED = 1,
LRT_SHADOW_FILTER_SHADED = 2,
LRT_SHADOW_FILTER_ILLUMINATED_ENCLOSED_SHAPES = 3,
} eLineartGpencilModifierShadowFilter;
typedef enum eLineartGpencilModifierSilhouetteFilter {

View File

@ -38,7 +38,6 @@ 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;

View File

@ -3197,9 +3197,27 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
};
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", ""},
{LRT_SHADOW_FILTER_NONE,
"NONE",
0,
"None",
"Not filtering any lines based on illumination region"},
{LRT_SHADOW_FILTER_ILLUMINATED,
"ILLUMINATED",
0,
"Illuminated",
"Only selecting lines from illuminated regions"},
{LRT_SHADOW_FILTER_SHADED,
"SHADED",
0,
"Shaded",
"Only selecting lines from shaded regions"},
{LRT_SHADOW_FILTER_ILLUMINATED_ENCLOSED_SHAPES,
"ILLUMINATED_ENCLOSED",
0,
"Illuminated (Enclosed Shapes)",
"Selecting lines from lit regions, and make the combination of contour, light contour and "
"shadow lines into enclosed shapes"},
{0, NULL, 0, NULL, NULL},
};
@ -3464,13 +3482,6 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
"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, "use_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);