Studierstube uses the Open Inventor file format for the input files that define
an application's content and behavior. OIV files follow a structured ASCII-based
syntax, allowing the author to define an application's scene graph. Inventor
files generally have the extension .iv .
All Inventor files are required to have the same first line
#Inventor V2.0 ascii
that identifies them as containing data in the Open Inventor file format.
Extra whitespace characters like blanks, tabs or newlines are ignored. It is possible and very advisable to use plenty of whitespace and comments to structure your IV-files, improving their readability for humans, and making it easier to find parts of your scene.
Comments start with the # character. All content after that character
until the end of the line is ignored by the parser (except for the very first
line in the file stating the file format and version).
A node is represented in the file by its class name (for built-in OIV nodes,
the So prefix of the class name can be omitted), an opening
brace ({),
the fields of the node and their values (if any), and a closing brace (}).
For example:
Cube {
width 0.1
depth 0.1
height 0.1
}
Defines a cube that measures 10 cm in each dimension.
The individual values of a vector-type field (Vec3f, Rotation,...)
are seperated by whitespace, multiple values of a MF-field are
enclosed in square brackets ([ ]) and seperated by commas. Strings
must be enclosed in quotation marks if they contain a whitespace character.
Examples:
Transform {
translation 0 0 1 # Single Vector value (0,0,1)
}
Material {
diffuseColor [1 0 0, 0 1 0, 0 0 1] # 3 Color values: red, green and blue
}
Text3 {
string "This is a String." # Single String value
}
Note that all fields that are not specified explicitly are always set to their
default value. This means that all fields of a node will always be used, even
if not listed in the input file. If you want to use just a subset of a node's
fields, and suppress the influence of other fields, you can set the ingore flag
by appending a tilde (~) character. To change only the transparency,
but not the base color and other properties of the current material, you would
use for example:
Material {
transparency 0.5 # Make all subsequent geometry semi-transparent
diffuseColor ~ # ignore these fields
specularColor ~
ambientColor ~
emissiveColor ~
shininess ~
}
Group nodes are nodes that can contain other nodes, called children. A group node is defined by specifying the node type, an open brace, the node's fields (if any), the node's children, and a closing brace. This results in a nested syntax for trees of nodes:
Group { # Group node (no fields)
Group { # 1st child
Cube {}
Sphere {}
}
Group { # 2nd child
Sphere {}
Cube {}
}
}
Group nodes are useful for creating sub-scenegraphs that can be referenced
and re-used in other locations, and for controlling traversal (e.g. rendering)
behaviour. The basic group node is called Group, and has no side
effects besides grouping its children together. The different other group nodes
and their effects on traversal are explained in section 2.
Node Kits are nodes that encapsulate a scene graph, acting as a template for possibly complex arrangements of nodes that can be reused easily. Node kits can only be implemented in C++ (see section "Extending Open Inventor"), and from a scripting perspective they look like nodes with SFNode fields. Internally, these special fields, called parts, are leaf nodes of the encapsulated scenegraph. The main difference between a part and a SFNode field is that parts are part of the scene graph structure and will be traversed, whereas SFNode fields are just fields of a node and will not be traversed by any action (including rendering).
In the file format, node kits are written like normal nodes, and parts are written like SFNode fields - the part name followed by the node definition. For example:
ShapeKit {
transform Translation { translation 0 1 0 }
shape Sphere {}
# both parts are part of the scenegraph and will be traversed.
# This will render a Sphere at position 0 1 0
}
While the node kits built into Open Inventor are rarely used, a lot of Studierstube classes are node kits. In the documentation, this will be indicated by putting the type of the part in brackets.
A single node can be used multiple times in the scene graph - this is very useful if the same objects should be rendered multiple times in different locations, or you want to reuse other things like textures or transformations without having to redefine them. This does not only save typing work and makes your code more readable, but it also saves memory - the node is only stored once and just referenced from other parent nodes. An natural consequence of this is that any change done to the node will affect all its occurences in the scene graph.
To make a node referencable, the node has to be given a unique name. The name
is assigned to the node by putting the DEF keyword, followed by
chosen name, in front of the definition of the node. Names must start with an
uppercase or lowercase letter or an underscore, followed by digits (0..9), uppercase
or lowercase letters and underscores. For example
DEF _MyCube1 Cube { # define a cube named _MyCube1
width 0.1
depth 0.1
height 0.1
}
Defines a cube and assigns it the valid name _MyCube1.
To reference an already existing node in the scenegraph, you use the USE keyword, followed by the name:
DEF _MyCube1 Cube { # define a cube named _MyCube1
width 0.1
depth 0.1
height 0.1
}
DEF mat1 Material { diffuseColor 1 0 0 } # define the Material mat1
Transform { translation 0.5 0 0 } # translate position
USE _MyCube1 # reference the Cube defined above
Will render the cube a second time, in a different color and at a different location.
Similar to whole nodes, also single fields can be referenced in other nodes.
This creates a field connection between the referenced field and the
target field, updating the target field whenever the referenced field changes.
Field references are composed of the DEF name of the containing
node, a dot and the name of the field to be referenced. References are assigned
to a field by using the = sign, after a possible default value,
followed by the USE keyworkd and the field reference. For example:
DEF trans1 Transform {
translation 0 0 1
}
Cube {}
DEF trans2 Transform {
translation 0 0 0 = USE trans1.translation # trans1's translation value is connected here
}
Sphere {}
In this example, it is sufficient to change trans1.translation
to update both translation values.
Note that field connections introduce a second graph-structure, which is orthogonal to the scene graph, into your application: the dependency graph. The dependency graph models the dependency of fields from other fields in the scene graph. If a field changes, the dependency graph forwards the field change to all connected fields, which are also updated.