Milton Scene File Format Tutorial

Milton's Scene File Format

In this tutorial we'll explore how Milton scenefiles are constructed. When Milton is executed from the command line, it expects a Milton scenefile to be passed to it. The format of these scenefiles are described in the Milton Scene File Grammar, but we're going to save you the trouble of parsing the grammar walking through some simple examples.

(more detail)
The format uses JSON, Javascript Object Notation, to describe everything Milton needs to render a scene. JSON is a text-based format for representing associative and indexed arrays. It's quite simple and human readable, but if you're not familiar with JSON, you should do a quick google search to catch up. Let's take a look at the simplest Milton scene file:
{
    "scenefile" : {
        /**
         * Scene (materials and shapes) 
         */
        "scene" : {
        },
    },
}

In this example, a scene is created with absolutely nothing in it. If you run Milton with this scene, you should see this output:

We're looking at an OpenGL rendering of... nothing! (The axes that you see are built into the OpenGL preview and are not actually part of your scene.) Alright, we'll fix that by adding a sphere. A sphere is a pre-defined object in Milton, which you can add to the "scene" object as such:

{
    "scenefile" : {
        /**
         * Scene (materials and shapes) 
         */
        "scene" : {
"sphere" : { },
}, }, }

"But wait," you say, "this tutorial isn't about rendering in OpenGL!" Let's get our Pixar-quality scene up and running with a state-of-the-art Whitted-style Ray Tracer (circa 1980-- OK, so it's not quite state-of-the-art anymore, but it'll make us a pretty picture.) We need to specify a "renderer" object with the type of renderer that we want.

{
    "scenefile" : {
"renderer" : { "type" : "rayTracer", },
/** * Scene (materials and shapes) */ "scene" : { "sphere" : { }, }, }, }

Bah! That doesn't look so good, we haven't lit the scene so we're not seeing much. The next step is to add a light (or a luminaire as fancy people call them).

{
    "scenefile" : {
        "renderer" : {
            "type" : "rayTracer",
        },

        /**
         * Scene (materials and shapes) 
         */
        "scene" : {
"material" : { /* light */ "emitter" : { "type" : "oriented", "power" : [0, 100, 10], }, "transform" : { "translate" : [ 0, 2, 0 ], "transform" : { "rotate" : [ 0, 0, 0, 1, 0, 0, 180 ], "plane" : { }, }, }, },
"sphere" : { }, }, }, }

Alright, so now we're really making progress here. We've defined an emissive, diffuse plane with a rotation and a translation applied to it (in that order.)

(more detail)
A few things to note: the value that power takes is called a spectrum which is an n-tuple of doubles. Some types, i.e. clampedSpectrum and color types take values which are n-tuples of doubles within the range [0,1]. For example, kd is a clampedSpectrum and accepts either one double or n doubles (in an array) within the range [0,1]. clampedSpectrum also accepts a path to a file which will be used to look up values as a map. In the above example, by passing the value 1 to kd, we are saying that every wavelength in the valid spectrum (this is usually RGB) gets the value 1 for the diffuse coefficient. Another note is that transformations which are order specific must be nested because JSON doesn't guarantee an ordering of elements at the same level in an object. E.g. without nesting the rotation within the translation, the JSON parser could tell Milton to perform either transformation first and a translation followed by a rotation is different from a rotation followed by a translation. Lastly, you'll notice that the innermost element of the first material block is a plane meaning that all of the nesting objects will apply to it.

Now that we've seen a bit of code, let's cover some of the concepts guiding the file format. The Milton scene file format revolves around the idea of a 'variant' data type which is an object with a property called 'type' (which has some set of possible values) and some number of additional properties (a key/value pair with a string key and a value which is an object.) You'll notice (either by looking at enough scenefiles or by reading the scene file format) that the 'renderer', 'camera', and 'output' blocks are all objects that are 'variant's. This format enables Milton's scene format to be quite extensible and allows additional functionality to be added very quickly. The first key/value pair in the scene is an emissive plane which has been translated and rotated. Notice that Material, Shape and Transform objects can be combined in many ways to produce aggregate objects with shared materials and/or transformations.

Now let's make the scene a bit more exciting by adding a few additional spheres with varying material properties and a camera.

{
   "scenefile" : {
      /**
       * Renderer
       */
      "renderer" : {
         "type" : "pathTracer",
      },

/** * Camera */ "camera" : { "type" : "pinhole", "eye" : [ 3, .8, 0 ], "up" : [ 0, 1, 0 ], "heightAngle" : 45, "aspectRatio" : 1.0, "near" : 1, "far" : 100, },
/** * Scene (materials and shapes) */ "scene" : { "material": { "emitter" : { "type" : "omni", "power" : [ 700,700,700 ], }, "transform" : { "translate" : [ 0, 3, 0 ], "transform" : { "rotate" : [ 0, 0, 0, 0, 0, 1, 180 ], "scale" : [ .75, 1, .75 ], "plane" : { }, }, }, },
"material": { "transform" : { "scale" : [ 5, 1, 5 ], "plane" : { }, }, },
"material": { "bsdf" : { "type" : "phong", "ks" : [ .2, .8, .2 ], "n" : 80, }, "transform" : { "translate" : [ 0, .25, 1 ], "transform" : { "scale" : [ .5, .5, .5 ], "sphere" : { }, }, }, },
"material": { "bsdf" : { "type" : "specular", "ks" : .8, }, "transform" : { "translate" : [ 0, .25, 0 ], "transform" : { "scale" : [ .5, .5, .5 ], "sphere" : { }, }, }, },
"material": { "bsdf" : { "type" : "phong", "ks" : [ .1, .1, .5 ], "n" : 80, }, "transform" : { "translate" : [ 0, .25, -1 ], "transform" : { "scale" : [ .5, .5, .5 ], "sphere" : { }, }, }, },
"material": { "bsdf" : { "type" : "dielectric", "transparency" : 1, }, "medium" : { "ior" : 1.49 }, "transform" : { "translate" : [ 1.2, .18, .3 ], "transform" : { "scale" : [ .3, .3, .3 ], "sphere" : { }, }, }, },
}, }, }

This last iteration adds quite a bit to the scene. The camera that's added allows the scene to be viewed from a different eye point. As with everything else in Milton, the camera is very extensible and this scene is only using the most basic functionality. Within the scene itself, we've added a scaled plane, and a number of spheres. There are two spheres with Phong shading, one with a specular model, and another with a dielectric model (one which can reflect or transmit light).

Hopefully you now have enough information to edit and make basic scenes for Milton. Happy rendering!