Our engine handles both VRML 1.0 and VRML 2.0. As we have seen in Chapter 1, Overview of VRML, there are important differences between these VRML versions. The way how I decided to handle both VRML versions is the more difficult, but also more complete approach. Effectively, you have the sum of VRML 1.0 and 2.0 features available.
I decided to avoid trying to create some internal conversions from VRML 1.0 to VRML 2.0, or VRML 2.0 to 1.0, or to some newly invented internal format. I wanted to have a full, flexible, 100% conforming to VRML 1.0 and VRML 2.0 specifications engine. And the fact is that any conversion along the way will likely cause problems — ideologically speaking, that's because there is always something lost, or at least difficult to recover, when a complicated conversion is done.
Practically here are some reasons why a simple conversion between VRML 1.0 and VRML 2.0 is not possible, in any direction:
VRML 2.0 specification authors intentionally wanted to simplify some things that people (both VRML world authors and VRML browser implementors) thought were unnecessarily complicated in VRML 1.0. This causes problems for a potential converter from VRML 1.0 to 2.0, since it will have trouble to express some VRML 1.0 constructs. For example:
In VRML 1.0 you can specify multiple materials for a single geometry node. In VRML 2.0 each geometry node uses at most one material. So a potential converter from VRML 1.0 to 2.0 may need to split geometry nodes.
In VRML 1.0 you can accumulate texture transformations (
Texture2Transform
nodes). In VRML 2.0 you can't (you can only place oneTextureTransform
node in theAppearance.textureTransform
field). So a potential converter must accumulate texture transformations on it's own. And this is not trivial in a general case, because you can't directly specify texture transformation matrix in VRML 2.0. Instead you have to express texture transformation in terms of one translation, one rotation and one scaling.In VRML 1.0 you can specify any 4x4 matrix transformation using
MatrixTransformation
node. This is not possible at all in VRML 2.0. In VRML 2.0 geometry transformation must be specified in terms of translations, rotations and scaling.In VRML 1.0 you can limit which geometry nodes are affected by
PointLight
orSpotLight
by placing light nodes at particular points in the node hierarchy. That's because in VRML 1.0 light nodes work just like other “state changing” nodes: they affect all subsequent nodes, until blocked by the end of theSeparator
node.In VRML 2.0 this doesn't work. You cannot control what parts of the scene are affected by light nodes by placing light nodes at some particular place in the node hierarchy. Instead, you have to use
radius
field of light nodes. This means that some VRML 1.0 tricks are simply not possible.OrthographicCamera
is not possible to express using VRML 2.0 standard nodes.
Summary: in certain cases translating VRML 1.0 to 2.0 can be very hard or even impossible. If we want to handle VRML 1.0 perfectly, we can't just write a converter from VRML 1.0 to 2.0 and then define every operation only in terms of VRML 2.0.
On the other hand, VRML 2.0 also includes various things not present in VRML 1.0. This includes many new nodes, that often cannot be expressed at all in VRML 1.0: all sensors, scripts, interpolators, special things like
Collision
andBillboard
.Moreover, VRML 2.0 uses
SFNode
(with possibleNULL
value) andMFNode
, and generally reduces the state that needs to be remembered when processing VRML graph. This means that many existing features have to be expressed differently.For example consider specifying normals for
IndexedFaceSet
. In VRML 2.0 everything that decides about how generated normals are supplied are thenormal
andnormalIndex
fields of givenIndexedFaceSet
node. We take advantage of theSFNode
field type, and say that wholeNormal
node may be just placed withinnormal
field ofIndexedFaceSet
. So we just keep whole knowledge insideIndexedFaceSet
node.On the other hand, in VRML 1.0 we have to use the value of last
NormalBinding
node. This says whether we should use the lastNormal
node, and how.Potential VRML 2.0 to 1.0 converter would have to make a lot of effort to “deconstruct” VRML 2.0 shape properties back to VRML 1.0 state nodes. This makes conversion difficult to revert (e.g. when we want to write VRML 2.0 content back to file).
That's why I decided to support in my engine the sum of all VRML features.
For example, VRML 1.0 nodes can have direct children nodes, so I support it
(by Children
property of TVRMLNode
).
VRML 2.0 nodes can have children nodes through SFNode
and MFNode
fields, so I support it too.
I'm not trying hard to “combine”
these two ideas (direct children nodes and children inside
MFNode
) into one
— I just implement and handle them both
[8].
In some cases this approach forces me to do more work. For example, for many routines that calculate bounding boxes of geometry nodes, I had to prepare three routines:
Common implementation, as a static procedure inside the
X3DNodes
unit. This handles actual calculation and as parameters expects already calculated properties of given shape. As a simple example, when calculating bounding box of a cube, we expect to get three parameters describing cube's sizes in X, Y and Z dimension.VRML 1.0 implementation in VRML 1.0-specific node version that calls the common implementation, after preparing parameters for common implementation. As a simple example,
TNodeCube_1
(VRML 1.0 cube) just uses it'sFdWidth
,FdHeight
andFdDepth
as appropriate sizes.And VRML 2.0 implementation in VRML 2.0-specific node version, that also calls the common implementation after preparing it's parameters. As a simple example,
TNodeBox
(VRML 2.0 cube) accesses three items of it'sFdSize
field to get the appropriate sizes.
In our simple example above we talked about a cube,
and the whole issue with calculating three size values differently
for VRML 1.0 and 2.0 was actually trivial.
But the point is that for some nodes,
like IndexedFaceSet
, this is much harder.
For VRML authors this “sum” approach means that when reading VRML 1.0, many VRML 2.0 constructs (that not conflict with anything in VRML 1.0) are allowed, and the other way around too. That's why you can actually mix VRML 1.0 and 2.0 code in my engine.
Update in 2022: As VRML 1.0 format is now ancient and maintaining it has been some work, this "sum" feature has been a little "downgraded". It is still possible to use many VRML 2.0 / X3D nodes in VRML 1.0, but not the other way around. That is, you can no longer use VRML 1.0 nodes in files declared as VRML 2.0 / X3D.
This also means that you have many VRML 2.0 features available
in VRML 1.0. VRML 2.0 nodes like Background
,
Fog
and many others, that express features not available
at all in standard VRML 1.0, may be freely placed inside VRML 1.0 models
when using our engine.
Also including (using WWWInline
or
Inline
nodes) VRML 1.0 files within VRML 2.0
files (and the other way around) is possible. Each VRML file will
be parsed taking into account it's own header line, and then included
content is actually placed as a children node of including
WWWInline
or Inline
node.
So you get VRML graph hierarchy with nodes mixed from both VRML versions.
[8] SmartChildrenXxx
properties
mentioned in the previous section somewhat combine
VRML 1.0 and 2.0 ideas of children nodes, but they are generally not used
except in some small pieces of code where they just make the code
shorter.