Transition Macros

As part of my animation work I have a set of macros which simplify moving objects from one location to another, or in some other way allow me to transition an object from one state to another.
Linear Changes
There are going to be times when you want to fade a scene to black or from black, or fade between two scenes. You will want things to be at a starting state up until the motion or change begins, and for it to be at a certain place when the motion ends, and for it to stay there, and for the movement in between those times to occur at a steady rate. When that is the case, a macro like the following will come in handy:
#macro Transition(tNow, tStart, pStart, tEnd, pEnd)
  #if (tNow <= tStart)
    (pStart)
  #elseif(tNow >= tEnd)
    (pEnd)
  #else
    (pStart + (pEnd - pStart) * (tNow - tStart) / (tEnd - tStart))
  #end
#end
Call this macro with the parameters set to the following values:
  • tNow: Set this to the current time of the animation (or the time for which you want the sampled value);
  • tStart: Set this to the time that you want the change to begin. Prior to this time, the returned value will be the starting point.
  • pStart: Set this to the position or value that you want returned at the start of the transition period.
  • tEnd: Set this to the time that you want the change to finish. After this time, the returned value will be the ending point.
  • pEnd: Set this to the position or value that you want returned at the end of the transition period.
  • pStart and pEnd can be any value type that can be added, subtracted, etc. I've used this for scalar values, vector values, and color values.
    Non-linear motion
    While the macro above works well for camera fades and other transitions that aren't physical in nature, it has an issue that makes it less useful for moving physical objects, and to explain why this is the case I will introduce a concept called continuity
    Degrees of continuity
    Continuity is when a particular value or quality does not make any sudden instant changes, but instead changes gradually over time. It is a very important concept in computer graphics, both in modeling as well as in animation. A model will have C0 continuity when the edges of its pieces meet, C1 continuity when they meet in a smooth edge, C2 continuity when the curvature on both sides of the edge is the same, and so on. In the same way, the location of an object over time has its own set of continuities, and the first seven of these have special names for them:
  • Position is where an object is located.
  • Velocity is the rate at which an object's position is changing.
  • Acceleration is the rate at which an object's velocity is changing.
  • Jerk is the rate at which an object's acceleration is changing.
  • Snap is the rate at which an object's jerk is changing.
  • Crackle is the rate at which an object's snap is changing.
  • Pop is the rate at which an object's crackle is changing.
  • I swear I am not making these names up.
  • There is no common name for the rate at which pop is changing, because the value rarely comes up in physics and engineering.
  • As you go down this list, lapses in continuity start out garishly obvious, but become less noticeable the further down the list you go.
  • A discontinuity in position will appear as an object being at one place at one instant, and then being at another place at the very next instant. To us it looks like the object teleported, and unless that was the animator's intent it will look very unnatural.
  • A discontinuity in velocity will appear as an object making sudden changes in its velocity. While not as painfully wrong as a discontinuity in position, it does look very unnatural.
  • A discontinuity in acceleration will appear odd in some situations, but in other cases will go unnoticed, and in fact in many applications it takes someone with an engineer's knowledge to know that there is any problem with the motion observed. A discontinuous acceleration is most apparent when you use the current acceleration value to calculate the orientation of the object (such as when an object banks to make turns).
  • Discontinuities in jerk are less noticeable, although engineers working on highways, railroads, and carnival rides do have to worry about keeping the jerk level within tolerable limits.
  • In most applications discontinuities in snap, crackle, and/or pop are very difficult for the viewer to notice, and addressing them may be required only in very special instances.
  • Macro for C1 Motion
    If you only need a smooth start and stop, and sudden changes in acceleration aren't a problem, then you only need C1 continuity. I've found that non-linear transitions often do not follow a straight line from the start to the end, but also have a lateral component to the motion, so this macro has an extra parameter which I'll explain after the code:
    #macro Transition1(tNow, tStart, pStart, tEnd, pEnd, vSwerve)
      #if (tNow <= tStart)
        (pStart)
      #elseif(tNow >= tEnd)
        (pEnd)
      #else
        #local tHack = (tNow - tStart) / (tEnd - tStart);
        #local uIndex = ((3 - 2 * tHack) * tHack * tHack);
        #local vIndex = tHack * tHack * (1 - tHack) * (1 - tHack) * 16;
        (pStart + (pEnd - pStart) * uIndex + vSwerve * vIndex)
      #end
    #end
    The parameters have the same meaning as in the Transition macro above. The parameter vSwerve supports the extra lateral motion, and should be set to the maximum extent that the lateral component will have. The lateral displacement will be applied gradually until its maximum value at the halfway point between tStart and tEnd, and then go down and taper off gradually at the end of the motion. If you don't want the lateral motion, set the parameter to <0, 0, 0>.
    Macro for C2 Motion
    If you need a smoother motion, so that acceleration is zero at the start and end of the animation, then you need C2 continuity. This macro has the same parameters as Transition1, but uses a more sophisticated calculation to ensure C2 continuity:
    #macro Transition2(tNow, tStart, pStart, tEnd, pEnd, vSwerve)
      #if (tNow <= tStart)
        (pStart)
      #elseif(tNow >= tEnd)
        (pEnd)
      #else
        #local tHack = (tNow - tStart) / (tEnd - tStart);
        #local uIndex = (((6 * tHack - 15) * tHack + 10) * tHack * tHack * tHack);
        #local vIndex = tHack * tHack * tHack * (1 - tHack) * (1 - tHack) * (1 - tHack) * 64;
        (pStart + (pEnd - pStart) * uIndex + vSwerve * vIndex)
      #end
    #end
    Macro for C3 Motion
    If you need even smoother motion, so that jerk is zero at the start and end of the animation, then you need C3 continuity, and this macro will provide it:
    #macro Transition3(tNow, tStart, pStart, tEnd, pEnd, vSwerve)
      #if (tNow <= tStart)
        (pStart)
      #elseif(tNow >= tEnd)
        (pEnd)
      #else
        #local tHack = (tNow - tStart) / (tEnd - tStart);
        #local uIndex = ((((70 - 20 * tHack) * tHack - 84) * tHack + 35) * tHack * tHack * tHack * tHack);
        #local vIndex = tHack * tHack * tHack * tHack * (1 - tHack) * (1 - tHack) * (1 - tHack) * (1 - tHack) * 256;
        (pStart + (pEnd - pStart) * uIndex + vSwerve * vIndex)
      #end
    #end
    The parameters have the same meaning as in the Transition1 macro above.
    As for which of the macros to use for motion, the best way to decide is to test all three of them, and decide which one looks more natural to you.
    For the Math-Heads
    The equations for the non-linear macros were derived using some basic calculus. For all three macros, I took the polynomial x - x2 and raised it to the power of the desired continuity level, giving x - x2 for Transition1, x2 - 2x3 + x4 for Transition2, and x3 - 3x4 + 3x5 - x6 for Transition3.
    I then took the antiderivative of each polynomial and multiplied each one by the inverse of its value when evaluated at x=1. In each case, this resulted in a polynomial with a value of zero at x=0 and a value of one at x=1, and is used to calculate the amount of motion along the vector from the start of motion to the end point.
    The formula for the coefficient of lateral motion was derived by taking the polynomial x - x2, raising it to the second, third, or fourth power respectively, and then scaling it by the inverse of the value of each polynomial when evaluated at a value of one-half. This results in a polynomial whose value is zero at x=0 and x=1 and a value of one at x=½.
    Preview of Coming Attractions
    The next item of most interest to some readers will be a way to create a motion path, again with arbitrary degrees of continuity. I'll have the math all done and some useful code to use. Watch this space.

    Comments

    Popular posts from this blog

    Titling Made Simple

    Star Field Generator