DarioMazzanti / OneEuroFilterUnreal

OneEuroFilter plugin for Unreal Engine 4
MIT License
42 stars 18 forks source link

Rotator wrap around error. #3

Open RMKeene opened 2 years ago

RMKeene commented 2 years ago

With Rotator One Euro Filters the wrap around 0 to 360 degrees is not handled. E.g. if raw yaw is currently 295 degrees and the new yaw is 3 degrees that should be a +8 degrees difference. Instead it is seen as a -292 degree difference and so the interpolation in the filter slews the long way around the yaw circle.

The correct way to do it is to have the input check incoming new values of rotation against the current raw value and if the difference is > 180 or < -180 fudge the incoming angle by adding or subtracting 360 degrees. I did this in blueprints and it works.

It should be in the C++. I may submit a C++ code fix and pull request.

RMKeene commented 2 years ago

Ok, fixed. But I do not have permission to push (even as a branch).

Here is the code in OneEuroFilterBlueprintDatatypes.cpp...

void FOneEuroFilterRotator::SetValue(FRotator NewValue) {

if (!bInitialized)
{
    TheFilter = MakeShareable(new OneEuroFilter<FRotator>(Frequency, MinCutoff, Beta, DCutoff));

    bInitialized = true;
}

// Compensate for circle degrees wrap around.
float diff = NewValue.Roll - Value.Roll;
if (diff > 180.0f)
    NewValue.Roll -= 360.0f;
else if (diff < -180.0)
    NewValue.Roll += 360.0f;

diff = NewValue.Pitch - Value.Pitch;
if (diff > 180.0f)
    NewValue.Pitch -= 360.0f;
else if (diff < -180.0)
    NewValue.Pitch += 360.0f;

diff = NewValue.Yaw - Value.Yaw;
if (diff > 180.0f)
    NewValue.Yaw -= 360.0f;
else if (diff < -180.0)
    NewValue.Yaw += 360.0f;

Value = NewValue;

if (TheFilter.IsValid())
    FilteredValue = TheFilter->Filter(Value);

};

RMKeene commented 2 years ago

Note that the Unity version of the filter has this problem. The solution there would be to flag Rotator style values as needing wrap around and then do a very similar fix for those.