Page MenuHome

Geometry Nodes: Add Easing Function Node
AbandonedPublic

Authored by Charlie Jolly (charlie) on Jul 27 2021, 1:13 AM.
Tokens
"Love" token, awarded by Alumx."Love" token, awarded by hitrpr."Love" token, awarded by AndyCuccaro."Love" token, awarded by monio."Pterodactyl" token, awarded by EAW."Like" token, awarded by asmitty."Party Time" token, awarded by Bit."Love" token, awarded by Branskugel."Love" token, awarded by HEYPictures."Like" token, awarded by GeorgiaPacific.

Details

Summary

This node adds easing functions as a new function node.

Originally the patch used the BLI_easing.h functions.
These have been reimplemented so they are less complicated and use a [0,1] unit domain.
Additional easing functions have also been added to allow finer control.

Diff Detail

Repository
rB Blender
Branch
master
Build Status
Buildable 19579
Build 19579: arc lint + arc unit

Event Timeline

There are a very large number of changes, so older changes are hidden. Show Older Changes

Generally I'm fine with this node, but I think we shouldn't prioritize merging it for 3.0. Maybe afterwards.
The input socket name "Time" seems a bit odd.

Generally I'm fine with this node, but I think we shouldn't prioritize merging it for 3.0. Maybe afterwards.
The input socket name "Time" seems a bit odd.

Yes, the variable names may need some generalisation.

Time = Value
Begin = Start
Change = End
Duration, Amplitude, Period and Overshoot remain as they are.

Rebase and change socket names so they are more generalised.

Time = Value
Begin = Start
Change = End
Duration, Amplitude, Period and Overshoot remain as they are.

Hans Goudey (HooglyBoogly) requested changes to this revision.Oct 29 2021, 6:53 PM

Duration is the only name that doesn't seem to fit anymore. If I understand its purpose correctly, maybe Range would fit a bit more?

source/blender/functions/FN_multi_function_builder.hh
344 ↗(On Diff #44085)

I'd be curious what Jacques thinks about adding these huge templates, probably it's fine-- definitely makes the other code easier to read.

One thing to node is that it isn't possible to use VArray_Span for inputs that are expected to not be single values here.

source/blender/nodes/function/nodes/node_fn_easing.cc
275

Here the easing function already does the 0 check. Maybe that's the case elsewhere.

This revision now requires changes to proceed.Oct 29 2021, 6:53 PM
Charlie Jolly (charlie) marked 2 inline comments as done.

Rebase to master. Change Duration to Range. Reply to comments.

source/blender/functions/FN_multi_function_builder.hh
344 ↗(On Diff #44085)

I'm a bit confused by the VArray_Span comment. This is the same template as CustomMF_SI_SI_SI_SO used elsewhere etc

source/blender/nodes/function/nodes/node_fn_easing.cc
275

If does a check on time not duration. The duration check is used to avoid division by zero.

source/blender/functions/FN_multi_function_builder.hh
344 ↗(On Diff #44085)

Since VArray access is slower than access from Span, we can use VArray_Span to ensure that an input value is retrieved from a span, at the cost of an allocation and a materialize step when it isn't. For example, we might guess that the "Value" input will most often be a different value on every element, so accessing it with Span is probably worthwhile.

The CustomMF_SI_SO did that optimization automatically, because they just had two inputs. But here, there are way too many inputs to do that without exploding the code size.

Currently this is a more theoretical issue, but it does highlight that we lose some contextual information by using these templates. I'm curious about @Jacques Lucke (JacquesLucke)'s opinion though.

source/blender/nodes/function/nodes/node_fn_easing.cc
275

Oops, sorry, my bad.

source/blender/functions/FN_multi_function_builder.hh
344 ↗(On Diff #44085)

Think I'd rather not add even larger templates here. May be better to think about how we can reduce the overhead for defining a custom multi-function in some cases.
I think it's fine if this does not optimize for different possible data layouts for now. It's nice to be able to add these kinds of optimizations separately afterwards. That also makes measuring the performance impact easier for everyone if the optimization is submitted as a separate patch.

I think what Jacques meant in the inline comment is that we should avoid adding these large templates to FN_multi_function_builder.hh

I think either templating the operation function or using a larger function with the direction and operations as inputs would be the way to go.

I think what Jacques meant in the inline comment is that we should avoid adding these large templates to FN_multi_function_builder.hh

I think either templating the operation function or using a larger function with the direction and operations as inputs would be the way to go.

Lol, I read it as a response to your comment and he was fine with it as it is and look at this in the future. I'll take another look.

Charlie Jolly (charlie) marked 3 inline comments as done.Nov 16 2021, 6:47 PM

Use static Easing MF functions instead of Custom MF templates.

Hans Goudey (HooglyBoogly) requested changes to this revision.Nov 16 2021, 10:51 PM
  • The code looks good to me at this point.
  • The enum items for the direction property are missing descriptions.
  • Using this, I sort of expected range to be right after value, since those are the two inputs that describe the function's domain. What do you think about that?
  • I think the node's inputs should have descriptions, otherwise it's not obvious for someone unfamiliar with the functions.
This revision now requires changes to proceed.Nov 16 2021, 10:51 PM
Charlie Jolly (charlie) updated this revision to Diff 44852.EditedNov 17 2021, 12:59 AM

Add descriptions to direction In, Out, In-Out.

Naming is still a little ambiguous.

See diagram:

Charlie Jolly (charlie) edited the summary of this revision. (Show Details)Nov 17 2021, 1:22 AM

If only the creator of these functions had written a book, and within that book had written a chapter that covered said functions, and made that chapter freely available on his website. That sure could clear up what the input variables represent.

Oh wait, he did!

http://robertpenner.com/easing/penner_chapter7_tweening.pdf

source/blender/nodes/function/nodes/node_fn_easing.cc
30

Change = End - Start = Y₂ - Y₁ = ΔY
You can't just change the name of the socket from ΔY to Y₂, without adding a conversion function Change = End - Start to feed into the functions in BLI_easing.h 😉

Charlie Jolly (charlie) marked an inline comment as done.Nov 18 2021, 1:49 PM

@Evan Wilson (EAW) The variable name changes are suggested and implemented as part of the code review. Easing is also a type of interpolation so can be represented using non-time based names. I'm not strongly opinionated on this.

source/blender/nodes/function/nodes/node_fn_easing.cc
30

This comment is there to provide an understanding how the socket names map to the easing function names.

Charlie Jolly (charlie) updated this revision to Diff 44917.EditedNov 18 2021, 3:32 PM
Charlie Jolly (charlie) marked an inline comment as done.

Rebase to master after socket availability changes.
Add Clamp socket with default value of true. This clamps when the value falls outside the range of the easing.
Add some socket descriptions.

Charlie Jolly (charlie) edited the summary of this revision. (Show Details)Nov 18 2021, 3:36 PM
Charlie Jolly (charlie) edited the summary of this revision. (Show Details)Nov 18 2021, 3:39 PM
Charlie Jolly (charlie) edited the summary of this revision. (Show Details)
Charlie Jolly (charlie) updated this revision to Diff 44925.EditedNov 18 2021, 5:39 PM

@Evan Wilson (EAW) as per comment, change is now computed from End - Start. This makes current naming more coherent too.

No more changes planned.

source/blender/nodes/function/nodes/node_fn_easing.cc
30

Use Change = End - Start

I haven't posted this as a revision but this uses a function to get the easing function used in the loop to reduce boiler plate code. P2602

Rebase to master.
Add new function names.
Add gather_link_search_ops.

Use make_available declaration instead of gather_link_search_ops

We discussed this in the latest geometry nodes sub-module meeting. Here are the notes from that:

  • The inputs and functionality are very similar to the map range node.
  • Conceptually the node feels different though, and there are also in and out options, which probably makes it worth adding.
  • The clamp option could be named differently, since it clamps the input rather than the output.
  • Or the clamp option can be removed, because there doesn't seem to be a strong use case for it and the behavior seems expected.
  • There could be more settings for the sinusoidal modes:

The idea with the last comment is that we should take advantage of the more specific behavior of this node and expose more settings where it makes sense.


For the code, I think rather than using a function pointer variable, it might make more sense to add a function that applies the operation with the function as a template parameter. I don't think the compiler will optimize this code using function pointers as well.

Charlie Jolly (charlie) updated this revision to Diff 46950.EditedJan 12 2022, 5:35 AM

Remove function pointer.
Remove Clamp socket.
Reworked and removed use of BLI_easing.h and ported the functions locally. Now, instead of three functions for each direction, this is now generalised to one function per operation. These all work in a [0-1] domain.
Add Out-In direction in addition to In, Out and In-Out.
Add Mirror socket, this mirrors the easing to allow creation of pulse curves.
Add Power and Slope functions for adjustable curves.
I did try adding the option for adjustable bounces but removed it as it was not working as expected.

Charlie Jolly (charlie) updated this revision to Diff 46979.EditedJan 12 2022, 2:16 PM

@Simon Thommes (simonthommes) if you have some time to test this would be great. The patch has gone through a fair amount of changes and it would be good to have some artist feedback.

This is a big node, so I have a couple of remarks:

  • I'm not sure how useful the Mirror input is. It kind of undermines the behaviour of easing from a start value to an end value. The same behaviour can be achieved by mirroring the input. I can't really think of a good application other than the pulse curves you mentioned and to me that alone is not a strong enough argument to include it.
  • When testing this node, it becomes really apparent to me how crucial the visualization is using the example file. Considering that this is something the user will not have available in practice, it is worth considering how this kind of thing could be visualized. As an example there is the interpolation viewer in animation nodes. Just throwing it out there.
  • The behaviour of the power interpolation looks a bit wrong to me. It looks to me like what is Out with exponent=x should be In with exponent=1/x.
  • For Slope, it would feel more natural to me if the behaviour of In and Out would be swapped (Offset inverted).
  • For Bounce being able to adjust the number of bounces seems quite useful to me, so it would be nice if you could get that to work before the merge.
  • In the same sense, I think an Oscillations input would control more intuitively than a period for the Elastic case. I had some trouble what exactly the amplitude is doing, but I think in general it's fine. It just just have a lower soft limit of 1, as it doesn't change anything below that. The dampening shape is something that could also be controlled additionally (Same for Bounce), but I think the natural falloff that it has now is fine.
  • The naming of the inputs gives me some issues. In my opinion Start, End and Range aren't very clear at all. Any one of them could be either regarding the input or the output. However I don't have a perfect answer to how they should be called. I would even bring into question what set of input parameters should be defined here. I do think that if we already expose all this functionality, rather than leaving the mapping to external map range node (which I'm fine with), then we should give the same functionality as the map range node has. That would mean an additional parameter to define the From Min/Max.

    We can also say that we don't expose all the parameters, but if we define the From Min to always be 0 there is no good reason to expose the From Max as a range imo. The node can both ease in and out, so in and out parameters can be viewed on the same importance level as being symmetrical. So either we expose both or none. I could see the option to only expose the To Min/Max values as inputs and defining From Min/Max as 0 and 1.

    As we already use In/Out for the Easing Types, I think using the same language to describe the mapping can make sense. So To Min/Max (Start/End currently) could be called Value In/Out. As for the From Min/Max inputs I think that the language of Start/End seems much more appropriate here, as in many cases an interpolation with easing is associated with time. Again, for these I think we should have either both or none, but that could go either way for me.

@Simon Thommes (simonthommes) thanks for the feedback

What do you think about these changes....

  • Remove Range and End... this node then operates solely in the [0-1] range with just a Value input. This reduces the ambiguity and simplifies the node.
  • Keep Mirror and rename it to Loop. This name fits better and is great for motion design.
  • IN, OUT is accepted terminology for Easing but when you have adjustable curves it doesn't fit so well. Perhaps remove IN,OUT from some of the adjustable curves. I think this should keep the naming as it is used in IPO curves and is commonly used elsewhere for animation.

This would fit in well with the existing toolset.

  • Map Range for mapping values
  • Curves for fine visual control
  • Mix Node (hopefully) for basic interpolation
  • RGB Node for blending values

I will look into the suggestions for Bounces and Elastic again.

  • Remove Range and End... this node then operates solely in the [0-1] range with just a Value input. This reduces the ambiguity and simplifies the node.

I assume then you mean Range, End and Start?
Leaving out the mapping for both the input and the output of this node would mean a lot of overhead for the mapping (2 additional map range nodes).
I do see a benefit and strong connection to the functionality of the node in exposing from and to what value to ease. In what input range that happens can be [0,1] imo.
Here the naming of start and end implies a time connection imo. I would propose in connection with the easing types something along Value In/Out or Level In/Out.

  • Keep Mirror and rename it to Loop. This name fits better and is great for motion design.

For me a loop implies periodicity. With the current behaviour, I think the name mirror is fine. I don't have a strong opinion on whether or not to include this input.

  • IN, OUT is accepted terminology for Easing but when you have adjustable curves it doesn't fit so well. Perhaps remove IN,OUT from some of the adjustable curves. I think this should keep the naming as it is used in IPO curves and is commonly used elsewhere for animation.

I wasn't proposing to change the In/Out terms. You are right, on some curves the changing between these doesn't make a lot of sense. But for consistency I wouldn't be oppposed to keep the options nonetheless.

  • Remove Range and End... this node then operates solely in the [0-1] range with just a Value input. This reduces the ambiguity and simplifies the node.

I assume then you mean Range, End and Start?
Leaving out the mapping for both the input and the output of this node would mean a lot of overhead for the mapping (2 additional map range nodes).
I do see a benefit and strong connection to the functionality of the node in exposing from and to what value to ease. In what input range that happens can be [0,1] imo.
Here the naming of start and end implies a time connection imo. I would propose in connection with the easing types something along Value In/Out or Level In/Out.

For Map Range behaviour, I'm thinking this would just plug into the factor/value input. This node would then become a factor control rather than another map range node. In the same way, this could also drive the Factor of a Mix node.

E.g.

Easing > Map Range value input
Easing > Mix Node factor input

I will look at the visualisation. Agree this is important for the dynamic effects.

Charlie Jolly (charlie) updated this revision to Diff 47186.EditedJan 18 2022, 4:39 AM

Add easing dynamic bounce based on Animation Nodes for testing.

I feel bad for having an inconsistent opinion here, but I'm finding myself less convinced this is worth adding as a native C++ implementation at this point.
When it used existing functions there wasn't much of a cost to it, but at this point the patch adds a lot of new code that will need to be maintained.

Implementing this as a node group and shipping it in an asset bundle (T95445, T91843) seems like a preferable option to me at this point, for a few reasons:

  • Less code to maintain
  • Less code to review (just weighing priorities, I'm not sure I'll have to time to review this code for a bit)
  • Much better performance, because we can focus on making the smaller builtin nodes faster with SIMD, LLVM compilation, and GPU calculation. (Doing all that manually in this node would be much harder).
  • The design can be more easily changed, and is generally less binding.

The biggest blocker is the lack of enum sockets now. But that should be worked on anyway, since it will help in other areas.

I feel bad for having an inconsistent opinion here, but I'm finding myself less convinced this is worth adding as a native C++ implementation at this point.
When it used existing functions there wasn't much of a cost to it, but at this point the patch adds a lot of new code that will need to be maintained.

This is an interesting case because the node was pretty close to being accepted and after getting Simon to review it, it kind of muddied the water a bit. As a result I did add a simplified version of the patch here: D13884: Geometry Nodes: Add Easing Function Node (WIP)

Implementing this as a node group and shipping it in an asset bundle (T95445, T91843) seems like a preferable option to me at this point, for a few reasons:

  • Less code to maintain
  • Less code to review (just weighing priorities, I'm not sure I'll have to time to review this code for a bit)
  • Much better performance, because we can focus on making the smaller builtin nodes faster with SIMD, LLVM compilation, and GPU calculation. (Doing all that manually in this node would be much harder).
  • The design can be more easily changed, and is generally less binding.

I'd consider easing functions a core node. If they are implemented as an asset bundle, I'm not sure that is less work for maintainability and review.

The biggest blocker is the lack of enum sockets now. But that should be worked on anyway, since it will help in other areas.