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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYimingWu <xp8110@outlook.com>2022-05-13 19:55:18 +0300
committerYimingWu <xp8110@outlook.com>2022-05-13 19:56:09 +0300
commit7c9b6cc3802982bfb7a13aed37d4a032d9166fbc (patch)
tree385f5dcd17466730448e1f0593f8dfd45eb129c1 /source/blender/gpencil_modifiers/intern
parentee363ee7b3a26e3236f2107b8a8324877404db04 (diff)
LineArt: Better behavior of smooth tolerance.
This fixes the smooth tolerance feature in master where sometimes you could get over simplified chains and lose the shape it's supposed to be originally. Reviewed By: Sebastian Parborg (zeddb) Differential Revision: https://developer.blender.org/D14929
Diffstat (limited to 'source/blender/gpencil_modifiers/intern')
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c78
1 files changed, 59 insertions, 19 deletions
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
index b666eb677eb..d7b370ef5e5 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
@@ -971,27 +971,67 @@ void MOD_lineart_chain_clear_picked_flag(LineartCache *lc)
void MOD_lineart_smooth_chains(LineartRenderBuffer *rb, float tolerance)
{
LISTBASE_FOREACH (LineartEdgeChain *, ec, &rb->chains) {
- LineartEdgeChainItem *next_eci;
- for (LineartEdgeChainItem *eci = ec->chain.first; eci; eci = next_eci) {
- next_eci = eci->next;
- LineartEdgeChainItem *eci2, *eci3, *eci4;
-
- /* Not enough point to do simplify. */
- if ((!(eci2 = eci->next)) || (!(eci3 = eci2->next))) {
- continue;
- }
-
- /* No need to care for different line types/occlusion and so on, because at this stage they
- * are all the same within a chain. */
-
- /* If p3 is within the p1-p2 segment of a width of "tolerance". */
- if (dist_to_line_segment_v2(eci3->pos, eci->pos, eci2->pos) < tolerance) {
- /* And if p4 is on the extension of p1-p2 , we remove p3. */
- if ((eci4 = eci3->next) && (dist_to_line_v2(eci4->pos, eci->pos, eci2->pos) < tolerance)) {
- BLI_remlink(&ec->chain, eci3);
- next_eci = eci;
+ /* Go through the chain two times, once from each direction. */
+ for (int times = 0; times < 2; times++) {
+ for (LineartEdgeChainItem *eci = ec->chain.first, *next_eci = eci->next; eci;
+ eci = next_eci) {
+ LineartEdgeChainItem *eci2, *eci3, *eci4;
+
+ if ((!(eci2 = eci->next)) || (!(eci3 = eci2->next))) {
+ /* Not enough points to simplify. */
+ next_eci = eci->next;
+ continue;
}
+ /* No need to care for different line types/occlusion and so on, because at this stage they
+ * are all the same within a chain.
+ *
+ * We need to simplify a chain from this:
+ * 1-----------2
+ * 3-----------4
+ * to this:
+ * 1-----------2--_
+ * `--4 */
+
+ /* If p3 is within the p1-p2 segment of a width of "tolerance", in other words, p3 is
+ * approximately on the segment of p1-p2. */
+ if (dist_to_line_segment_v2(eci3->pos, eci->pos, eci2->pos) < tolerance) {
+ float vec2[2], vec3[2], v2n[2], ratio, len2;
+ sub_v2_v2v2(vec2, eci2->pos, eci->pos);
+ sub_v2_v2v2(vec3, eci3->pos, eci->pos);
+ normalize_v2_v2(v2n, vec2);
+ ratio = dot_v2v2(v2n, vec3);
+ len2 = len_v2(vec2);
+ /* Because this smoothing applies on geometries of different scales in the same scene,
+ * some small scale features (e.g. the "tails" on the inner ring of a torus geometry)
+ * could be completely erased if the tolerance value is set for accomondating the entire
+ * scene. Those situations typically result in (ratio << 0), looks like this:
+ * 1---2
+ * 3-------------------------------4
+ * (this sort of long zig zag obviously are "features" that can't be erased)
+ * setting a ratio of -10 turned out to be a reasonabe threshold in tests. */
+ if (ratio < len2 && ratio > -len2 * 10) {
+ /* We only remove p3 if p4 is on the extension of p1->p2. */
+ if ((eci4 = eci3->next) &&
+ (dist_to_line_v2(eci4->pos, eci->pos, eci2->pos) < tolerance)) {
+ BLI_remlink(&ec->chain, eci3);
+ next_eci = eci;
+ continue;
+ }
+ if (!eci4) {
+ /* See if the last segment's direction is reversed, if so remove that.
+ * Basically we don't need to preserve p3 if the entire chain looked like this:
+ * ...----1----3===2 */
+ if (len_v2(vec2) > len_v2(vec3)) {
+ BLI_remlink(&ec->chain, eci3);
+ }
+ next_eci = NULL;
+ continue;
+ }
+ }
+ }
+ next_eci = eci->next;
}
+ BLI_listbase_reverse(&ec->chain);
}
}
}