Now we're approaching the fundamental idea of VRML: some
nodes can be placed as a children of other nodes. We already
saw some examples of this idea in VRML 2.0 examples
above: we placed various nodes inside geometry
field of Shape
node. VRML 1.0 has a little different
way of specifying children nodes (inherited from Inventor format)
than VRML 2.0 and X3D — we will see both methods.
In VRML 1.0, you just place children nodes inside the parent node. Like this:
#VRML V1.0 ascii Group { Sphere { } Cube { width 1.5 height 1.5 depth 1.5 } }
Group
is the simplest grouping node.
It has no fields, and it's only purpose is just to treat a couple of nodes
as one node.
Note that in VRML 1.0 it's required that a whole VRML file consists of exactly one root node, so we actually had to use some grouping node here. For example the following file is invalid according to VRML 1.0 specification:
#VRML V1.0 ascii Sphere { } Cube { width 1.5 height 1.5 depth 1.5 }
Nevertheless the above example is handled by many VRML engines, including our engine described in this document.
In VRML 2.0, you don't place children nodes directly
inside the parent node. Instead you place children nodes inside
fields of type SFNode
(this contains
zero (NULL
) or one node) or
MFNode
(this contains any number (possibly zero)
of nodes). For example, in VRML 2.0 Group
node has an MFNode
field children
,
so the example file in VRML 2.0 equivalent to previous example looks like
this:
#VRML V2.0 utf8 Group { children [ Shape { geometry Sphere { } } Shape { geometry Box { size 1.5 1.5 1.5 } } ] }
Syntax of MFNode
is just like for other multiple-valued
fields: a sequence of values, inside brackets ([
and ]
).
Example above also shows a couple of other differences between VRML 1.0 and 2.0:
In VRML 2.0 we have to wrap
Sphere
andBox
nodes inside aShape
node.Node
Cube
from VRML 1.0 was renamed toBox
in VRML 2.0.Size of the box in VRML 2.0 is specified using
size
field of typeSFVec3f
, while in VRML 1.0 we had three fields (width
,height
,depth
) of typeSFFloat
.
While we're talking about VRML versions differences, note also that
in VRML 2.0 a file can have any number of root nodes. So actually
we didn't have to use Group
node in our example,
and the following would be correct VRML 2.0 file too:
#VRML V2.0 utf8 Shape { geometry Sphere { } } Shape { geometry Box { size 1.5 1.5 1.5 } }
To be honest, we have to point one more VRML difference: as was mentioned before, in VRML 2.0 shapes are unlit by default. So our VRML 2.0 examples above look like this:
To make them lit, we must assign a material
for them. In VRML 2.0 you do this by placing a Material
node inside material
field of Appearance
node. Then you place Appearance
node inside
appearance
field of
appropriate Shape
node. Result looks like this:
#VRML V2.0 utf8 Group { children [ Shape { appearance Appearance { material Material { } } geometry Sphere { } } Shape { appearance Appearance { material Material { } } geometry Box { size 1.5 1.5 1.5 } } ] }
We didn't specify any Material
node's fields,
so the default properties will be used. Default VRML 2.0 material properties
are the same as for VRML 1.0: light gray diffuse color and a slight
ambient color.
As you can see, VRML 2.0 description gets significantly more verbose than VRML 1.0, but it has many advantages:
The way how children nodes are specified in VRML 2.0 requires you to always write an
SFNode
orMFNode
field name (as opposed to VRML 1.0 where you just write the children nodes). But the advantages are obvious: in VRML 2.0 you can explicitly assign different meaning to different children nodes by placing them within different fields. In VRML 1.0 all the children nodes had to be treated in the same manner — the only thing that differentiated children nodes was their position within the parent.As mentioned earlier, the default behavior of various VRML 2.0 parts is the one that is the easiest to render. That's why the default behavior is to render unlit, and you have to explicitly specify material to get lit objects.
This is a good thing, since it makes VRML authors more conscious about using features, and hopefully it will force them to create VRML worlds that are easier to render. In the case of rendering unlit objects, this is often perfectly acceptable (or even desired) solution if the object has a detailed texture applied.
Placing the
Material
node inside theSFNode
field ofAppearance
, and then placing theAppearance
node inside theSFNode
field ofShape
may seem like a “bondage-and-discipline language”, but it allows various future enhancements of the language without breaking compatibility. For example you could invent a node that allows to specify materials using a different properties (like by describing it's BRDF function, useful for rendering realistic images) and then just allow this node as a value for thematerial
field.Scenario described above actually happened. First versions of VRML 97 specification didn't include geospatial coordinates support, including a node
GeoCoordinate
. A nodeIndexedFaceSet
has a fieldcoord
used to specify a set of points for geometry, and initially you could place aCoordinate
node there. When specification of geospatial coordinates support was formulated (and added to VRML 97 specification as optional for VRML browsers), all that had to be changed was to say that now you can placeGeoCoordinate
everywhere where earlier you could use onlyCoordinate
.The
Shape
node in VRML 2.0 contains almost whole information needed to render given shape. This means that it's easier to create a VRML rendering engine. We will contrast this with VRML 1.0 approach that requires a lot of state information in Section 1.5, “VRML 1.0 state”.
Let's take a look at another grouping node:
VRML 2.0 Transform
node. This node specifies a transformation (a mix
of a translation, a rotation and a scale) for all it's children nodes.
The default field values are such that no transformation actually
takes place, because by default we translate by (0, 0, 0) vector,
rotate by zero angle and scale by 1.0 factor. This means that
the Transform
node with all fields left as default
is actually equivalent to a Group
node.
Example of a simple translation:
#VRML V2.0 utf8 Shape { appearance Appearance { material Material { } } geometry Box { } } Transform { translation 5 0 0 children Shape { appearance Appearance { material Material { } } geometry Sphere { } } }
Note that a child of a Transform
node
may be another Transform
node. All transformations
are accumulated. For example these two files are equivalent:
#VRML V2.0 utf8 Shape { appearance Appearance { material Material { } } geometry Box { } } Transform { translation 5 0 0 children [ Shape { appearance Appearance { material Material { } } geometry Sphere { } } Transform { translation 5 0 0 scale 1 3 1 children Shape { appearance Appearance { material Material { } } geometry Sphere { } } } ] }
#VRML V2.0 utf8 Shape { appearance Appearance { material Material { } } geometry Box { } } Transform { translation 5 0 0 children Shape { appearance Appearance { material Material { } } geometry Sphere { } } } Transform { translation 10 0 0 scale 1 3 1 children Shape { appearance Appearance { material Material { } } geometry Sphere { } } }
A
Switch
node allows you to choose only one (or none) from children nodes to be in the active (i.e. visible, participating in collision detection etc.) part of the scene. This is useful for various scripts and it's also useful for hiding nodes referenced later — we will see an example of this in Section 1.4, “DEF / USE mechanism”.A
Separator
and aTransformSeparator
nodes in VRML 1.0. We will see what they do in Section 1.5, “VRML 1.0 state”.A
LOD
node (the name is an acronym for level of detail) specifies a different versions of the same object. The intention is that all children nodes represent the same object, but with different level of detail: first node is the most detailed one (and difficult to render, check for collisions etc.), second one is less detailed, and so on, until the last node has the least details (it can even be empty, which can be expressed by aGroup
node with no children). VRML browser should choose the appropriate children to render based on the distance between the viewer and designated center point.A
Collision
node is available in VRML 2.0 and X3D. It's very useful to disable collisions for particular shapes (visible but not collidable geometry), or to specify a “proxy” shape to be used for collisions. “Proxy” can be used to perform collisions with a complicated 3D object by a simpler shape, for example a complicated statue of a human could be surrounded by a simple box proxy for the sake of collisions. Also, this can be used to make collidable but invisible geometry.