' '
def material(color)
{
  Materials.uniform( [ "ambient": color * 0.1,
                       "diffuse": color * 0.8,
                       "specular": Colors.white() * 0.8,
                       "specular_exponent": 100,
                       "reflectivity": 0.1 ] )
}

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

  var pos1 = Animations.lissajous( [ "x_phase": degrees(90),
                                     "duration": seconds(5) ] )

  var pos2 = Animations.lissajous( [ "z_amplitude": 0,
                                     "x_frequency": 2,
                                     "y_frequency": 3,
                                     "x_phase": degrees(180),
                                     "duration": seconds(5) ] )

  var pos3 = Animations.lissajous( [ "z_amplitude": 3,
                                     "x_frequency": 7,
                                     "y_frequency": 5,
                                     "z_frequency": 3,
                                     "duration": seconds(5) ] )

  var wall_material = Materials.uniform( [ "ambient": Colors.white() * 0.1,
                                           "diffuse": Colors.white() * 0.5,
                                           "reflectivity": 0.1 ] )

  var back_wall = translate(vec(0,0,-5), decorate(wall_material, xy_plane()))

  var floor = translate(vec(0,-5,0), decorate(wall_material, xz_plane()))


  var root = union([ translate(vec(-5,0,0) + pos1[now] - pos(0,0,0), decorate( material(Colors.red()), sphere())),
                     translate(pos2[now] - pos(0,0,0), decorate( material(Colors.red()), sphere())),
                     translate(vec(5,0,0) + pos3[now] - pos(0,0,0), decorate( material(Colors.red()), sphere())),
                     back_wall,
                     floor])

  var lights = [ Lights.omnidirectional( pos(0,5,5), Colors.white() ) ]


  create_scene(camera, root, lights)
}


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

pipeline( scene_animation(scene_at, seconds(5)),
          [ Pipeline.animation(30),
            Pipeline.renderer(renderer),
            Pipeline.studio() ] )

1. Implementation

To simplify things, we generalize the formula from the background information even further:

\[\begin{array}{rcl} x(t) & = & A_\mathrm{x} \cdot \sin(B_\mathrm{x} \cdot 2\pi \cdot t - C_\mathrm{x}) \\ y(t) & = & A_\mathrm{y} \cdot \sin(B_\mathrm{y} \cdot 2\pi \cdot t - C_\mathrm{y}) \\ z(t) & = & A_\mathrm{z} \cdot \sin(B_\mathrm{z} \cdot 2\pi \cdot t - C_\mathrm{z}) \\ \end{array}\]

We give the parameters the more descriptive names:

Math Code Default

\(A_\mathrm{x}\)

x_amplitude

1

\(A_\mathrm{y}\)

y_amplitude

1

\(A_\mathrm{z}\)

z_amplitude

1

\(B_\mathrm{x}\)

x_frequency

1

\(B_\mathrm{y}\)

y_frequency

1

\(B_\mathrm{z}\)

z_frequency

1

\(C_\mathrm{x}\)

x_phase

\(0^\circ\)

\(C_\mathrm{y}\)

y_phase

\(0^\circ\)

\(C_\mathrm{z}\)

z_phase

\(0^\circ\)

Implement the Lissajous animation so that we can use it as

var position = Animations.lissajous( [ "x_amplitude": 1,
                                       "y_amplitude": 1,
                                       "z_amplitude": 1,
                                       "x_frequency": 1,
                                       "y_frequency": 1,
                                       "z_frequency": 1,
                                       "x_phase": degrees(0),
                                       "y_phase": degrees(90),
                                       "z_phase": degrees(90),
                                       "duration": seconds(5) ] )

where all parameters except duration can be omitted.

Tip

The duration parameter is a bit harder to deal with, since the Duration class has no default constructor. Use the following code:

Duration duration = Duration::zero();

START_ARGUMENTS(argument_map);
...
BIND_ARGUMENT(duration);
END_ARGUMENTS();

2. Evaluation

Render the scene below.

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



  var pos2 = Animations.lissajous( [ "z_amplitude": 0,
                                     "x_frequency": 2,
                                     "y_frequency": 3,
                                     "x_phase": degrees(180),
                                     "duration": seconds(5) ] )

  var pos3 = Animations.lissajous( [ "z_amplitude": 3,
                                     "x_frequency": 7,
                                     "y_frequency": 5,
                                     "z_frequency": 3,
                                     "duration": seconds(5) ] )

  var primitives = []

  {
    var v = Animations.lissajous( [ "x_phase": degrees(90),
                                    "duration": seconds(1),
                                    "x_amplitude": 6,
                                    "y_amplitude": 4 ] )[now] - pos(0,0,0)

    primitives.push_back(translate(v, sphere()))
  }

  {
    var v = Animations.lissajous( [ "x_frequency": 3,
                                    "x_amplitude": 3,
                                    "y_amplitude": 0,
                                    "z_amplitude": 5,
                                    "z_frequency": 2,
                                    "duration": seconds(2) ] )[now] - pos(0,0,0)

    primitives.push_back(translate(v + vec(0,0,0), sphere()))
  }

  {
    var v = Animations.lissajous( [ "x_frequency": 2,
                                    "y_frequency": 5,
                                    "y_phase": degrees(90),
                                    "x_amplitude": 5,
                                    "y_amplitude": 2,
                                    "duration": seconds(2) ] )[now] - pos(0,0,0)

    primitives.push_back(translate(v + vec(0,8,0), sphere()))
  }

  {
    var v = Animations.lissajous( [ "x_frequency": 1,
                                    "y_frequency": 3,
                                    "y_phase": degrees(90),
                                    "x_amplitude": 5,
                                    "y_amplitude": 2,
                                    "duration": seconds(2) ] )[now] - pos(0,0,0)

    primitives.push_back(translate(v + vec(0,-8,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(2)),
          [ Pipeline.animation(30),
            Pipeline.renderer(renderer),
            Pipeline.studio() ] )