' '
preview
var camera = Cameras.perspective( [ "eye": pos(5, 0.5, 5),
                                    "look_at": pos(0, 0.5, 0),
                                    "up": vec(0, 1, 0),
                                    "distance": 1,
                                    "aspect_ratio": 1 ] )

var white_material = Materials.uniform( [ "ambient": Colors.white(),
                                          "diffuse": Colors.black(),
                                          "specular": Colors.black(),
                                          "specular_exponent": 0 ] )

var black_material = Materials.uniform( [ "ambient": Colors.black(),
                                          "diffuse": Colors.black(),
                                          "specular": Colors.black(),
                                          "specular_exponent": 0 ] )

var checkered_material = Materials.from_pattern(Patterns.checkered(1, 1), white_material, black_material)

var root        = decorate(checkered_material, xz_plane())

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

var scene = create_scene(camera, root, lights)


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

pipeline( scene,
          [ Pipeline.renderer(renderer),
            Pipeline.studio() ] )

Implement the half-jittering sampler. Make it public through a factory function

Sampler raytracer::samplers::stratified_half_jittered(unsigned rows, unsigned columns);

Expose the sampler to the scripting language by updating scripting/samplers-module.cpp.

1. Evaluation

Render the scene below:

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

  var spheres   = []

  for_each([-10..10], bind(fun (i, spheres) {
    for_each([-10..10], bind(fun (j, i, spheres) {
      spheres.push_back(translate(vec(5*i, 0, 5*j), sphere()))
    }, _, i, spheres))
  }, _, spheres))

  var root      = union(spheres)

  var lights    = [ ]

  return create_scene(camera, root, lights)
}

var renderer = Renderers.standard( [ "width": 100,
                                     "height": 100,
                                     "sampler": Samplers.halfjittered(1, 1),
                                     "ray_tracer": Raytracers.v0() ] )

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

Render the scene below:

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

  var spheres   = []

  for_each([-10..10], bind(fun (i, spheres) {
    for_each([-10..10], bind(fun (j, i, spheres) {
      spheres.push_back(translate(vec(5*i, 0, 5*j), sphere()))
    }, _, i, spheres))
  }, _, spheres))

  var root      = union(spheres)

  var lights    = [ ]

  return create_scene(camera, root, lights)
}

var renderer = Renderers.standard( [ "width": 100,
                                     "height": 100,
                                     "sampler": Samplers.halfjittered(3, 3),
                                     "ray_tracer": Raytracers.v0() ] )

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

Write at least 10 tests that check cases easy to compute manually, such as

  • Given a rectangle \([0,1]\times[0,1]\) and \(1 \times 1\) samples, the returned sample should inside \([0.25,0.75]\times[0.25,0.75]\).

  • Given a rectangle \([0,2]\times[0,1]\) and \(1 \times 1\) samples, the returned sample should inside \([0.5,1.5]\times[0.25,0.75]\).

  • Given a rectangle \([0,1]\times[0,2]\) and \(1 \times 1\) samples, the returned sample should inside \([0.25,0.75]\times[0.5,1.5]\).

  • Given a rectangle \([5,9]\times[2,6]\) and \(1 \times 1\) samples, the returned sample should inside \([6,8]\times[3,5]\).

  • Given a rectangle \([0,8]\times[0,8]\) and \(2 \times 2\) samples, the returned samples should inside \([1,3]\times[1,3]\), \([1,3]\times[5,7]\), \([5,7]\times[1,3]\) and \([5,7]\times[5,7]\).

Important

The tests should not expect the samples to be returned in a certain order. During the defense, this will be checked. Failure to take this into account will disqualify this extension.

Tip

If you are uncertain of how to interpret the rectangle notation above (e.g., \([0,4]\times[0,4]\)), read this page.

Tip

See the reading material if you have no clue about how to write sampler tests.