1
$\begingroup$

That's me again, struggling with the animation. I created a number of key frames. However, my camera sometimes was doing a full 360 loop interpolating between two close camera positions. So I had to add more and more key frames to stop it. But in the end I have just one odd frame 114, where it suddenly jumps. In the "Transform" panel under "Rotations" I have "Quaternion (WXYZ)"). All the components of the quaternion are quite small and change its sign between these two frames as I see in the "Transform" panel.

Deleting the key frame 113 causes the camera to roll all over the place again.

Is there a way to stop this behaviour? I also found some posts talking about parenting when creating animations, but I can't understand it exactly.

I checked how it looks in the Graph editor, but rotations are smooth and no sign change at that frame 114. So as far as I understand Graph Editor has rotation in local coordinates, while the transform panel in global.

The animation is here (model from blendswap, made by TheDuckCow):

EDIT:

Here is an example. This frame is fine.

goodFrame

But next one is not: badFrame

Then next one is good again.enter image description here

Apparently something numerical happens when they all go through zero...

This is what happens if I run the script: scriptResult

$\endgroup$
  • 1
    $\begingroup$ Possibly related: blender.stackexchange.com/questions/28438/… $\endgroup$ – Mutant Bob Jul 29 '16 at 16:05
  • $\begingroup$ @MutantBob thanks for the link, but it still don't know how to fix it. My rotations looks smooth anyway. I run the script posted in the answer, but it created an awful load of keyframes (for some reason only in the first part of animation) and camera rotates all around and sees the object only by accident. $\endgroup$ – Noidea Jul 29 '16 at 22:07
2
$\begingroup$

Quaternions must be "normalized" in order to represent an actual orientation. That means 1=w*w+x*x+y*y+z*z. Fortunately this gets handled for you, and much of the time the result is close enough to what you want that you don't even notice a problem.

However, if the animation system interpolates a value where all of them are zero, then it probably gets changed to <1,0,0,0> . The only way to solve that problem is to add a keyframe that has the intermediate orientation, preferably in a normalized form.

$\endgroup$
1
$\begingroup$

What I found so far: Quaternions q and -q represent the same rotation. For interpolation to take the shortest path one has to choose the quaternion closest one to the previous frame (either q or -q). If rotations q1 and q2 are close to each other as rotations, but are positioned oppositely on the sphere, than intermediate frames from q1 to q2 will basically travel a full 360 degrees.

Solution:

This script goes through keyframes and inverts quaternions if necessary. After running the script one has to press "T" in the F-curve view and choose interpolation type (Bezier), because it looks weird otherwise.

import bpy
from mathutils import Quaternion
import math

def main():
    #reading curves
    obj = bpy.context.active_object
    action = obj.animation_data.action

    # quaternion curves
    fqw = action.fcurves.find('rotation_quaternion', index = 0)
    fqx = action.fcurves.find('rotation_quaternion', index = 1)
    fqy = action.fcurves.find('rotation_quaternion', index = 2)
    fqz = action.fcurves.find('rotation_quaternion', index = 3)  

    # invert quaternion so that interpolation takes the shortest path
    endQuat = 0
    if (len(fqw.keyframe_points) > 0):
        endQuat = Quaternion((fqw.keyframe_points[0].co[1],fqx.keyframe_points[0].co[1],fqy.keyframe_points[0].co[1],fqz.keyframe_points[i].co[1] ))

    for i in range(len(fqw.keyframe_points)-1):
        startQuat = endQuat
        endQuat = Quaternion((fqw.keyframe_points[i+1].co[1],fqx.keyframe_points[i+1].co[1],fqy.keyframe_points[i+1].co[1],fqz.keyframe_points[i+1].co[1] ))

        if startQuat.dot(endQuat) <0 :
            endQuat.negate()
            fqw.keyframe_points[i+1].co[1] = -fqw.keyframe_points[i+1].co[1]
            fqx.keyframe_points[i+1].co[1] = -fqx.keyframe_points[i+1].co[1]
            fqy.keyframe_points[i+1].co[1] = -fqy.keyframe_points[i+1].co[1]
            fqz.keyframe_points[i+1].co[1] = -fqz.keyframe_points[i+1].co[1]
main()
$\endgroup$
  • $\begingroup$ fqz.keyframe_points[i].co[1] should be fqz.keyframe_points[0].co[1] $\endgroup$ – Mr.Epic Fail Oct 12 '18 at 12:45
0
$\begingroup$

Not sure of this is too simple and therefore "I'm not understanding the situation", but when I get interaction problems of this nature I parent cameras on an invisible object such as a plane, and if necessary, parent that object to another. That has solved similar problems I've had with complex movements in several axis at once. Each dummy object can be moved/rotated independently and at any time without interfering with the other dummy(s).

The camera can also be moved independently, all of it ending up smooth and seemingly without restriction as to the number of simultaneous transformations.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.