Scenefiles are the way we specify the information needed to generate 3D scenes in this class. The structure documented here is specific to the way our scene parser was designed. Once lab 5 is released, you can refer to it for complementary information/specific examples.
The structure of the scenefile is organized as a declaration of the global data, camera, lights, and objects. Scenes are specified in xml format. The general format of the file is as follows:
<scenefile> <globaldata> ... </globaldata> <cameradata> ... </cameradata> <lightdata> ... </lightdata> ... <lightdata> ... </lightdata> <object type="tree" name="value"> <transblock> <!--transformations--> <object> ... </object> </translbock> ... </object> ... <object type="tree" name="value"> ... </object> </scenefile>
The value types for each field in this documentation are defined as follows where
value is your value for that field. Note that each value must be enclosed in quotation marks such as
"root". Note that all angle values are expected to be in degrees.
float— a single floating point number with syntax:
vector— three floating point numbers that represent a vector for a displacement, axis of rotation, or scaling factors in the x-y-z plane with syntax:
x="value" y="value" z="value"
color— three floating point numbers that represent a color in the red-green-blue (values 0-1) color space with syntax:
r="value" g="value" b="value"
function— three floating point numbers that allow one to specify the coefficients of the constant, linear, and quadratic term in a function, respectively, with syntax:
v1="value" v2="value" v3="value"
Your scenefile will still work if you leave this section out. It allows the scenefile writer to specify certain constants used while rendering. Each of the coefficients has a certain place in the lighting equation; they are all floating point constants that are used to scale the diffuse, ambient, transparent, and specular components respectively. These constants are helpful for scenes with very few or very many lights.
<globaldata> <diffusecoeff float/> <ambientcoeff float/> <transparentcoeff float/> <specularcoeff float/> </globaldata>
There can only be one camera in the scene. If none is specified a default camera will be used. In a camera block, there must be listed the position (
pos), look vector (
look), up vector (
up), and height angle (
angle). Note that it is possible to replace the look vector with a focal point (denoted by the keyword
focus), if so desired. Also note that the two fields for aperature and focal length are optional and only need to be included when implementing certain extra credit features.
<cameradata> <pos vector/> <focus vector/> <look vector/> <up vector/> <heightangle float/> <aperature float/> <focallength float/> </cameradata>
lighttype can be defined as a point, directional, spot or area light. If none is given, the light type will default to a point light. There can be up to 8 lights in the scene, and each light should be defined in its own subsection. The id of a particular light is a float where the value is its index from 0 to 7.
Every point light should define a
position, its actual position of the light in the scene, and a
color, the color of the light in rgb. Directional lights will not have a position - they will instead have a
direction. Spotlights, or cone shaped lights, need both
direction, as well as
penumbra. Lastly, there is a parameter,
function, that allows one to specify the coefficients of the lighting function.
<lightdata> <id float/> <type lighttype/> <position vector/> <color color/> <function function/> <direction vector/> <penumbra float/> </lightdata>
Objects & Transformations
Objects and Transformations are located at the bottom of our scenefile and hold all the shapes that, when combined, build our scene. On the outer layer, we have can have any number of trees which are explained in more depth below. However, every object besides the outer most layer tree must be wrapped in a transformation block that details where that object or group of objects will go. Let's go over transformations first.
Each nested object in the scene must be immediately surrounded by a transformation block. The first portion of a transformation block is a list of the transformations that will be applied to the object within. The other part of a transformation block is the object itself. There can be only one object per transformation block, though the object can be of any type (types defined below), and nothing should follow the object. If anything is found after the first object in a translation block, it should be ignored.
<transblock> <!--your transformations here--> <object type=type object=object> ... </object> </transblock>
You can use any number of any of these listed transformations in any order at the location marked "your transformations here", but typically you will only use either the transformation vectors or the transformation matrices per transformation block. They will be executed in the reverse order that they are listed, meaning that the last transformation type listed will be the first to be applied to the enclosed object.
rotate- a rotation angle represented as a float follows the rotation vector
<rotate vector float/>
matrix- in row-major order
<matrix> <row0 v1="value" v2="value" v3="value" v4="value" /> <row1 v1="value" v2="value" v3="value" v4="value" /> <row2 v1="value" v2="value" v3="value" v4="value" /> <row3 v1="value" v2="value" v3="value" v4="value" /> </matrix>
There are three main types of objects -
Primitives are the most basic object and are at the lowest level what the scene is comprised of. Primitives are those which represent three-dimensional shapes, namely,
meshes, which we specify the type of in the object field of the primitive.
Primitives contain in their block a combination of optional surface characteristic definitions: diffuse color
diffuse, ambient color hack
ambient, reflected color
reflective, specular color
specular, specular exponent
transparent, and index of refraction
ior. There is also the ability to provide
texture to an object using a bitmap or to use a
bumpmap. Both of these fields have optional u,v coefficient fields for the scaling of the texture which both default to a value of 1 if not specified.
<object type="primitive" object="shape"> <diffuse color/> <specular color/> <ambient color/> <reflective color/> <transparent color/> <shininess float/> <blend float/> <texture file="path\to\file" u="value" v="value"/> <bumpmap file="path\to\file" u="value" v="value"/> </object>
Note that meshes have their own object definition with an additional
meshfile field which looks like this:
<object type="primitive" object="mesh" meshfile="path\to\mesh"> ... </object>
Masters are trees(more below) that essentially act as instance variables in our scene and are typically used when the same set of objects and transforms are repeated throughout a scene. They are originally defined as type
tree and are referred to as type
master when being instantiated. These masters must all be defined ahead of the tree in which they are used, and they must be given a unique name which is used to reference the master during instantiation. Masters can also be nested, so masters can contain other masters. Here's an example of defining and using a
<object type="tree" name="mymaster"> <transblock> <!--my primitive--> </transblock> ... </object> <object type="tree" name="mymasterlevel2"> <transblock> <!--some transformations--> <object type="master" name=mymaster" /> </transblock> <transblock> <!--some transformations--> <object type="master" name=mymaster" /> </transblock> <transblock> <!--some transformations--> <object type="master" name=mymaster" /> </transblock> </object>
Trees are more complex structures that our scenefile uses to place
masters into the scene. A tree can contain any number of transformation blocks, and we can also nest trees within transformation blocks to group transforamtions for a set of objects and build more complex scenes. Since trees are a type of object, they can be nested in the same way that our
masters are in that they are surrounded by a transformation block. Our scene is defined in one
root tree which can be composed of other sub-trees, primitives, and/or masters. The name
"root" should be reserved for the main scene graph and signifies to our parser that all masters have been declared.
Comprehensive Objects & Transformations Sample
Below we have a root tree that uses a primitive object, a master, and a subtree.
<object type="tree" name=mymaster> <transblock> <!--some transformations--> <object type="primitive" object=object> <diffuse color/> <specular color/> </object> </transblock> <transblock> ... </transblock> ... </object> <object type="tree" name="root"> <transblock> <!--some transformations--> <object type="primitive" object="shape"> ... </object> </transblock> <transblock> <!--some transformations--> <object type="master" name="mymaster"> ... <object/> </transblock> <transblock> <!--some transformations--> <object type="tree" name="mysubtree"> <transblock> <!--some transformations--> <object type="primitive" object="shape"> ... </object> </transblock> <transblock> <!--some transformations--> <object type="tree" name="mysecondsubtree"> ... <object/> </transblock> ... <object/> </transblock> ... </object>
This format is not as all-encompassing as it could be, but this is intentional as one of the major aims is for it to be simple to parse.