' '

Difficulty

3

Prerequisites

animations/easing-library

Reading material

animations/basics

design/animations

1. Introduction

Numbers have operations defined on them: we can add two numbers together (\(a + b\)), subtract them (\(a - b\)), multiply them (\(a \times b\)), and so on. Similary, we can apply operations on primitives: take their union, their difference, their intersection, we can translate, scale and rotate them, and so on. The same can be done with animations.

In this extension, you are tasked with defines a series of operations that act upon animations.

2. Limit

Sometimes, we just want to cut off an animation prematurely. Say we have an animation of duration 10:

limit

We can choose to cut it off after 5 seconds:

limit2

Create a file animation/animation-limiter.h. In the namespace animation, create a function

template<typename T>
Animation<T> limit(Animation<T> animation, Duration duration)
{
  ...
}
Tip

First examine animations/interval-animation.h and try to understand what each part does. limit (and most of the other operations) will have the same structure.

3. Invert

An animation can be inverted: instead of going from A to B, it goes from B to A.

invert

Create a file animation/animation-inverter.h. In the namespace animation, create a function

template<typename T>
Animation<T> invert(Animation<T> animation)
{
  ...
}

that returns the inversion of the given animation

4. Sequence

Animations can be put in sequence. For example, consider the two animations below, each lasting 10 seconds:

sequence

Sequencing them yields

sequence2

Typically, you will only combine animations if they have matching endpoints (ending point of the first is equal to the starting point of the second), but this is not mandatory.

Create a file animation/animation-sequence.h. In the namespace animation, create a function

template<typename T>
Animation<T> sequence(Animation<T> a, Animation<T> b)
{
  ...
}

5. Looper

An animation can be repeated at infinitum. For example, take the animation below:

looper

Repeating this animation endlessly gives a new animation with infinite duration:

looper2

Create a file animation/animation-looper.h. In the namespace animation, create a function

template<typename T>
Animation<T> loop(Animation<T> a)
{
  ...
}

6. Cycle

Looping an animation is nicer if the starting and ending point coincide, otherwise a sudden jump will occur when the animation resets. One way to easily achieve this is to sequence an animation with its inversion.

Consider the animation below:

cycle

We take its inverse:

cycle2

We sequence them:

cycle3

Finally, we loop it:

cycle4

Create a file animation/animation-cycler.h. In the namespace animation, create a function

template<typename T>
Animation<T> cycle(Animation<T> a)
{
  ...
}

7. Bindings

Expose each of these functions to the scripting language. Since we support animations of different types (double, Point3D, Angle), we need to export an overload for each.

For example, say you want to export limit. In the AnimationLibrary, you will need to define a template method:

template<typename T>
Animation<T> limit(Animation<T> animation, Duration duration) const
{
    ...
}

Next, you will need to add a binding for all supported types:

BIND_AS(limit<double>, limit);
BIND_AS(limit<Point3D>, limit);
BIND_AS(limit<Angle>, limit);

8. Evaluation

Reproduce the following animation:

Reproduce the following animation:

Reproduce the following animation:

Render the scene below.

def scene_at(now)
{
  var camera = Cameras.perspective( [ "eye": pos(0,0,15),
                                      "look_at": pos(0,0,0) ] )

  var primitives = [ ]

  {
    var a = Animations.animate(degrees(0), degrees(360), seconds(2))
    var angle = Animations.cycle(Animations.limit(a, seconds(1)))[now]
    var x = 5 * cos(angle)
    var y = 5 * sin(angle)

    primitives.push_back(translate(vec(x, y, 0), sphere()))
  }

  {
    var p1 = Animations.animate(Pos.cylindrical_z(3, degrees(-30), 0),
                                Pos.cylindrical_z(3, degrees(90), 0),
                                seconds(1.0 / 3.0))
    var p2 = Animations.animate(Pos.cylindrical_z(3, degrees(90), 0),
                                Pos.cylindrical_z(3, degrees(210), 0),
                                seconds(1.0 / 3.0))
    var p3 = Animations.animate(Pos.cylindrical_z(3, degrees(210), 0),
                                Pos.cylindrical_z(3, degrees(330), 0),
                                seconds(1.0 / 3.0))
    var p123 = Animations.loop(Animations.sequence(Animations.sequence(p1, p2), p3))[now]

    primitives.push_back(translate(p123 - pos(0,0,0), sphere()))
  }

  {
    var x = Animations.cycle(Animations.animate(-3, 3, seconds(2)))[now]

    primitives.push_back(translate(vec(x,-4,0), sphere()))
  }


  var root = union(primitives)

  var lights = [ ]

  create_scene(camera, root, lights)
}

var raytracer = Raytracers.v0()
var renderer = Renderers.standard( [ "width": 500,
                                     "height": 500,
                                     "sampler": Samplers.single(),
                                     "ray_tracer": raytracer ] )

pipeline( scene_animation(scene_at, seconds(4)),
          [ Pipeline.animation(30),
            Pipeline.renderer(renderer),
            Pipeline.wif(),
            Pipeline.base64(),
            Pipeline.stdout ] )