RAY File Format Specification


The RAY file format has been specially modified to suit the needs of CS155, for use with the ray tracer project. This specification corresponds to the accepted file format for rt, the example raytracer developed for this class. It's basic format is a list of directives, denoted by hashes (#), followed by the necessary data for the directive. C and C++ style comments are allowed anywhere within the file. The beginning of a RAY file is denoted by the #version directive and the end is the #rayfile_end directive.

Conventions

A directive is a single string (no whitespace) beginning with a hash mark. It is immediately followed by its arguments. If the directive accepts flags, the flags should come first. After all the flags (or immediately, if there are no flags), there must be a double-hyphen, '--', to mark the end of the flags and the beginning of the object's data. Whitespace is ignored, so place spaces, tabs, newlines, etc. wherever you like.

Comments may appear at any point in the file. There are two types of comments: line comments and block comments. A line comment starts with a // and continues to the end of the line. A block comment starts with a /* and continues until a */ is encountered. Nested block comments are not allowed and will result in a parse warning. There must be whitespace around the comment tokens (// /* and */) for the comments to be properly parsed. If there isn't, such as int i = 0;// initialize i, the // will be missed and parsing will fail.

All angles are specified in degrees.

Directives

#version HMCCS155FALL2002

The version directive starts the rayfile. The string following it is the version of the RAY file - since each semester the format changes slightly, it is important to check this string to know what format to expect.

#rayfile_end

The rayfile_end directive ends the rayfile. This directive isn't necessary, but can be useful if you need to embed a rayfile in a text stream (such as an email message).

#background r g b

The background directive specifies the color to use when raytracing, in the event that a ray doesn't intersect with any objects. It is followed by an RGB triplet (range [0..1]).

#ambient ar ag ab

The ambient directive specifies the color and intensity of ambient lighting in the scene. It is followed by an RGB triplet (range [0..1]).

#camera
    px py pz    // position
    tx ty tz    // toward
    ux uy uz    // up
    theta       // half height angle

The camera directive specifies the default view point in the scene. The first triplet is the position of the camera, followed by the direction the camera is facing, the up vector, and finally an angle in degrees representing half of the height view angle.

#light_dir [ -n name ] --
    lr  lg  lb     // color
    ldx ldy ldz    // direction

The light_dir directive adds a directional light to the scene. It has an optional name flag (useful for debugging), followed by a '--' to mark the end of the flags. The RGB triplet specifies the color of the light and the second triplet is the direction the light points.

#light_point [ -n name ] --
    lr  lg  lb     // color
    lpx lpy lpz    // position
    ca  la  qa     // const linear quad attenuation

The light_point directive adds a point light to the scene. It has an optional name flag (useful for debugging), followed by a '--' to mark the end of the flags. The RGB triplet specifies the color of the light, the second triplet is the position of the light, and the last three values are the constant, linear and quadratic attentuation factors (use 1 0 0 for no attenuation).

#light_spot [ -n name ] --
    lr  lg  lb     // color
    lpx lpy lpz    // position
    ldx ldy ldz    // direction
    ca  la  qa     // const linear quad attenuation
    co  do         // cutoff angle, dropoff rate

The light_spot directive adds a spot light to the scene. It has an optional name flag (useful for debugging), followed by a '--' to mark the end of the flags. The RGB triplet specifies the color of the light, the second triplet is the position of the light, the third triplet is the direction the light is facing, the fourth triplet is the constant, linear and quadratic attentuation factors (use 1 0 0 for no attenuation). The last two values are the cutoff angle, in degrees, which represents half the angle of the spotlight's cone of light, and the dropoff rate (range [0..inf)) which represents how quickly the intensity falls off from the center of the spotlight.

#material -n name [ -t texture file ] [ -r transparency map file ] 
			 [ -x cutout map file ] [ -u bump map file ] 
			 [ -tp procedural texture ] 
			 [ -rp procedural transparency map ]
			 [ -xp procedural cutout map ]
			 [ -up procedural bump map ] --
    mar mag mab    // ambient response
    mdr mdg mdb    // diffuse response
    msr msg msb    // specular response
    mer meg meb    // emissive color
    ks  kt  rf     // kspec, ktrans, refractive index

The material directive specifies a set of surface properties to use for calculating the color of an object. It has a required name flag (used by objects to specify their material), an optional texture file flag (path relative to the RAY file), an optional transparency map file flag (path relative to the RAY file), an optional cutout map file flag (path relative to the RAY file), and an optional bump map file flag (path relative to the RAY file). These maps can also be specified as procedural textures, in which case the -tp, -rp, -xp, and -up flag should be used with the name of the texture. If both procedural and non-procedural maps are specified, the non-procedural one will be used (for any of the four functions). These are followed by a '--' to mark the end of the flags. The first RGB triplet is the material's response to ambient light. The second is the response to diffuse light, the third is the response to specular light, and the fourth is the light the material emmits. The last three values are the kspec or shininess coefficient (see OpenGL Programming Guide Third Edition), the transparency coefficient (range [0..1], 0 is opaque, 1 is perfectly transparent), and the refractive index (1.0 is air, 1.52 is glass).

#sphere -m material [ -n name ] [ -t ] [ -r ] [ -x ] [ -u scale ] --
    cx cy cz    // center position
    r           // radius

The sphere directive creates a sphere shape in the scene. It has a required material flag (with the name of the desired material as the argument), followed by an optional name flag (useful for debugging), an optional textured flag (if present, the sphere is texture mapped, otherwise no texture mapping is done), an optional transparency mapping flag (if present, the sphere is transparency mapped), an optional cutout mapping flag (if present, the sphere uses a cutout map), an optional bump-mapping flag (if present, the sphere is bump-mapped) with a scaling factor to apply when bump-mapping, and finally the '--' to mark the end of the flags. Next comes the XYZ coordinates of the sphere's center, and finally the sphere's radius.

#triangle -m material [ -n name ] [ -t ] [ -r ]  [ -x ] [ -u scale ] --
    v0x v0y v0z  [ t0s t0t ]    // vertex 0  [ texcoord 0 ]
    v1x v1y v1z  [ t1s t1t ]    // vertex 1  [ texcoord 1 ]
    v2x v2y v2z  [ t2s t2t ]    // vertex 2  [ texcoord 2 ]

The triangle directive creates a flat triangle shape in the scene. It has a required material flag (with the name of the desired material as the argument), followed by an optional name flag (useful for debugging), and optional flags for texturing, transparency, cutout, and bump-mapping (which must also have a specified scale). (If any is present, the texture coordinates must be specified with the vertex coordinates; otherwise, texture coordinates must not be specified with the vertex coordinates), and finally the '--' to mark the end of the flags. Next come the XYZ coordinates (and ST texture coordinates, if the -t, -r, -x, or -u flag is present) of each of the three vertices in the triangle.

Note: Normals point in the CCW direction, so specify your vertices counter-clockwise to orient the normal appropriately. Materials should be rendered two sided however, so it may not be an important concern. OpenGL mode by default does not backface cull - turn it on via the menu to see which direction your triangle normals point.

Note: The presence or absence of the -t and -r flags determines which data the parser expects to come afterwards. If either flag is present, there must be 15 numbers, 5 per vertex, 3 for position and 2 for texture coordinates. If both are absent, there must be 9 numbers, 3 per vertex for position.

#cylinder -m material [ -n name ] [ -t ] [ -c ] [ -r ]  [ -x ] [ -u scale ]--
    cx cy cz    // base center
    r  l        // radius, length

The cylinder directive creates a cylinder shape in the scene, aligned with the z-axis. It has a required material flag (with the name of the desired material as the argument), an optional name flag (useful for debugging), an optional textured flag (if present, the cylinder is texture mapped), an optional closed flag (if present, the cylinder has endcaps), an optional transparency mapping flag (if present, the cylinder will use transparency mapping), an optional cutout mapping flag (if present, the sphere uses a cutout map), and an optional bump-mapping flag (if present, the sphere is bump-mapped) with a scaling factor to apply when bump-mapping, followed by the '--' to mark the end of the flags. The XYZ triplet specifies the center of the base of the cylinder, r is the radius and l is the length from end to end.

#cone -m material [ -n name ] [ -t ] [ -c ] [ -r ]  [ -x ] [ -u scale ]--
    cx cy cz    // base center
    r  l        // base radius, length

The cone directive creates a cone shape in the scene, aligned with the z-axis with the base at the origin. It has a required material flag (with the name of the desired material as the argument), an optional name flag (useful for debugging), an optional textured flag (if present, the cone is texture mapped), an optional closed flag (if present, the cone has endcaps), an optional transparency mapping flag (if present, the cone will use transparency mapping), an optional cutout mapping flag (if present, the sphere uses a cutout map), and an optional bump-mapping flag (if present, the sphere is bump-mapped) with a scaling factor to apply when bump-mapping, followed by the '--' to mark the end of the flags. The XYZ triplet specifies the center of the base of the cone, r is the radius at the base, and l is the length from base to apex.

#torus -m material [ -n name ] [ -t ] [ -r ] [ -x ] [ -u scale ]--
    cx cy cz    // center
    r1 r2       // major radius, minor radius

The torus directive creates a torus shape in the scene, in the XY plane. It has a required material flag (with the name of the desired material as the argument), an optional name flag (useful for debugging), an optional textured flag (if present, the torus is texture mapped), and an optional transparency mapping flag (if present, the torus will use transparency mapping), an optional cutout mapping flag (if present, the sphere uses a cutout map), and an optional bump-mapping flag (if present, the sphere is bump-mapped) with a scaling factor to apply when bump-mapping, followed by the '--' to mark the end of the flags. The XYZ triplet specifies the center of the torus. The major radius is the distance from the center to the circular axis of of the cylinder, and the minor radius is the radius of the cylinder.

#box -m material [ -n name ] [ -t ] [ -r ] [ -x ] [ -u scale ]--
    cx cy cz    // center
    sx sy sz    // size

The box directive creates an axis-aligned box shape in the scene. It has a required material flag (with the name of the desired material as the argument), an optional name flag (useful for debugging), an optional textured flag (if present, the box is texture mapped), an optional transparency mapping flag (if present, the box will use transparency mapping), an optional cutout mapping flag (if present, the sphere uses a cutout map), and an optional bump-mapping flag (if present, the sphere is bump-mapped) with a scaling factor to apply when bump-mapping, followed by the '--' to mark the end of the flags. The first XYZ triplet specifies the center of the box, and the second is the size of the box in each direction.

#csg_begin [ -n name ] --
    cx cy cz    // center
    ...csg directives...
#csg_end

The csg directive creates an object defined by constructive solid geometry operations in the scene. It has only an optional name flag, as material properties are taken from its constituent objects. The material used for the surface of a csg object will be that specified for the constituent object whose surface is being displayed. The XYZ triplet specifies the center of the object. The following csg operations are supported:

#csg_union // any point in either a or b
   a
   b
#csg_merge // any point in exactly one of a and b
   a
   b
#csg_isect // any point in both a and b 
   a
   b
#csg_diff // any point in a, but not b
   a
   b
#csg_inv // any point not in a
   a

The first four operators require two parameters, a and b, while inv only requires one. Any shape or group object can be used for these parameters, including groups, spheres, triangles, cones, cylinders, tori, boxes, csg-defined objects, rayfile instances, and macro instances.

#group_begin [ -n name ] --
    m11 m12 m13 m14
    m21 m22 m23 m24
    m31 m32 m33 m34
    m41 m42 m43 m44
    ...shape directives...
#group_end

The group_begin directive marks the beginning of a group of shapes in the scene. It has an optional name flag (useful for debugging), followed by the '--' to mark the end of the flags. Next comes the group's tranformation matrix - a 4 by 4 array of floating point numbers to specify the geometric tranformation to apply to objects inside the group. Use the identity matrix for no transformation. The end of the group is specified with a group_end directive. Inside the group, any shape or group object can be placed, including more groups, spheres, triangles, cones, cylinders, tori, boxes, rayfile instances, and macro instances.

#macro_begin -n name --
    ...shape directives...
#macro_end

The macro_begin directive marks the beginning of a macro - a group of shapes that can be pasted into the scene multiple times for easy duplication of complicated objects. It has a required name flag (used to specify where to place the macro in the scene), followed by the '--' to mark the end of the flags. The end of the macro is marked by the macro_end directive. Inside the macro, any shape or group object can be placed, including groups, spheres, triangles, cones, cylinders, tori, boxes, rayfile instances, and macro instances.

Tip: Don't use macros when you're first starting out. They're provided to make building more complex scenes possible for art submissions, but they can add a great deal of complexity to RAY files. Only use them when you're comfortable with the file format and the raytracer.

Note: When a macro is defined, it is not placed in the scene. To place the macro objects into the scene, use a macro_instance directive

Note: It is possible to instance a macro inside itself, or using another macro, define some circular loop which can never be properly evaluated. No checking is done for this sort of mistake! This will send the parser into an infinite loop. If parsing a RAY file is taking an unreasonable amount of time, make sure you don't define any circular macros.

#macro_instance macroName

The macro_instance directive pastes a macro's shape group into the scene in place of itself. It requires one argument, the name of the macro to create an instance of.

#rayfile_include -n name -f file --

The rayfile_include directive specifies another RAY file to read in for inclusion in the scene. It has a required name flag (used to specify where to place the RAY file in the scene) and a required file flag with the path to the file to include, relative to the current file. Finally, there is a '--' to mark the end of flags.

Tip: Don't include RAY files when you're first starting out. This features is provided to make building more complex scenes possible for art submissions, but it can add a great deal of complexity to RAY files. Only use it when you're comfortable with the file format and the raytracer.

Note: When a RAY file is included, it is not placed in the scene. To place the RAY file's objects into the scene, use a rayfile_instance directive.

Note: It is possible to instance a RAY file inside itself, or using another RAY file, define some circular loop which can never be properly evaluated. No checking is done for this sort of mistake! This will send the parser into an infinite loop. If parsing a RAY file is taking an unreasonable amount of time, make sure you don't make any circular RAY file dependencies.

Note: Only the shapes, groups, macros and materials from the included RAY file are placed into the scene. Lights, ambient and background color, cameras, etc. are all ignored. Names are always RAY file local, never global, so a RAY file cannot reference a material, macro, or other named object in an included RAY file, and vice-versa. Namespace collision is handled for you, but may make debugging a little trickier. Only use included RAY files when you know what you're doing.

#rayfile_instance rayfileName

The rayfile_instance directive pastes an included RAY file's shape group into the scene in place of itself. It requires one argument, the name of the included RAY file to create an instance of.

#grad_begin -n name --
    i0   r g b
    i1   r g b
    .....
#grad_end

Defines a color gradient for use with procedural textures. The gradient has a required name field, then a series of value/color pairs. When using the gradient to get a color for some value, the gradient will do linear interpolation between the values specified originally to determine the appropriate color. For more on their use, see the manual.

#expr -n name --
   ...function definition...

This directive allows for the definition of an expression using lisp-like syntax. The name field is required. The supported grammar is as follows (most operations are self-explanatory):

expression -> binary
            | unary


binary -> ( + terminal terminal ) 
        | ( - terminal terminal ) 
        | ( * terminal terminal )
        | ( / terminal terminal )
        | ( ^ terminal terminal )
        | ( % terminal terminal )


unary -> ( -    terminal )
       | ( abs  terminal )
       | ( sqrt terminal )
       | ( ln   terminal )
       | ( sin  terminal )
       | ( cos  terminal )
       | ( int  terminal ) // cast the terminal to an integer
       | ( tan  terminal )
       | ( asin terminal )
       | ( acos terminal )
       | ( atan terminal )

terminal -> variable_name
          | e | pi
          | number
          | expression
#proctex_perlin -n name -g gradient_name [ -s seed ] [ -t time ] 
						[ -e expression_name ] --
    octaves
    persistence
Defines a procedural texture based on perlin noise. For a given point (x, y, z) calculates a random value in [-1, 1] and uses this value to look up a color in the specified gradient. If a function is specified, it is used in summation as defined in the manual. If no seed is specified, one is randomly generated. If a time value is specified, then noise coherent in four dimensions will be used, with time as the fourth dimension. This can be used to make a sequence of images with smooth transitions from one to the next (provided the same seed is used for each).