Animation: Butterworth Smoothing filter #106952
No reviewers
Labels
No Label
Interest
Alembic
Interest
Animation & Rigging
Interest
Asset System
Interest
Audio
Interest
Automated Testing
Interest
Blender Asset Bundle
Interest
BlendFile
Interest
Code Documentation
Interest
Collada
Interest
Compatibility
Interest
Compositing
Interest
Core
Interest
Cycles
Interest
Dependency Graph
Interest
Development Management
Interest
EEVEE
Interest
FBX
Interest
Freestyle
Interest
Geometry Nodes
Interest
glTF
Interest
Grease Pencil
Interest
ID Management
Interest
Images & Movies
Interest
Import Export
Interest
Line Art
Interest
Masking
Interest
Metal
Interest
Modeling
Interest
Modifiers
Interest
Motion Tracking
Interest
Nodes & Physics
Interest
OpenGL
Interest
Overlay
Interest
Overrides
Interest
Performance
Interest
Physics
Interest
Pipeline & IO
Interest
Platforms, Builds & Tests
Interest
Python API
Interest
Render & Cycles
Interest
Render Pipeline
Interest
Sculpt, Paint & Texture
Interest
Text Editor
Interest
Translations
Interest
Triaging
Interest
Undo
Interest
USD
Interest
User Interface
Interest
UV Editing
Interest
VFX & Video
Interest
Video Sequencer
Interest
Viewport & EEVEE
Interest
Virtual Reality
Interest
Vulkan
Interest
Wayland
Interest
Workbench
Interest: X11
Legacy
Asset Browser Project
Legacy
Blender 2.8 Project
Legacy
Milestone 1: Basic, Local Asset Browser
Legacy
OpenGL Error
Meta
Good First Issue
Meta
Papercut
Meta
Retrospective
Meta
Security
Module
Animation & Rigging
Module
Asset System
Module
Core
Module
Development Management
Module
Grease Pencil
Module
Modeling
Module
Nodes & Physics
Module
Pipeline & IO
Module
Platforms, Builds & Tests
Module
Python API
Module
Render & Cycles
Module
Sculpt, Paint & Texture
Module
Triaging
Module
User Interface
Module
VFX & Video
Module
Viewport & EEVEE
Platform
FreeBSD
Platform
Linux
Platform
macOS
Platform
Windows
Severity
High
Severity
Low
Severity
Normal
Severity
Unbreak Now!
Status
Archived
Status
Confirmed
Status
Duplicate
Status
Needs Info from Developers
Status
Needs Information from User
Status
Needs Triage
Status
Resolved
Type
Bug
Type
Design
Type
Known Issue
Type
Patch
Type
Report
Type
To Do
No Milestone
No project
No Assignees
4 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: blender/blender#106952
Loading…
Reference in New Issue
Block a user
No description provided.
Delete Branch "ChrisLend/blender:graph_editor_butterworth"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Implements the butterworth filter (https://en.wikipedia.org/wiki/Butterworth_filter) for smoothing FCurves.
This filter is ideal for smoothing dense data, like motion capture recordings.
It has the advantage of keeping the shape of the curve intact while reducing minimal fluctuations.
The disadvantage is the impulse response has a twang, meaning extreme spikes cause fluctuations to either side. (see picture)
The implementation is based on the GPL code found here: https://exstrom.com/journal/sigproc/dsigproc.html
In order to avoid phase shifting, the filter is run forward and backward, effectively doubling the filter order.
The Redo panel offers the following options
The operator can be called from the Key menu. (Key->Smooth->Butterworth Smooth)
Impulse Response at Filter Order 4 and Cutoff Frequency at half the Nyquist Frequency
Filtered Curve with Ghost Curve as a reference
On a side note, the issue I was having for a long time is that I had these fluctuations at the start and end of the segment. It turns out you need to offset the samples so the first sample is 0.
Video of an impulse Response at Filter Order 4 with Cutoff Frequency 0-1
demo video
@blender-bot package
Package build started. Download here when ready.
@blender-bot package
Package build started. Download here when ready.
@blender-bot package
added modal. That's actually faster to run because the whole undo-redo step is the slow part
Package build started. Download here when ready.
@blender-bot package Windows
Package build started. Download here when ready.
For best results for Blender a default value of FACTOR = 1, samples = 2 and filter order = 3,
but the code for HZ at least the slider value for the user should be mapped to whole numbers int 0-100
instead of float values.
The "slider" could default to the Factor to blend between a good curve smooth and the source data and then an modifier key to change frequency without exiting the slider would be good
@blender-bot package
changed to a frequency cutoff and the slider controls the factor now
also due to the update from main the menu entry is now in key->smooth
Package build started. Download here when ready.
Function works well now from animation/artist testing, the filter does what is expected with some adjustments.
Just need to finalize the slider operator if FACTOR is better than HRZ to have the slider adjust as I would expect the slider to impact what gets smoothed not how much of the source curve is impacted.
And set the defaults to get a good result like 3hz with 16 samples for example and factor of 1
Function of the filter is approved, small tweaks left but the core filter is working on animation curves as I would expect.
@BClark not sure if you want the slider to drive the blend factor or not. Can you clarify that
I am also a bit hesitant to increase the default samples per frame. It really is only meant for subframe data. The result might not match other software 100% but is that a requirement. We don't know their implementation so there might be all sorts of stuff going on under the hood
@blender-bot package
changed back to slider driving the cutoff_frequency, but indirectly via a hidden property "cutoff_factor" in order to fit the 0-1 range that the slider expects.
Package build started. Download here when ready.
@blender-bot package
@BClark added a blend in/out value as discussed yesterday. I defaulted it to 4 because I think it is useful for most cases. Do let me know what you think about that
Package build started. Download here when ready.
Animation user results approved, thanks for the hard work on taming the stat/end drift and improving the usability on a selected range with the improved blending
Nice work!
I found a few smaller things in the code. More importantly, I can't figure out how the modal slider interacts with the redo panel. When I use the slider, it seems to reset to the default parameters, and not use the ones I set in the redo panel. This is what I tried:
@ -389,0 +438,4 @@
}
/**
* \param samples are expected to be centered around the segment with a buffer of size filter_order
* at the left.
filter_order
→bw_coeff->filter_order
, otherwise people will look for afilter_order
parameter.updated the comment in general. Samples no longer need to be centered around the segment
they only need a buffer of filter_order at the left
@ -389,0 +463,4 @@
const float fwd_offset = samples[0];
for (int i = 0; i < sample_count; i++) {
double x = (double)(samples[i] - fwd_offset);
const
@ -389,0 +469,4 @@
}
for (int i = 0; i < filter_order; i++) {
w0[i] = 0.0;
Given that
wN
is calloc'ed, it's already all-zeroes. Is this assignment necessary?yes because is that is after the forward run of the filter.
within the filter they are used as buffer values, and they should all be 0 for the backward run
@ -389,0 +478,4 @@
/* Run the filter backwards as well to remove phase offset. */
for (int i = sample_count - 1; i >= 0; i--) {
double x = (double)(filtered_values[i] - bwd_offset);
const
@ -389,0 +488,4 @@
const float blend_in_y = fcu->bezt[segment->start_index].vec[1][1];
const float blend_out_y = fcu->bezt[segment_end_index - 1].vec[1][1];
for (int i = segment->start_index; i < segment_end_index; i++) {
Maybe add a comment here to explain the higher-level step that's taken here. It looks like it's blending the output of the Butterworth filter with the original keyframes, in a way that's somehow sensitive to the start/end edges. It would be good to have that explained here.
@ -389,0 +506,4 @@
blend_in_out_factor = min_ff((float)(segment_end_index - i - 1) / blend_in_out, 1.0f);
blend_value = blend_out_y;
}
key_y_value = interpf(key_y_value, blend_value, blend_in_out_factor);
This seems to be the only place where
key_y_value
gets a new value. Maybe you could use a 2nd variable here, so that both can beconst
? Maybefiltered_y_value
andblended_y_value
?@ -1210,0 +1251,4 @@
FCurve *fcu = (FCurve *)ale->key_data;
ListBase fcu_segments = find_fcurve_segments(fcu);
LISTBASE_FOREACH (FCurveSegment *, segment, &fcu_segments) {
Can't this use
apply_fcu_segment_function()
?unfortunately not because the parameters for
butterworth_smooth_fcurve_segment
are more complicated@dr.sybren part of the confusion might be that the slider controls a hidden property that in turn drives the cutoff frequency.
@BClark and I decided that it makes more sense for the user to control the cutoff frequency with the slider than the blend factor
That does make things confusing, as it's quite natural for a user to expect that a 0%-100% slider maps to a 0-1 factor.
If the user is indeed controlling the cutoff frequency (which also totally makes sense), shouldn't that be what should be displayed in the slider UI?
I think that 'factor' might also be named too vague. It just means 'multiplier', which doesn't say much.
How about this?
That was my thought as well... the value we change (cutoff) should be first in the list not factor to indicate it is what we are adjusting first.
Since we just worked on "blend with rest pose" Factor is a blending with/to source fcurve, maybe we can use some of the same kind of language. Blend factor ?
I've had a look at driving the cutoff frequency directly with the slider
I remembered why I didn't do it:
The slider displays the value 1.0 as 100%
now the max cutoff frequency is
frame rate * sample rate
assuming sample rate is 1 and frame rate is 24 that would mean the slider would display the highest value at 2400%
now that conveys no meaning imo.
what we could do is extend the slider to not only display percentages. So the % would be default but it could be any arbitrary unit passed as a string
That sounds like a really nice addition to me.
b42d5d2cd6
to1a10a40a92
@dr.sybren @BClark I extended the slider to allow setting a unit
looks like this now with the butterworth operator
I had to do a small change to the behavior of the slider: The cursor movement it takes to go from min to max slider is now constant no matter the range of the slider. e.g. the -1/1 would have needed more travel than 0/1. not anymore
@blender-bot package
Package build started. Download here when ready.
@blender-bot package windows
Package build started. Download here when ready.
Much improvement! I like it a lot, thanks.
I have two questions left:
@ -389,0 +503,4 @@
blend_value = blend_out_y;
}
const float x_delta = fcu->bezt[i].vec[1][0] - left_bezt.vec[1][0] + filter_order;
I think that for an S-curve, we'd only need something like
blend_in_out_factor = sigmoid(blend_in_out_factor)
here.Of course that would also require a
float sigmod(float)
function in Blender's math lib ;-)413bb3e8f0
to14e9d9f0b7
@dr.sybren I changed the blend in/out logic to blend to the extrapolated slope of the bounding keys
it creates a nice arc now
and please ignore all these commits in the PR, I made the mistake again of pulling my branch after modifying it on the laptop. This seems to confuse the pull request
I fixed it by force pushing my commit just before the pull
no blend
blend of 8
@blender-bot package windows
@BClark new build for you with the modified blend behaviour
Package build started. Download here when ready.
Testing the latest build, blending is working well and nicer than the linear, and the results of the smoothing memory is really nice when running it several times in a row. Approve!
LGTM!