' '

Difficulty

3

Prerequisites

ray-tracers/v2

Reading material

design/primitives/ray-intersections

def scene_at(now)
{
  var eye_animation = Animations.animate( [ pos(5, 5, 5), pos(0,5,5), pos(0,0,5), pos(0,0,-5) ], seconds(3) )
  var lookat_animation = Animations.animate( [ pos(0, 0, 0), pos(0,0,0), pos(0,0,0), pos(0,0,-10) ], seconds(3) )

  var camera = Cameras.perspective( [ "eye": eye_animation[now],
                                      "look_at": lookat_animation[now] ] )

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

  var root = decorate(material, crop_along_z( cylinder_along_z(), interval(-1, 1) ))

  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(3)),
          [ Pipeline.animation(30),
            Pipeline.renderer(renderer),
            Pipeline.studio() ] )

One of a Primitive's few responsibilities is to compute its intersections with a ray: the method find_all_hits(ray) returns a list of these intersections between the primitive itself and the given ray.

What if we were to impose restrictions on which hits can be returned? For example, we could only allow hits that are located in a certain region. This would make it look as if the primitive only exists in that box. In other words, we "cut off" all parts of the primitive that fall outside of this box.

Create a new Cropper primitive.

  • Put it in its own files (primitives/cropper-primitive.cpp and corresponding header file).

  • Provide the following factory functions:

    • Primitive crop_along_x(Primitive child, const Interval<double>&) only allows hits whose x-coordinate fall inside the given interval.

    • Primitive crop_along_y(Primitive child, const Interval<double>&) only allows hits whose y-coordinate fall inside the given interval.

    • Primitive crop_along_z(Primitive child, const Interval<double>&) only allows hits whose z-coordinate fall inside the given interval.

    • Primitive crop_by_box(Primitive child, const Box&) only allows hits who fall inside the given box.

    • Primitive crop_by_sphere(Primitive child, double radius) only allows hits that fall within a sphere of the given radius around \((0, 0, 0)\).

  • Provide bindings for these functions. Note: there is no way to create boxes from within the scripting language, so you’ll have to be a bit creative when dealing with crop_by_box.

Tip

One class (featuring the necessary parameters) will suffice for this extension.

1. Evaluation

Render the following scene:

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

  var camera = Cameras.perspective( [ "eye": pos(8 - 16*t,5-5*t,5),
                                      "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": 10,
                                      "reflectivity": 0.5,
                                      "transparency": 0,
                                      "refractive_index": 0 ] )

  var primitives = []
  primitives.push_back(translate(vec(-3,0,0),crop_along_x( sphere(), interval(-.5, .5))))
  primitives.push_back(translate(vec(0,0,0),crop_along_y( sphere(), interval(-.5, .5))))
  primitives.push_back(translate(vec(3,0,0),crop_along_z( sphere(), interval(-.5, .5))))

  var root = decorate(material, union(primitives))

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

  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(3)),
          [ Pipeline.animation(30),
            Pipeline.renderer(renderer),
            Pipeline.wif(),
            Pipeline.base64(),
            Pipeline.stdout() ] )