Page MenuHome

GPencil: Curvature support for length modifier
ClosedPublic

Authored by Henrik Dick (weasel) on Jun 22 2021, 11:34 AM.

Details

Summary

Extend the stroke following an approximated circluar/helical curve.

This can be used as an effect for lineart or on its own as helix generator.

The UI looks like this:

This is the testcase for how it should work:


In this file the circle should stay exactly as is while the overshoot factor gets changed during the animation.
You can also dissolve single vertices of the circle and the result should stay the same.

For Line Art examples look at some of the comments in this patch.
This is an example of what can be done with it as helix generator: (using the default cube)


Diff Detail

Repository
rB Blender

Event Timeline

There are a very large number of changes, so older changes are hidden. Show Older Changes
  • cleanup memory allocation and fix read of freed memory

Now there is probably only minor stuff left to change before landing, no more critical stuff afaict.

Hans Goudey (HooglyBoogly) requested changes to this revision.Aug 23 2021, 8:35 PM
Hans Goudey (HooglyBoogly) added inline comments.
source/blender/blenkernel/intern/gpencil_geom.cc
554 ↗(On Diff #40992)

Declare variables where their values are assigned, i.e. bGPDspoint *new_pt = (bGPDspoint *)MEM_callocN(sizeof(bGPDspoint) * new_count, "gp_stroke_points_extra");

A few smaller things here (a bit pickier):

  • Use __func__ instead of manually deciding a name for the allocation.
  • The variable name should be plural, since this is an array and not a single point-- new_pts
689–723 ↗(On Diff #40992)

Many of these variables can be declared const.

700–731 ↗(On Diff #40992)

These three comments are quite vague-- in their current form they're a bit more confusing than helpful honestly.
On the other hand, it's nice to describe these things in comments, since they're not obvious, so I think more detail should be added.

source/blender/gpencil_modifiers/intern/MOD_gpencillength.c
83–85

Use const arguments.

198–202

These can be a new subpanel, with the checkbox in the header.

source/blender/makesrna/intern/rna_gpencil_modifier.c
117–121

Why is the order changed here? Also, probably best to add a TODO comment for the icon like the line art modifier.

3240

of extended stroke -> of the stroke's extension

3248

Points density -> Point density

This revision now requires changes to proceed.Aug 23 2021, 8:35 PM
Henrik Dick (weasel) marked 8 inline comments as done.
  • requested changes
source/blender/makesrna/intern/rna_gpencil_modifier.c
117–121

Moved because it is now a generate modifier, not only deform like before.

source/blender/makesrna/intern/rna_gpencil_modifier.c
71

I don't think we must move this to generate section. The length looks more a transformation of the geometry mor ethan a generation.

What do you think @Matias Mendiola (mendio) ?

The UI looks good now.

gpencil_geom.cc is a C++ file, so it can use types like float3, which can make the math much more readable. That's not blocking here though, just something to note for the future.


I was thinking it might be worth extracting the logic for curved extrapolation of a stroke/poly spline here so that it could be used for curves as well. (I'd like there to be a "Curve Extrapolate" node as well as the current "Curve Trim").
That would be nice here also, to separate the grease pencil specific stuff from the extrapolation logic. Just noting that for no particular reason though, carry on!

source/blender/blenkernel/BKE_gpencil_geom.h
114–116

It looks like there is no need to expose this function. Best to keep it static I think.

source/blender/gpencil_modifiers/intern/MOD_gpencillength.c
217

You can use IFACE_("Curvature") since "use" is redundant when the button is a checkbox.

source/blender/makesrna/intern/rna_gpencil_modifier.c
117–121

Ah, I missed that. Thanks.

source/blender/makesrna/intern/rna_gpencil_modifier.c
71

As far as I know, the sections have specific meanings though-- "Generate" modifiers can alter the topology (add/remove points or strokes), as this one does. Deform modifiers should never alter the topology.

source/blender/makesrna/intern/rna_gpencil_modifier.c
71

I think if the modifier adds geometry (extra points to the strokes) it is fine to move to the Generate column. It is not just a deformation of the existing geometry

source/blender/makesrna/intern/rna_gpencil_modifier.c
71

If it's ok for you, then it's ok for me ;-)

  • change name of subpanel header
  • make extra points function static

Do we need "angle increment" support? (Increase/decrease rotation for each segment)

If so I can code it but the matrix generation has to be inside the loop.

@Henrik Dick (weasel) Hello... This code crashes when gps->totpoints == 2, I suggest always create new points when curvature is turned on, otherwise the second call will have incorrect vert count. However when I removed the vert count check it still crashes with curvature off. You are most familiar with the new code path, so maybe you could give a hand. Thanks!

  • fix nan

Thanks for testing!
There was a nan sneaking into overshoot_fac by the division
I had in the modifier file.
My solution was to just use a default value if the input is nan,
since crashing is never good, so it needs to be handled even if
it never occurs.

Great! it doesn't crash now, but after some testing I found two weird problems:

  • The stretched part should probably be closing to a straight line if the overshoot value is closing to zero, but it's not the case with this test file. Maybe we still need to interpolate actual sampling position instead of using closest points? (Disable that sample modifier to get a clearer idea)
  • Stretched parts sometimes disappear, adjust sample value in the modifier above it to see the effect.

very nice modifier :)!
tested with my room scene, now it is stable.


@Henrik Dick (weasel), any chance of adding vertex group support?

Because with it, we could apply the effect to only part of the scene, this example is from vertex weight + offset randomize. With this, the fallof would look great, we could make part of the scene look like something is organically growing out if it :)

@YimingWu (NicksBest) I debugged your problems and here is what I gathered:

  1. The extention does not go flat in case that overshoot_fac is close to zero.. This is because of how the math works now. It looks at angles at the points and then interpolates. At the first point interpolation does not change the measured curvature. I would need to hack it in to make the extensions go flat with the factor close to zero, but I doubt that would be good since the factor is relative to the point number of the curve, so this interpolation to zero would kick in at different values for every stroke.
  2. The lines disappearing comes from duplicate vertices. I don't know why the sample modifier creates perfect duplicate verts, but they cause problems here. I could handle them, but the simpler workaround it to use an adaptive simplify modifier before the length modifier.

btw what do you think about the Overshoot Factor beeing relative to the number of points instead of relative to the line length? Can you (or someone) present an example file where there is a reallife benefit from either one (point relative vs. length relative)?

@Aleš Jelovčan (frogstomp) great to hear! I can add vertex groups support in the future. Next up is a patch to add "Curvature Gradient" or "Spiral Factor" or something along those lines, which will make your organic spirals.

Henrik Dick (weasel) edited the summary of this revision. (Show Details)Sep 4 2021, 5:31 PM

Hi @Henrik Dick (weasel)

About overshoot length: In my implementation the overshoot value is a ratio of stroke total length, this has a benefit of scaling the stroke doesn't change the appearance. Otherwise the curve will move around.

For flat extension: Manly because (especially) in line art there will be a lot of straight lines that doesn't have many points on each stroke, so the extension in such condition should stay flat so it's consistent with the rest of the scene. Using overshoot value related to stroke total length should also solve this problem (as long as you actually interpolate and find out the exact position of that 2 other sample points on the stroke), and adjusting overshoot will then produce continuous result as well.

Apparently these are obviously not right... no matter how big or small the overshoot value is, this method does not handle "hard lines" very well.

Even after I add a simplify->sample modifier before, it's still acting weird (and because of the sample operation, the modifier stack runs very slow as a side effect):

I only had a GIF to represent the old behaviour at the moment:

IMO the 3 point sample & interpolating internally is still more robust, while the code is looking a bit convoluted, but it is there to handle edge cases like long straight segments and strokes with very few points. And also after @Henrik Dick (weasel) 's algorithm fix the original code performs pretty well now.

Here's the file if you want to take a look:

What do you think @Sebastian Parborg (zeddb) ?

The sampled method is more robust especially when stroke quality is unknown for situations like line art. It uses the last segment's tangent as twist starting point, so existing usages with twisting needs tweaking, but for applying on line art, it's easier to get a nice effect. Maybe we could have two algorithms for the user to choose from?

YimingWu (NicksBest) commandeered this revision.EditedSep 11 2021, 7:00 AM
YimingWu (NicksBest) updated this revision to Diff 41688.
  • Wrong angle step fixed.
  • Always use relative overshoot value.
  • Added twist toggle switch.
  • add segment weight option
  • add max angle option
  • fix some numerical instabilities and edge cases
  • improve Start/End UI

@Henrik Dick (weasel) , @YimingWu (NicksBest), tested again, wooow! What an improvement!

I could not reproduce issues with twitching on the files where I was getting it before. Seems stable, animating parameters is smooth and additional parameters allow for much greater control.

I think ultimately we go with @Henrik Dick (weasel) 's patch. Works quite nicely with my models as well.

Let's see if there's more stuff @Hans Goudey (HooglyBoogly) has to say.

Hans Goudey (HooglyBoogly) requested changes to this revision.Sep 14 2021, 11:57 PM
  • Is the screenshot in the patch description up to date?
  • Property descriptions should not end with periods, that is added automatically
  • I noted a few places where I think the descriptions are too vague. I'm happy to help figure out wording, but I'm not sure what they do right now.
source/blender/makesrna/intern/rna_gpencil_modifier.c
3261

Does "Density" mean the number of points per meter or something else? It should probably say here

3269

This leaves me wondering, "weight use for what?"

3274

I'm also not sure what this property does after reading the description. Maybe it could expand on its purpose briefly?

This revision now requires changes to proceed.Sep 14 2021, 11:57 PM
  • requested changes to naming and tooltips
Henrik Dick (weasel) edited the summary of this revision. (Show Details)Sep 16 2021, 6:44 PM
Hans Goudey (HooglyBoogly) added inline comments.
source/blender/makesrna/intern/rna_gpencil_modifier.c
3320

Follow *the* curvature of the stroke

3344

Periods are added automatically by the tooltip system, no need to add them here.

I accepted based on the UI and naming changes. For the records, I haven't tested the patch at all.

Henrik Dick (weasel) marked 2 inline comments as done.
  • remove effect applied on cyclic strokes
  • requested minor changes

I just fixed a small thing here:

if ((gps->flag & GP_STROKE_CYCLIC) != 0) {
  /* Don't affect cyclic strokes as they have no start/end. */
  continue; /* should be return */
}

Function wise it all looks good now. :D Thanks for the improvements

YimingWu (NicksBest) commandeered this revision.Sep 19 2021, 7:33 AM
YimingWu (NicksBest) updated this revision to Diff 42039.

Fixed the continue case.

Besides my comments, I want to rename "overshoot" as well.
Basically because I think overshoot is not describing what it happening.

Note that the overshoot description also now implies it is only used for curvature, but this is not the case.

Overshoot implies that you have a calculated direction/angle but then "overshoot" this goal with a certain amount.

What is actually happening is that we:

a) In the non curvature case we change the point of the curve we calculate the direction from.
(Higher values makes us go further along the curve from the start/end positions when we calculate a vector that points at our start/end point for the extension direction)

b) In the curvature case we take more points into account when calculating the final curvature value.

Neither of these I think is some kind of overshoot. Instead this is a normalized length value.
IE 1.0f means we should traverse the whole curve. 0.0f means that we should only look at data in the very near vicinity of our start/end points.

To me this is some kind of normalized range or "window" where we estimate the mean curvature/derivative.

I have the same issue with "smoothness".
It seems to me that it doesn't really smooth it but weights the angles depending on the length of the edge it was calculated from?
So a value of 1.0f means that smaller edges of the curve will have much less influence than the longer edges.
And a value of 0.0f means that all calculated angles have the same influence regardless of the edge length.

Of course I know naming is extremely hard, but I hope we can come up with something better with some more discussion.

source/blender/blenkernel/intern/gpencil_geom.cc
612 ↗(On Diff #42052)

I don't really like the name edge_point_tradeoff or point_edge_tradeoff
Especially since it is called something else in the UI (smoothness)

If nothing else, I think these variables should be renamed to at least be quite similar to the name in the UI.

625 ↗(On Diff #42052)

I think you should elaborate on this comment.

Now it seems a bit weird?

Like:

if (x != inf)
  // If u == 2, then x can be what ever!
  x = 2.0f

IE you state something, but the scenario described in the comment will seemingly never happen.

679 ↗(On Diff #42052)

I think this should be more like:

/* The (fractional) amount of points we will query when calculating the average curvature of the strokes */

Does that sound good to you?

740 ↗(On Diff #42052)

This comment seems to need to cleanup?

For example I don't really understand what weights introduced point_edge_tradeoff the calculation is trying to say.
I'm guessing some words are missing here.

Henrik Dick (weasel) marked 3 inline comments as done.
  • requested naming changes

I didn't change overshoot_factor internally because that would need versioning. Maybe @YimingWu (NicksBest) can do that in a separate commit.

This revision is now accepted and ready to land.Sep 21 2021, 4:20 PM