' '

Difficulty

3

Prerequisites

ray-tracers/v2

Reading material

lights/spot

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

  var material = Materials.uniform( [ "ambient": Colors.white() * 0.1,
                                      "diffuse": Colors.white() * 0.8,
                                      "specular": Colors.white(),
                                      "specular_exponent": 100,
                                      "reflectivity": 0,
                                      "transparency": 0,
                                      "refractive_index": 0 ] )

  var root = decorate(material, union([ translate(vec(0,-1,0),xz_plane()), sphere() ]))

  var t = Animations.animate(degrees(0), degrees(360), seconds(5))[now]

  var pos1 = Animations.lissajous( [ "x_amplitude": 5,
                                     "x_frequency": 2,
                                     "z_amplitude": 5,
                                     "z_frequency": 1,
                                     "duration": seconds(5) ] )
  var pos2 = Animations.lissajous( [ "x_amplitude": 5,
                                     "x_frequency": 2,
                                     "x_phase": degrees(180),
                                     "z_amplitude": 5,
                                     "z_frequency": 1,
                                     "z_phase": degrees(180),
                                     "duration": seconds(5) ] )

  var lights = [ Lights.spot( pos(-5,5,1), pos1[now], degrees(40), Colors.red() ),
                 Lights.spot( pos(5,5,1), pos2[now], degrees(40), Colors.green() ) ]


  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() ] )

A spot light is parameterized by

  • The position \(L\) of the spot light (Point3D).

  • The direction \(\vec{v}\) it shines in (Vector3D).

  • The angle \(\theta\) of the light cone (Angle).

  • The color \(C\) of the light (Color).

Getting the information in this form is ideal for the implementation. However, as a scene builder, having to specify the direction is not intuitive. From the scene builder’s perspective, it makes much more sense to specify the location that the spot light is supposed to be directed at. This leads to a slightly different set of parameters:

  • The position \(L\) of the spot light (Point3D).

  • The position \(P\) that the light should shine on (Point3D).

  • The angle \(\theta\) of the light cone (Angle).

  • The color \(C\) of the light (Color).

diagram

Fortunately, it is easy to, given the second set of parameters, compute the first set of parameters from it. In other words, given \(L\) and \(P\), it is easy to determine \(\vec{v}\) from it.

Implement spot lights. Create two factory functions:

LightSource spot(const math::Point3D& position,
                 const math::Vector3D& direction,
                 math::Angle angle,
                 const imaging::Color& color);

LightSource spot(const math::Point3D& position,
                 const math::Point3D& target,
                 math::Angle angle,
                 const imaging::Color& color);

Provide bindings for both.

1. Evaluation

Render the following script:

def scene_at(now)
{
  var t = Animations.animate(0, 1, seconds(5))[now]

  var camera = Cameras.perspective( [ "eye": pos(0, 0, 10),
                                      "look_at": pos(0, 0, 0) ] )

  var material = Materials.uniform( [ "ambient": Colors.black(),
                                      "diffuse": Colors.white() ] )

  var root = decorate(material, xy_plane())

  var lights = [ Lights.spot( pos(-2,2,1), vec(0,-4*t,-1).normalized(), degrees(30), Colors.red() ),
                 Lights.spot( pos(2,-2+4*t,2), pos(2,-2+4*t,0), degrees(60*t), Colors.blue() ),
                 Lights.spot( pos(0,-3,1), pos(-4+8*t,0,0), degrees(60), Colors.green() ) ]

  create_scene(camera, root, lights)
}

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

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