Can anyone help me fix quaternion rotation errors in Unity?

  • Thread starter Thread starter twoski
  • Start date Start date
  • Tags Tags
    Quaternions
twoski
Messages
177
Reaction score
2
I am trying to implement animation smoothing for a given set of keyframes. Some keyframes have "jitter" which i have to remove through my own algorithms. I am using the Unity game engine which has its own quaternion classes and such.

I looked into it, and using an Exponential Moving Average seems like a good idea. This approach works well for removing positional jitter, however when i use it with quaternions it causes some errors with rotations.

I am currently converting quaternions to euler angles, averaging, then converting back. However this doesn't seem to work. It causes my models to rotate in the wrong directions.

Here is the code i use:

Code:
void UpdateRotationEMA(int i, Quaternion q)
    {
        if (transforms[i] != null)
        {
            if (frameList[i] != null)
            {
                Vector3 pos = AvgPos(frameList[i], q.eulerAngles); //T1

                transforms[i].rotation = Quaternion.Euler(pos);
                frameList[i] = pos;
            }
            else
            {
                transforms[i].rotation = q;
                frameList[i] = q.eulerAngles; 
            }
        }
    }
Vector3 AvgPos(Vector3 lastPos, Vector3 pos)
    {
        return (emaAlpha * pos + ((1f - emaAlpha) * lastPos));
    }

Can anyone spot any obvious bugs?
 
Physics news on Phys.org
Perhaps you can get it to print the input and the averaged output to see what's going on. Could the algorithm be averaging the angles too?
 
I wasn't sure if this was the proper method - should i be converting my quaternions to euler angles, then averaging those? Or am i meant to just average the quaternions?
 
I think my problems are stemming from a situation like this:

Angle 1: 10, 0, 0.
Angle 2: 350, 0, 0.

The distance between 10 and 350 is 20. This is pretty clear.

However, by doing:

(0.2 * Angle1 + ((0.8) * Angle2))

We get a new angle which is 282, 0, 0. This is totally wrong since it goes the wrong direction!
 
This seems like a step in the right direction.

Code:
Vector3 AvgPos(Vector3 lastPos, Vector3 pos)
    {
        Vector3 init = (emaAlpha * pos + ((1f - emaAlpha) * lastPos));

        if (init == pos)
        {
            return init;
        }

        Vector3 res = init;
        Vector3 delta = pos - init;

        if (Mathf.Abs(pos.x - lastPos.x) > 180f)
        {
            res.x = pos.x - delta.x;
        }

        if (Mathf.Abs(pos.y - lastPos.y) > 180f)
        {
            res.y = pos.y - delta.y;
        }

        if (Mathf.Abs(pos.z - lastPos.z) > 180f)
        {
            res.z = pos.z - delta.z;
        }

        res.x = res.x % 360f;
        res.y = res.y % 360f;
        res.z = res.z % 360f;

        return res;
    }

Still, my skeletons are rotating weirdly.
 
I don't know much about what you're trying to do but am talking from the experience of debugging programs.

So are you trying to move an object from once place to the next smoothly without changing it orientation? Or change it in a natural and smooth way?

I found this NASA pdf talking about how to average quaternions and also about subtle errors you may encounter:

http://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/20070017872.pdf

Here's another reference:

http://www.mathworks.com/matlabcentral/fileexchange/40098-tolgabirdal-averaging-quaternions
 
Hmm that looks correct, however i am trying to do an exponential moving average which is slightly different from the way they are doing it.
 
twoski said:
I am trying to implement animation smoothing for a given set of keyframes. Some keyframes have "jitter" which i have to remove through my own algorithms. I am using the Unity game engine which has its own quaternion classes and such.

Clarify the meaning of "jitter".

Thinking of hand drawn animation, I can imagine a sequence of keyframes that are supposed portray a globe turning. Perhaps some of them inadvertently show the globe moving a little from side to side, so the animation that interpolates images between the keyframes shows the globe vibrating as well as rotating.

How were the keyframes generated? Is a keyframe a set of parameters or an actual image?
 
  • #10
Ok keyframes was misleading as an example, I'm using raw input from a kinect. Essentially, i have the last frame, and the current frame. Both have a rotation value.

I want to calculate the exponential moving average of these values, however in order to do so i need to convert to euler i think. The problem with using an exponential moving average for this is that euler angles go from 0 to 360 then start at 0 again, so if 2 angles are, say, 350 and 10, the exponential moving average of these will be incorrect using the function i posted.

Intuitively, we know that the difference is 20 degrees. Given this value is there a way to find out the exponential moving average?
 
  • #11
I've glanced at pages about using quaternions for animation and seen interpolation recommended - something like a spline. Supposedly interpolation between quaternion values produces smoother results than interpolating between Euler angles. Is interpolation relevant to what you are doing?

I don't know what an "exponential moving average" is. The meaning of "moving average" is familiar, but what is being averaged? What is being exponentiated?
 
  • #12
Stephen Tashi said:
I've glanced at pages about using quaternions for animation and seen interpolation recommended - something like a spline. Supposedly interpolation between quaternion values produces smoother results than interpolating between Euler angles. Is interpolation relevant to what you are doing?

I don't know what an "exponential moving average" is. The meaning of "moving average" is familiar, but what is being averaged? What is being exponentiated?

I am showcasing different methods of animation smoothing, I've already implemented quaternion lerping so now I'm trying to show a different method.

Here is the definition: http://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average

The exponential moving average is easy to implement for vectors, however in my case we need to account for the fact that the vectors are euler angles and can go from 0 to 350 in 10 degrees rather than 350 degrees.
 
  • #13
The way I think of moving averages computed from a sequence of data points is that they don't form a curve that goes through the points. So smoothing with moving average is not "interpolation". Is it your intention that your smoothed animation never exactly matches the keyframes?
 
  • #14
The main goal is to remove jitter, if the animation is slightly off then that just gives me one more talking point for when i showcase the different styles of smoothing.
 
  • #15
I second jedishfu's suggestion to check the code that does the exponential average, if you haven't done that yet.

Have you done any "sanity" tests? Does animation look right if you apply the method to something that just stays in the same constant position?
 
  • #16
I have done debug prints, however the easiest way to see what was going on was by looking at the raw data in action.



You can see that it's rotating joints in the wrong direction which results in the sporadic flipping of the middle girl.

It only happens when an angle goes from a low number to a very high number, like the scenarios i have described.
 
Back
Top