' '

Difficulty

2

Prerequisites

ray-tracers/v1

patterns/basics

def scene_at(now)
{
  var ez = Animations.ease(Animations.animate(15, 9, seconds(5)), Easing.cubic_out())[now]
  var ey = Animations.ease(Animations.animate(10, 1, seconds(5)), Easing.cubic_out())[now]
  var lz = Animations.ease(Animations.animate(10, 0, seconds(5)), Easing.cubic_out())[now]

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

  var white = Materials.uniform( [ "ambient": Colors.white() * 0.1,
                                   "diffuse": Colors.white() * 0.8,
                                   "specular": Colors.white(),
                                   "specular_exponent": 20 ] )

  var black = Materials.uniform( [ "ambient": Colors.black(),
                                   "diffuse": Colors.white() * 0.1,
                                   "specular": Colors.white(),
                                   "specular_exponent": 20 ] )

  var checkered_pattern = Patterns.checkered(1, 1)
  var checkered_material = Materials.from_pattern(checkered_pattern, white, black)

  var lines_pattern = Patterns.lines(.02, .04)
  var lines_material = Materials.from_pattern(lines_pattern, white, black)
  var lines_material2 = Materials.from_pattern(Patterns.rotate(degrees(90), lines_pattern), white, black)

  var polka_pattern = Patterns.polka2d(0.05, 0.1)
  var polka_material = Materials.from_pattern(polka_pattern, white, black)

  var angle = Animations.animate(degrees(0), degrees(360), seconds(5))

  var root = union( [ decorate(checkered_material, translate(vec(0, -1, 0), xz_plane())),
                      decorate(lines_material, sphere()),
                      decorate(lines_material2, translate(vec(-3,0,0),sphere())),
                      decorate(polka_material, translate(vec(3,0,0),sphere()))
                      ] )

  var lights = [ Lights.omnidirectional( pos(0,2,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() ] )

As explained in this extension, patterns are in essence nothing more than function that, given a position, return a boolean value.This extension’s purpose is to be able to use patterns as materials.

1. Examples

Consider this example script:

var material = Materials.from_pattern(pattern, material1, material2)

This creates a material whose structure is defined by pattern. Wherever the pattern returns true, material1 is used, and similarly for false and material2.

Let’s define values for pattern, material1 and material2:

var pattern = Patterns.checkered(1, 1)
var white = Materials.uniform( [ "ambient": Colors.white() * 0.1,
                                 "diffuse": Colors.white() * 0.8 ] )
var black = Materials.uniform( [ "ambient": Colors.white() * 0.1,
                                 "diffuse": Colors.white() * 0.8 ] )
var material = Materials.from_pattern(pattern, white, black)

Here, pattern defines the checkerboard structure, while white and black determine what materials are associated with every square of the checkerboard.

chess

Of course, any materials will do:

var pattern = Patterns.checkered(1, 1)
var m1 = Materials.uniform( [ "ambient": Colors.white() * 0.1,
                              "diffuse": RGB(0.8,0.5,0.5),
                              "specular": Colors.white(),
                              "specular_exponent": 20,
                              "reflectivity": 0.5 ] )

var m2 = Materials.uniform( [ "ambient": Colors.blue() * 0.1,
                              "diffuse": RGB(0.5, 0.5, 0.8),
                              "specular": Colors.white(),
                              "specular_exponent": 20 ] )

var material = Materials.from_pattern(pattern, m1, m2)
chess2

2. Implementation

  • Create new files materials/pattern-material.h and materials/pattern-material.cpp.

  • Update materials/materials.h.

2.1. pattern2d

Implement a function with signature

Material raytracer::materials::pattern2d(Pattern2D pattern,
                                         Material m1,
                                         Material m2);
Tip

The implementation can be kept very short if you rely on composite (see materials/composition-material.h), which already implements 90% of the required functionality.

2.2. pattern3d

Implement a function with signature

Material raytracer::materials::pattern3d(Pattern3D pattern,
                                         Material m1,
                                         Material m2);

3. Bindings

Expose both pattern2d and pattern3d to the scripting language as from_pattern overloads. In other words, bind both pattern2d and pattern3d as from_pattern. The scripting language will know based on the types of the arguments for from_pattern which patternNd factory to call.

4. Evaluation

Render the scene below.

challenge
def material2d(c1, c2, v)
{
    var m1 = Materials.uniform( [ "ambient": c1 ] )
    var m2 = Materials.uniform( [ "ambient": c2 ] )

    Materials.from_pattern(Patterns.constant2d(v), m1, m2)
}

def material3d(c1, c2, v)
{
    var m1 = Materials.uniform( [ "ambient": c1 ] )
    var m2 = Materials.uniform( [ "ambient": c2 ] )

    Materials.from_pattern(Patterns.constant3d(v), m1, m2)
}


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


var primitives = []

primitives.push_back(translate(vec(-3, 3, 0),
                               decorate( material2d(Colors.white(), Colors.red(), true),
                                         sphere())))

primitives.push_back(translate(vec(3, 3, 0),
                               decorate( material2d(Colors.white(), Colors.red(), false),
                                         sphere())))

primitives.push_back(translate(vec(-3, -3, 0),
                               decorate( material3d(Colors.green(), Colors.blue(), true),
                                         sphere())))

primitives.push_back(translate(vec(3, -3, 0),
                               decorate( material3d(Colors.green(), Colors.blue(), false),
                                         sphere())))


var root = union(primitives)

var lights = [ ]

var scene = create_scene(camera, root, lights)

var raytracer = Raytracers.v1()

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

pipeline( scene,
          [ Pipeline.renderer(renderer),
            Pipeline.wif(),
            Pipeline.base64(),
            Pipeline.stdout() ] )