KairosResearchLab / Kairos

A complete framework for data control and composition in the vvvv visual programming environment.
Other
128 stars 6 forks source link

Bezier Interpolation styles #245

Open gregsn opened 1 year ago

gregsn commented 1 year ago

We have 4 different ideas for Bezier Interpolation. Can we pick one or shall we allow all 4 different styles?

grafik

Independently of this we have the question whether we operate on data directly or just in normalized sampling space. see #244

natan-sinigaglia commented 1 year ago

my two cents:

First question: How do we want to work?

image

both options make sense.

Option 1 - "Value Bezier"

image

It's interesting to notice that in kairos both these last options could make sense, depending on the scenario. example: First keyframe: Constant Value Keyframe Second keyframe: Live Value Keyframe

image

both control options are interesting!

in the case of the control points being offsets, one could argue: "how the hell I'm supposed to edit (grab and move around) C3 if it's an offset over an unpredictable value that potentially moves every frame? It would be a videogame, just to grab it!"

we could easily solve this by imagining an edit mode in which C4 (which is unpredictable) gets temporarily replaced by a dummy keyframe where the codomain value is fixed at the center of the track, just to allow us "design" the offset from it.

image

Option 2 - "Transition Brezier"

image

This option doesn't seem to be problematic,: it would offer always the same editing possibilities, independently from the "kind" of keyframes we are dealing with, since this curve is not affected by the keyframes (potentially dynamic) value, only being a representation of the transition behavior, the scalar of the lerp function.

Value Types considerations

Given these two bezier "styles", let's pass to analyze how they could be implemented and edited in each value type.

We already covered the Float32 case scenario.

what happens with Vectors? being vectors an abstraction over a collection of values (eg. Vector3 = X value + Y value + Z value), I think the user would expect to be able to adjust the bezier curves potentially for each component of the vector.

the same is true for RGBA. In this case there's another level of complexity given by the fact that an RGBA value can be interpreted as a Vector4 but with different meanings: is it RGBA or HSV or HSL or... each color space introduces a new interpretation of the RGBA value. the user might want to operate in one specific color space.

Other exotic types (like String, matrix, or even skia layer or stride entity) can't properly be used to draw a 2d bezier curve, so would exclude Option 1. you would be only allowed to design the transition curve (Option 2).

gregsn commented 1 year ago

Great! Let's look at the possible implementations of each variant:

Restricted Value Bezier

Free Value Bezier

Transition Bezier

here the two-step idea #244 would be great. It would allows us to compute the Lerp Scalar once. The restricted variant would be the fastest, but also the free Transition Bezier only needs to call into InverseDomainBezier(t) and CoDomainBezier(w) only once.

It's the most versatile. It would work for spreads or even for many tracks. One curve for many tracks would be awesome...

Opinion

To me, it still sounds like the Free Value Bezier is the most wanted candidate, even if it might be the most complicated and potentially slowest one. Maybe we should go for Option A and abstract everything away behind an adaptive node FreeValueBezier(t, cp1, cp2, cp3, cp4) -> v which is responsible to do everything. So per type we need to offer the implementations. The implementations shall be able to delegate the hard tasks to helper nodes InverseDomainBezier(t, t1, t2, t3, t4) -> w (..) which they can use per component. Abstracting it this way via adaptive operation doesn't allow the implementations to keep state around, but maybe let's do the non-optimized yet most flexible approach first (no caching, no binary search, just solving the cubic formula each time) as this approach also works for live value keyframes.

gregsn commented 1 year ago

Uhm. I think I got the last part wrong. For a Vector3 there is not such a thing as a CP2 of type Vector3. We have 3 CP2 with each (x,y). That's 6 values.

Maybe we should think about having at least t restricted for all the components. CP2 =(t2,(x2,y2,z2)) This way we could compute w once for the whole type and implementing per type wouldn't be necessary at all (as we have adaptive Bezer already).

For the UI this would mean: You can move around all your controlpoints freely, but when moving (t2, y2) in time direction you also move (t2, z2), since there is only one t2.