For this project we define a rudimentary scene graph language. Each command should be placed on its own line, and CR/LF should only occur at the end of the command. If a CR/LF appears before the end, the results may be unpredicatable, but whitespace can be present anywhere, in any quantity. All color values are floating point values between 0.0 and 1.0, and all other numeric expressions are assumed to be floating point, also, unless otherwise noted. Angles are given in radians.
Commands:
#camera px py pz dx dy dz ux uy uz ha
This defines a perspective camera in the scene. (px,py,pz) is the position of the camera in world coordinates, (dx,dy,dz) is a unit vector describing the direction of the camera, and (ux,uy,uz) is a unit vector in the up direction. The half-height angle of the viewing frustum is given by ha, such that the half-width angle can be found by ha*ar, where ar is the width-over-height aspect ratio of the output image (given on the command line). The camera command must appear before of any group directives. The first camera found in the file will be used, and subsequent camera definitions are ignored.
#background r g b
The background color defines the color to assign to rays which fail to intersect any object, and leave the scene. Only the first background definition encountered is used, and subsequent instances are ignored. It must appear before any group directives. If not defined, a value of black is assumed.
#ambient r g b
Sets the global ambient light level. The first ambient definition is used, and subsequent instances are ignored. It must appear before any group directives. If not defined, a value of black is assumed.
#light_num n
The total number of lights in the scene is given by this command. This command must appear before any light_* definitions. Only the first incidence of this command is used, while subsequent instances are ignored. It must appear before any group directives. If there are no lights in the scene (only global ambient light), light_num 0 need not be declared.
#light_point r g b px py pz ca la qa
This defines a point light in the scene. (r,g,b) gives the color of the light. Note that we depart from the OpenGL convention of defining three colors for a light (one for each of ambient, diffuse, and specular properties.) In this ray tracer, use this single light color for diffuse and specular contributions at each surface. Do not compute ambient contributions from each light, but rather use the global ambient light defined by the ambient directive. Each instance must appear before any group directives.
(px,py,pz) gives the position of the light in world coordinates. The attenuation of the light with distance from its position is given by ca, la, and qa which define the constant, linear and quadratic components of the attenuation factor. If d is the distance from the light to the surface, then the light's color at the surface is given by (r,g,b) * (ca + la*d + qa*d^2)^-1. Each coeficient must be positive or equal to zero. Note: to achieve no attenuation use a (ca,la,qa) of (1,0,0).
#light_spot r g b px py pz dx dy dz ca la qa sc sd
This defines a spot point light in the scene. (r,g,b) gives the color of the light. Note that we depart from the OpenGL convention of defining three colors for a light (one for each of ambient, diffuse, and specular properties.) In this ray tracer, use this single light color for diffuse and specular contributions at each surface. Do not compute ambient contributions from each light, but rather use the global ambient light defined by the ambient directive. Each instance must appear before any group directives.
(px,py,pz) gives the position of the light in world coordinates, and (dx,dy,dz) is a unit vector describing the direction of the light. The attenuation of the light with distance from its position is given by ca, la, and qa which define the constant, linear and quadratic components of the attenuation factor. If d is the distance from the light to the surface, then the light's color at the surface is given by (r,g,b) * (ca + la*d + qa*d^2)^-1. Each cooeficient must be positive or equal to zero. Note: to achieve no attenuation use a (ca,la,qa) of (1,0,0).
The spot light cutoff is given by cs and defines the half angle of divergence of the light cone. It can be measured as the angle from the center axis to the edge of the spot cone. It should be less than pi/2 radians. The fall off in intensity from the center axis to the cone edge is given by the spot drop-off factor, sd. It can take values from 0.0 to 1.0, where 0.0 indicated constant intensity across the cone, and 1.0 yields a sharp fall-off. The cosine of the angle between light direction and the direction of a ray from (px,py,pz) to the point being lit, raised to the power of 128*sd will yield the correct result.
#light_dir r g b dx dy dz
This defines a directional light in the scene. (r,g,b) gives the color of the light. Note that we depart from the OpenGL convention of defining three colors for a light (one for each of ambient, diffuse, and specular properties.) In this ray tracer, use this single light color for diffuse and specular contributions at each surface. Do not compute ambient contributions from each light, but rather use the global ambient light defined by the ambient directive. Each instance must appear before any group directives.
(dx,dy,dz) is a unit vector giving the direction of the light in the scene. Note that attenuation makes no sense for directional lights, and so is not a parameter of this directive.
#texture_num n
The total number of textures used in the scene is given by this command. The command must appear before any texture AND/OR material definitions. Only the first incidence of this command is used, while subsequent instances are ignored. It must appear before any group directives. If there are no textures used, texture_num 0 need not be declared.
#texture filename
Each texture used in the scene is declared by the texture directive using the filename of the texture. The first texture declared will take the interger identifier 0, and subsequent textures will follow in order (i.e. 1, 2, 3, ...). This integer handle is used in material definitions to indicate that the material includes the respective texture. Textures need not be declared before materials, however texture_num must be called before any material declaration. This declaration must appear before any group directives.
#material_num n
The total number of materials used in the scene is given by this command. The command must appear before any material definitions. Only the first incidence of this command is used, while subsequent instances are ignored. This declaration must appear before any group directives.
#material ar ag ab dr dg db sr sg sb er eg eb ks kt ir tn !string!
Each material used in the scene is declared by the material directive. The first material declared will take the interger identifier 0, and subsequent materials will follow in order (i.e. 1, 2, 3, ...). This integer handle is used in shape definitions to indicate that the rendering should occur with the appropriate material. This declaration must appear before any group directives.
The colors (ar,ag,ab), (dr,dg,db), (sr,sg,sb), and (er,eg,eb) are the ambient, diffuse, specular, and emmisive colors of the material, respectively. The ambient material color is used in ambient light calculation with the global ambient light color, the diffuse and specular material colors are used in diffuse and specular lighting computations with the color of each light in the scene, and the emmisive material color acts independently of any light source.
ks defines the specular 'shininess' of the material, and takes values from 0.0 to 1.0. The cosine of the angle between the ray direction and the specular reflection direction raised to the power of 128*ks gives the OpenGL specular highlight factor. ks also defines the reflection coefficient for recursive reflection rays. kt is the transmission coefficient for recursive transmission rays, and ranges from 0.0 to 1.0. ks + kt need not total to 1.0. The index of refraction is given by ir and is used in Snell's Law computations for refraction direction. For non-closed surfaces, such as triangles, it is assumed that ir is the index of refraction on the backside of the surface. For closed surfaces, such as cones, it is assumed that ir is the index of refraction on the inside of the surface.
To assign a texture to this material, tn should be the integer handle of the appropriate texture declared in the file. At rending time, it is assumed that the color of the appropriate texture pixel will modulate the color computed by the lighting equation. If no texture is to be associated with the material, then a value of -1 must be indicated.
The final parameter is a string delimited by exclaimation marks. The string must not contain any control characters, or unpredicatable behaviour could occur. This field is provided for the users to assign material properties not defined by this file format. For instance, the numeric constants describing a Perlin Noise 3-D solid texture could be put in this field to instruct the rendered to how to texture shapes which are drawn with this material. If no unsupported parameters are required, empty exclamation marks must conclude the material declaration as follows: !!
#group_begin m11 m12 m13 m14 m21 m22 m23 m24
m31 m32 m33 m34 m41 m42 m43 m44
#group_end
This pair of directives defines a transformation context in which it is valid to specify shape_* objects to draw. All objects within the group_begin .. and associated group_end directive are subject to the 4x4 transformation matrix given in the group_begin declaration. Groups may be nested, permitting the specification of a transformation heirarchy. Shapes within nested groups are subject, in order, to the transformation contexts of all their enclosing groups. The total transformation context of a given shape is determined, then, by starting with the matrix of the root enclosing group, and concatenating additional matrices on the right as we decend into nested groups, until we reach the shape. The transformation context of a group is applicable only to its shapes and sub groups, so we must remove matrices from the right as we ascend back up the heirarchy. From an OpenGL stand point this is analagous to pushing the matrix state onto the stack and multiplying in a group's matrix as we enter it, and then poping the statck when we exit the group.
The matrix elements appear as follows and are intended to operate on column vectors:
|m11 m12 m13 m14|
|m21 m22 m23 m24|
|m31 m32 m33 m34|
|m41 m42 m43 m44|
Note: shape_* declarations can only occur within groups. Thus, even if no transformations are desired, a root group must still be defined to hold all the shapes. A group_begin 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 directive can be issued to define the root context with the identity transformation.
#shape_* m ...
All shapes that can be defined are prefixed by shape_ and take
a common first parameter m which indicates the integer handle of
the material to use when rendering the object. Subsequent descriptions
of the supported shapes will omit explanations of the m parameter...
#shape_sphere m cx cy cz r
This defines a sphere, situated at the point (cx,cy,cz) with a radius given by r.
#shape_box m cx cy cz lx ly lz
This defines an axis aligned box, centered at the point (cx,cy,cz). The length of the x, y, and z axis aligned sides is given by lx, ly, and lz, respectively. The box extends from x=cx-lx/2 to x=cx+lx/2, y=cy-ly/2 to y=cy+ly/2, and z=cz-lz/2 to z=cz+lz/2.
#shape_cylinder m cx cy cz r h
This defines a cylinder, with a central axis parallel to the y-axis, and centered at the point (cx,cy,cz). The radius and height are given by r and h, respectively. The cylinder is a closed surface (i.e. it has end caps.) The ends lie at y=cy-h/2 and y=cy+h/2.
#shape_cone m cx cy cz r h
This defines a cone, with a central axis parallel to the y-axis, and centered at the point (cx,cy,cz). The radius and height are given by r and h, respectively. The cone is a closed surface (i.e. it's base is capped) The base and apex of the cone lie at y=cy-h/2 and y=cy+h/2, respectively.
#shape_triangle m v1x v1y v1z v2x v2y v2z v3x v3y v3z n1x n1y n1z n2x n2y n2z n3x n3y n3z t1s t1t t2s t2t t3s t3t
This defines a triangle with vertices (v1x,v1y,v1z), (v2x,v2y,v2z),
and
(v3x,v3y,v3z). Associated, respectively, with each vertex are
are the normals (n1x,n1y,n1z), (n2x,n2y,n2z), and
(n3x,n3y,n3z). It is assumed that normals are of unit length.
Also associated, respectively, with each vertex are the texture coordinates
(t1s,t1t), (t2s,t2t), and (t3s,t3t). It
is assumed that the texture coordinate (0,0) maps to the lower left of
the associate texture map image, and that the positive s and t texture
coordinates axis extend in right and upward image directions, respectively.
Even if no texturing is desired for a given triangle, it is mandatory that
the 6 texture coordinate fields be present (so, add 0 0 0 0 0 0 after the
n3z
coordinate,
for instance.)