Milton Scene File Grammar

  1 root      = scenefile;
  2 scenefile = { version?, renderer?, camera?, output?, scene };
  3 
  4 variant   = type, property*;
  5 property  = string : primitive;
  6 primitive = null | boolean | int | double | string;
  7 
  8 path      = string;
  9 point3    = [ double, double, double ];
 10 vector3   = [ double, double, double ];
 11 color3    = [ double, double, double ];        // valid within [0, 1]^3
 12 spectrum  = [ double* ];                       // variable-length
 13 clampedSpectrum = double | path | [ double* ]; // valid within [0, 1]*
 14 
 15 version   = int | double;
 16 
 17 // Defaults to an OpenGL preview
 18 renderer  = { variant };
 19    renderer.type = "preview" | "rayCaster" | "rayTracer" | "pathTracer" |
 20                    "bidirectionalPathTracer" | "bidirPathTracer" |
 21                    "photonMapper" | "mlt" | "MLT";
 22    renderer.type["*"].noDirectSamples = uint;
 23    renderer.type["*"].noRenderThreads = uint;
 24    renderer.type["*"].noSuperSamples  = uint;
 25    renderer.type["*"].directSampleGenerator = string;
 26    renderer.type["*"].generator = string;
 27 
 28    renderer.type["rayCaster"].ambient   = spectrum;
 29    renderer.type["rayTracer"].maxDepth  = uint;
 30    renderer.type["rayTracer"].ambient   = spectrum;
 31 
 32    renderer.type["bidirPathTracer"] = renderer.type["bidirectionalPathTracer"];
 33 
 34    renderer.type["photonMapper"].diffuseNoGatherPhotons = uint;
 35    renderer.type["photonMapper"].causticNoGatherPhotons = uint;
 36    renderer.type["photonMapper"].diffuseGatherRadius    = double;
 37    renderer.type["photonMapper"].causticGatherRadius    = double;
 38    renderer.type["photonMapper"].diffuseNoPhotons       = uint;
 39    renderer.type["photonMapper"].causticNoPhotons       = uint;
 40 
 41 camera    = { variant };
 42    camera.type = "pinhole";
 43    camera.type["pinhole"].eye   = point3;
 44    camera.type["pinhole"].focus = point3;
 45    camera.type["pinhole"].look  = vector3;
 46    camera.type["pinhole"].up    = vector3;
 47    camera.type["pinhole"].heightAngle = double; // specified in degrees
 48    camera.type["pinhole"].aspectRatio = double;
 49    camera.type["pinhole"].near  = double;
 50    camera.type["pinhole"].far   = double;
 51 
 52 // Defaults to gui
 53 output    = { variant };
 54    output.type   = "naive" | "gui" | "reconstruction";
 55    output.width  = uint;
 56    output.height = uint;
 57    output.size   = [ uint, uint ];
 58    output.dimensions = output.size;
 59 
 60    output.type["reconstruction"].filter = filter;
 61 
 62 filter    = { variant };
 63    filter.type = "box" | "triangle" | "gaussian" | "mitchell" | "lanczosSinc";
 64    filter.type["*"].support = uint;
 65    filter.type["gaussian"].sigma  = double;
 66    filter.type["mitchell"].B      = double;
 67    filter.type["mitchell"].C      = double;
 68    filter.type["lanczosSinc"].tau = double;
 69 
 70 scene     = { node* };
 71 node      = material | transform | shape;
 72    node.name = "string";
 73 
 74 transform = { ((translate | rotate | scale)* | arbitraryTransform)?, node };
 75 arbitraryTransform = [ double, double, double, double, double, double, double, double,
 76                        double, double, double, double, double, double, double, double ];
 77 
 78 translate = vector3;
 79 rotate    = { point, axis, angle } | [ double, double, double,
 80                                        double, double, double,
 81                                        double ];
 82    rotate.point = point3;
 83    rotate.axis  = vector3;
 84    rotate.angle = double;  // specified in degrees
 85 scale     = vector3;
 86 
 87 shape     = { variant, material? };
 88    shape.type = "triangle" | "plane"  | "point" | "cube" | "cone" | "mesh" |
 89                 "cylinder" | "sphere" | "blob" | "shapeSet";
 90    shape.type["plane"].vertices    = [ double, double, double, double, double, double,
 91                                        double, double, double, double, double, double ];
 92    shape.type["triangle"].vertices = [ double, double, double, double, double, double,
 93                                        double, double, double ]; // x, y, z
 94    shape.type["triangle"].normals  = [ double, double, double, double, double, double,
 95                                        double, double, double ]; // x, y, z
 96    shape.type["triangle"].uvs      = [ double, double, double, double, double, double ];
 97    shape.type["triangle"].normal   = double; // constant over face of triangle
 98    shape.type["sphere"].position   = point3;
 99    shape.type["sphere"].radius     = double;
100    shape.type["blob"]      = [ shape.type["blob"].meta*, material? ];
101    shape.type["blob"].threshold  = double;  // valid within [0, 0.2)
102    shape.type["blob"].resolution = vector3;
103    shape.type["blob"].meta = { variant };
104       shape.type["blob"].meta.type = "ball";
105       shape.type["blob"].meta.type["*"].negative    = boolean;
106       shape.type["blob"].meta.type["*"].strength    = double;
107       shape.type["blob"].meta.type["ball"].position = vector3;
108       shape.type["blob"].meta.type["ball"].radius   = double;
109 
110    shape.type["mesh"].path = path;
111 
112    shape.type["shapeSet"]  = node;
113    shape.type["shapeSet"].spatialAccel = { variant };
114       shape.type.shapeSet.spatialAccel.type = "naive" | "kdTree";
115       shape.type.shapeSet.spatialAccel.type["kdTree"].kdSplitPlaneType =
116          "splitPlaneMiddle" | "splitPlaneMedian" | "splitPlaneSAH";
117       shape.type.shapeSet.spatialAccel.type["kdTree"].kdSplitAxisType =
118          "splitAxisRoundRobin" | "splitAxisLongestExtent";
119       shape.type.shapeSet.spatialAccel.type["kdTree"].kdMinPrimitives = uint;
120       shape.type.shapeSet.spatialAccel.type["kdTree"].kdMaxDepth      = uint;
121       shape.type.shapeSet.spatialAccel.type["kdTree"].kdNoThreads     = uint;
122       shape.type.shapeSet.spatialAccel.type["kdTree"].kdPostCompress  = boolean;
123       shape.type.shapeSet.spatialAccel.type["kdTree"].kdCostTraversal = double;
124       shape.type.shapeSet.spatialAccel.type["kdTree"].kdCostIntersect = double;
125       shape.type.shapeSet.spatialAccel.type["kdTree"].kdEmptyBias     = double;
126 
127 material  = { bsdf, emitter?, node? };
128    material.bumpMap        = path;
129    material.bumpIntensity  = double; // (0, inf), default 5.0
130    material.medium         = medium;
131    material.filter         = string;
132 
133 bsdf      = { variant };
134    bsdf.type = "absorbent" | "diffuse" | "dielectric" | "specular" | "transmissive" | "modifiedPhong" | "phong";
135    bsdf.type["diffuse"].kd             = clampedSpectrum;
136    bsdf.type["dielectric"].ks          = clampedSpectrum;
137    bsdf.type["dieletric"].transparency = clampedSpectrum;
138    bsdf.type["phong"].kd               = clampedSpectrum;
139    bsdf.type["phong"].ks               = clampedSpectrum;
140    bsdf.type["phong"].n                = spectrum; // [0, inf)*
141    // convenience aliases
142    bsdf.type["specular"]     = bsdf.type["dielectric"] with transparency=white;
143    bsdf.type["transmissive"] = bsdf.type["dielectric"] with transparency=black;
144 
145 emitter   = { variant };
146    emitter.type = "null" | "omni" | "oriented";
147    emitter.type["*"].power = spectrum | double; // if single double, fill3(double)
148    emitter.type["*"].glDiffuseColor  = color3;
149    emitter.type["*"].glSpecularColor = color3;
150    emitter.type["*"].glAttenuation   = vector3;
151 
152 medium    = { variant };
153    medium.type = "homogenous";
154    medium.type["*"].ior = double;
155 
156 generator = { variant };
157    generator.type = "uniform" | "stochastic" | "jittered" | "dissolve" | "hilbert";
158    generator["*"].binWidth  = double;
159    generator["*"].binHeight = double;
160    generator["*"].binSize   = double;
161 
162 // allow all variant types to be specified as dynamic plugins at runtime
163 *.type += | "dynamic";
164 *.type["dynamic"].dsoPath = path;
165