' '

Difficulty

3

Prerequisites

ray-tracers/v2

def material(color) {
  Materials.uniform( [ "ambient": color * 0.1,
                       "diffuse": color * 0.8,
                       "specular": Colors.black(),
                       "specular_exponent": 0,
                       "reflectivity": 0,
                       "transparency": 0,
                       "refractive_index": 0 ] )
}


def scene_at(now)
{
  var camera = Cameras.perspective( [ "eye": pos(0, 5, 5),
                                      "look_at": pos(0, 0, 0),
                                      "up": vec(0, 1, 0),
                                      "distance": 1,
                                      "aspect_ratio": 1 ] )

  var primitives = []

  primitives.push_back(group(1, decorate(material(Colors.red()),
                                                  translate(Animations.circular(pos(0,0,2),
                                                                                pos(0,0,0),
                                                                                vec(0,1,0),
                                                                                interval(degrees(0), degrees(360)),
                                                                                seconds(5))[now] - pos(0,0,0),
                                                            sphere()))))
  primitives.push_back(group(2, decorate(material(Colors.green()),
                                                  translate(Animations.circular(pos(0,0,2),
                                                                                pos(0,0,0),
                                                                                vec(0,1,0),
                                                                                interval(degrees(120), degrees(480)),
                                                                                seconds(5))[now] - pos(0,0,0),
                                                            sphere()))))
  primitives.push_back(group(3, decorate(material(Colors.blue()),
                                                  translate(Animations.circular(pos(0,0,2),
                                                                                pos(0,0,0),
                                                                                vec(0,1,0),
                                                                                interval(degrees(240), degrees(360+240)),
                                                                                seconds(5))[now] - pos(0,0,0),
                                                            sphere()))))

  primitives.push_back(decorate(material(Colors.white()), translate(vec(0,-5,0), xz_plane())))

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

  create_scene(camera, root, lights)
}


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

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

Achieving this effect is a matter of creating a custom Renderer. The implementation is actually very simple, but it requires you to examine existing code, understand how it works and find out which line you need to update.

Create new files renderers/cartoon-renderer.cpp and renderers/cartoon-renderer.h. Copy the code of StandardRenderer and make the necessary renames.

1. Shades

We represent colors using RGB values. Our ray tracer uses doubles to represent each component, but let’s pretend we use one byte for each component, as is typically the case. This means each component has 256 shades: 256 shades of red × 256 shades of green × 256 shades of blue results in 16,777,216 different colors.

We can reduce this number of shades, yielding a cartoonty effect.

#shades Result

256

shades256

64

shades64

16

shades16

8

shades8

4

shades4

2

shades2

The StandardRenderer has a number of parameters (horizontal_size, vertical_size, sampler, etc.) CartoonRenderer has an extra parameter shade_count of type unsigned.

2. Implementation

The only thing left to do is make the change to CartoonRenderer that achieves the effect shown above. Examine CartoonRenderer's current source code and make play around with it to check whether your understanding is correct.

Modify CartoonRenderer so that it produces results as shown on this page.

Tip

You only need an extra method call somewhere. The math part has already been implemented for you somewhere.

3. Evaluation

Reproduce the following animation:

Tip

The shade_count parameter remains constant. It’s something else that varies.