Frames and Leafs
This document is part of a collection of VRML2.0 history at http://www.mitra.biz/vrml/vrml2/mw_history.html
1st December 95, 9pm
Mitra <mitra@mitra.biz>
Gavin Bell gavin@engr.sgi.com
Review status
Note to other reviewers. Please send additions, to me, or changes. I'll
cut and paste them into the document with your name attached.
-
Tony: Has reviewed this in principal, and is in support of it - will add
comments in detail Friday.
-
Gavin: Reviewed, agreed in principal, several major disagreements noted
below.
Main changes since previous version(s)
-
1st December 95
-
Added Gavin's responses, either by making the change, or incorporating
his and my comments.
-
Renamed Object to Leaf
-
Moved transform fields up into Frame.
Outstanding Major Open Issues
Separators and Groups NOT
This is a proposal to replace Separators and Groups with a system that
meets these goals:
-
Fits in better with existing rendering libraries
-
Simpler to implement, explain.
-
Likely to be higher performance
-
May make authoring systems easier to implement
-
Likely to have a smaller memory "footprint"
-
Makes multi-processed rendering easier
-
Mitra: is easily moved to from VRML1.0
-
Mitra: gives us the basis for a more object oriented approach in
the future, in particular regarding behaviors.
Overview
This proposal removes Separators and Groups, and replaces them with Frames
and Leafs. A scene graph consists of a hierarchy of frames, with Leafs
at the leaf nodes. State which accumulates down the hierarchy (basically
only transforms is kept at the Frame level). Properties and Geometry are
kept at the Leaf level.
We have the following concepts:
-
Frames: Define geometric coordinate systems. Consist of a coordinate
and texture coordinate transformation (either of which may be the identity
transformation) and a set of zero or more children, which may be either
Frames or Leaves.
-
Leaves: shapes, -- things that exist in one or more coordinate systems
(Frames), and which may have properties associated with them.
Gavin: Adds lights and cameras here.
-
Properties: characteristics of shapes that affect how they are drawn--
materials, textures, font styles, shape hints.
-
Nodes: things that can be DEF/USE'ed or prototyped, and may have
fields that can be affected by behaviors.
Open issue
-
Leaf node, or adding property fields to Nodes like Cube
-
Properties as SFNODE fields, or syntactically as children
-
Gavin
I see no need for the "Object" class; it exists only to gather up Leaves
and Properties, and I think it is simpler to just put the properties directly
in the Leaf classes. I'd rewrite the first example as:
Frame {
translation 1 0 0
Frame {
translation 0 1 0
Cube {
texture Texture2 { ... }
material Material { .... }
}
}
}
I like to enforce rules like: "While the Object may have multiple Geometry
nodes specified, it may only have one each of the Properties nodes" ...
in the syntax by giving the Leaf nodes fields containing the appropriate
properties.
Mitra
I believe it is usefull to create a new node "Leaf", for the following
reasons.
-
It allows us to retain much of the syntax of existing VRML.
-
Adding new properties would not require redefining every Leaf node.
-
It allows a geometry to be composed of a collection of different primitives.
An orthogonal issue is whether to use SFNODE fields for things like "Texture2".
-
The syntax of specifying fields as "texture Texture2 {}" is really ugly,
and unneccessarily verbose.
-
Making "texture" an SFNODE field, opens up a lot of possibilities which
I think should be excluded because they require browsers to keep these
around as specific nodes.
An example:
Frame {
translation 1 0 0
Frame {
textureRotation 3.1415
Leaf {
Texture2 { ... }
Material { .... }
Cube { }
}
}
}
Note: Any nodes below the Leaf level are for syntactical reasons only,
and it cannot be assumed that a browser keeps them around in that form.
While the Leaf may have multiple Geometry nodes specified - e.g. an
IndexedFaceSet and Coordinate's and Normals and a Cube, it may only have
one each of the Properties nodes.
It should be easy to write a Perl, or QvLib program that transforms
VRML1.0 to this new scheme.
Where do nodes go
Nodes fit into several categories:
-
Transforms that are incorporated into Frame, and no longer valid
-
Transform - fields directly in Frame
-
Texture2Transform - fields are prepended e.g. textureTranslation textureRotation
-
Rotation, Scale, Translation - they were equivalent to Transform anyway
-
MatrixTransform Open
-
Gavin: MatrixTransform can cause massive implementation headaches, so I
want to get rid of it. If people really really want to keep MatrixTransform,
we could define a Frame (that corresponds to a Transform) and a MatrixFrame
that has matrices for defining the coordinate (and textureCoordinate, if
we want to be general) transformations. I think behaviors are going to
have to know whether or not a Frame is a general matrix or the restricted
translation/rotation/scale anyway.
-
Mitra: I'm open to this but seem to remember that there were major objections
from the mathematical community last time to this? MatrixFrame sounds like
a good idea.
-
CollideStyle Open
-
Gavin: that is a tough one, because you DO typically want to take all of
the geometry of a coordinate system and either turn collisions on/off (which
is very much like a property) or give a simpler representation against
which collisions should be done (which is possibly hierarchical and is
very much like LOD...).
-
Mitra: I suggest adding the fields of CollideStyle to Frame
-
NavigationInfo Open
-
Gavin: I think is just like an Info node, and applies to everything in
a world (browsers will have to decide what to do with nested worlds).
-
Mitra: My recollection is that NavigationInfo is a property of a Separator,
and effects everything inside that point, so that once a camera entered
a sub-world it could be slowed down for example. I do NOT believe this
can be left to browsers - its an authoring decision, although I would be
happy to restricting it to one per file (i.e. WWWINline your sub-world).
- Unsure, I beleive it applies to everything inside a Frame, maybe
this belongs as an alternative to a Frame? (as with LOD, Switch etc)
-
Properties that may occur at most once in an Leaf
-
FontStyle Open
-
Gavin: FontStyle applies only to AsciiText, so I think that AsciiText should
have a fontStyle SFNode field that points to the FontStyle node to use.
Why? Because I find that it is almost always worthwhile to "define-away"
meaningless constructions by changing syntax, if possible. This: Object
{ FontStyle { ... } Cube { } } ... is meaningless. This: Text { fontStyle
DEF FONT_STYLE_1 FontStyle { ... } } ... makes sense, and allows easy sharing
of the font style: Text { fontStyle USE FONT_STYLE_1 }
-
Mitra: Merging FontStyle into AsciiText makes sense, I'd prefer to just
move the fields of FontStyle into the AsciiText node.
-
Material
-
ShapeHints
-
Texture2
Open
-
Gavin: Material/Texture2 make sense for AsciiText and IndexedFaceSet; I
can imagine arguments on whether or not they make sense for IndexedLineSet
and PointSet (OpenGL allows textured and/or lit lines and points). I like
the idea of explicitly adding material and texture SFNode fields to all
the shapes, though, because I think strong arguments can be made that IndexedLineSet
and PointSet should have ONLY colors, not materials or textures-- and it
is clear how to do that in a design that makes the properties explicit.
Certainly ShapeHints makes sense only for IndexedFaceSet (creaseAngle
or SOLID PointSets are meaningless).
AsciiText: Rename to Text (since we're going UTF-8 internation)
fields: existing fields +
SFNode fontStyle # Must contain a FontStyle-type node
SFNode texture
SFNode material
Cone/Cube/Cylinder/Sphere/GeneralCylinder
fields: existing +
SFNode material
SFEnum materialBinding (except for Sphere)
SFNode texture
ElevationGrid/IndexedFaceSet/IndexedLineSet/PointSet
fields: existing fields +
MFVec3f coordinate
MFVec3f normal
SFEnum normalBinding
SFNode material
SFEnum materialBinding
SFNode texture
MFVec2f textureCoordinate
+ SFNode shapeHints (or fields of ShapeHints) for IndexedFaceSet
Coordinate3, Normal, NormalBinding, TextureCoordinate2, MaterialBinding:
removed, replaced by above fields.
-
Mitra: While I have no problem with making properties fields of the Leaf
(or into the shape nodes if Gavin's proposal is accepted), (except possibly
for the dificulty of adding new properties), I have a strong objection
with making them SFNODE fields (see Overview.
Also note - I agree with the matching of properties with nodes listed
above except:
-
Cone/Cube/Cylinder/GeneralCylinder also need ShapeHints for backface culling
of Cubes etc,
-
GeneralCylinder (and maybe Cube, Cone) is going to need the CreaseAngle.
-
ElevationGrid is going to need ShapeHints
-
Geometries that may occur multiple times as children of an Leaf
-
AsciiText (renamed to Text as we go UTF8)
-
Cone
-
Coordinate3
-
Cube
-
Cylinder
-
ElevationGrid
-
GeneralCylinder
-
IndexedFaceSet
-
IndexedLineSet
-
Normal
-
NormalBinding
-
PointSet
-
Sphere
-
TextureCoordinate2
Open: While we are all agreed on these being the "Geometry" nodes,
see Overview for arguments as to how they should
appear syntactically.
-
Nodes that may occur multiple times as children
of a Frame
-
DirectionalLight and PointLight and SpotLight
-
DirectedSound and PointSound
-
OrthographicCamera and PerspectiveCamera
Open
-
Gavin: Lights, sounds, cameras, Info: are "Leafs".
-
Mitra: I think Lights and Sounds belong as properties of frames, because
they effect everything underneath that frame.
-
Nodes that may occur anywhere
-
Nodes that are no longer valid
-
Group
-
Separator
-
Did we deprecate any other nodes between 1.0 and 1.1?
-
Nodes that act as a Frame, i.e. they are children of Frames, and may contain
Frames or Leafs
-
LOD
-
Switch
-
WWWAnchor
-
WWWInline (there is some debate over this)
-
Nodes that may occur at most once
-
Background
-
Environment
-
WorldInfo
Open
-
Gavin: (These) are also "Leafs", but only first one in world has any affect
on browser.
-
Mitra: We might want to constrain these to occur in the top-most frame
of a world.
-
Also see comments on NavigationInfo
Interesting issues
Open DEF & USE and Reuse of textures, materials
etc
-
Mitra:
DEF and USE of Frame's and Leafs is not affected by this proposal however
because we want browsers to be able to convert the format below the Leaf
level, we don't want DEF being used on Texture2 nodes etc.
However now that textures, and materials are specified on the Leaf,
we want to be able to indicate somehow to the browser when two textures
are identical, significant optimisation depends on this, even if it doesn't
save any significant memory or bandwidth.
A solution is to extend the use of the "IS" keyword that is used in
Prototyping. For example:
DEF Foo1 Leaf { Texture2 { filename "brick.gif" }
DEF Foo2 Leaf { Texture2 IS Foo1.Texture2 }
A possible - but rejected - syntax would be.
DEF Foo3 Leaf { Texture2 { filename IS Foo1.Texture2.filename } }
Note this syntax is unambiguous because the Leaf can have only one Texture2.
The related question, is what happens if we change things. The semantics
(however implemented) should be such that Foo.Texture2 is treated as a
pointer, so that for example:
Foo2.Texture2.filename := "clay.gif"
Will change the Texture of both Foo1 and Foo2, whereas
Foo2.Texture2 := Foo4.Texture2
Will change the pointer at Foo.Texture2 to point at Foo4's Texture2, but
will not change Foo1 in any way.
Gavin
DEF/USE are meant to indicate shared instancing, I think it is a mis-use
of 'IS' to share textures/materials. I also don't see any need to complicate
whatever behavior mechanism we come up with to handle "node.part.subpart"
names. It is much simpler to just say that behaviors can affect the fields
of nodes, and define Texture/Material as nodes. In which case: DEF Foo2
Cube { texture DEF Brick Texture2 { ... } } DEF Foo3 Cube { texture USE
Brick } ... If I want to make Foo2 use a different texture I write: Foo2.texture
:= AnotherTexture ... and if I want to re-define Brick I write: Brick.filename
:= "zBrick.gif" And it is ABSOLUTELY necessary to share textures to save
memory; textures can easily eat up lots of memory. This is especially critical
today on high-end machines that have a limited amount of texture memory
down on the graphics subsystem and where downloading textures from main
system memory to the graphics hardware can easily become a bottleneck.
Tony: Thinks this is of marginal use for optimisation (doesn't apply in
most renders) for the overhead of supporting this where it is not supported,
and these two seperate textures have to be kept in line.
Open Animating Textures
-
Mitra:
An example is frequently used of how to animate a texture, such that
the animation doesn't get run multiple times. In the example above, the
output of the animation script would be used to set Foo1.Texture2.image.
Note that there is no need to combine the ScriptNode AND the Texture2 into
a single prototype.
-
Gavin:
It sure is simpler to be able to specify: Cube { texture AnimatedTexture2
{ filename "foo.mpg" animationType LOOP } } Rather than a Script, which
I think would look like: DEF AT AnimatedTextureScript { filename "foo.mpg"
animationType LOOP } DEF C Cube { } ROUTE AT.output -> C.texture.image
(I used a ROUTE because I didn't want to compile "C.texture.image" into
AnimatedTextureScript, since I may want to share the same animated texture
between several different nodes).
-
Mitra: This syntax is nicer, but supporting extended Property nodes in
a browser which is getting rid of the concept of a Node at this level open
up a can of worms. Or rather doesn't close an existing can-of-worms that
non-OI browsers want to close.
Open Defaults
An Leaf with an no properties, is identical to an Leaf with every property
set to its default. e.g:
Leaf { }
and
Leaf { Material {} Texture2 {}
-
Mitra:
It should be perfectly legal therefore to specify something like.
DEF Foo1 Leaf { }
DEF Foo2 Leaf { Material IS Foo1.Material }
And then at a later date to set Foo1.Material.filename = "brick.gif"
and expect Foo1 and Foo2 to change.
Gavin:
Again, I don't like overloading IS. The existing DEF/USE mechanism
is sufficient and equivalent (I think implementations will even be pretty
much equivalent-- so why add a new mechanism?)
Prototyping
What can be prototyped in this scheme.
-
Mitra:
-
Frames? Yes, obviously.
-
Leafs? Yes probably, a combination of properties plus Geometry is
complex enough for Prototyping to be usefull, and since behaviors can be
attached to Leafs they should be packagable together.
-
Properties? Probably not. Properties cannot have children, and are
themselves simple, and probably can't have behaviors attached (they should
be attached through the Leaf), which means that there is nothing to be
gained by prototyping them.
-
Transforms? No, subsumed into Frame's fields.
-
Geometry? Maybe, although it is hard to think of a case of a prototyping
a Geometry that could not be done as easily by Prototyping the Leaf.
-
Lights, Cameras etcYes. No change from existing proposals.
Open: If it is decided to allow prototyping of Properties and/or Transforms
and/or Geometry, then we have to be more specific about, or even change
the semantics of Prototyping, so that the semantics are equivalent to a
macro-language, i.e.
PROTO Prop1 { Texture2 { filename="sand.gif" } }
DEF P1 Prop1 {}
Is invalid because a Texture2 can only appear inside an Leaf.
Gavin:
My answer would be that "any node may be prototyped". Which maps into:
Frames: Yes
Objects: Don't exist in my world model
Properties: Yes, if they are nodes
Transforms: Don't exist
Geometry: Yes
Lights/Cameras/Etc: Yes
Re: your open issue:
Frame {
PROTO Prop1 { Texture2 { filename="sand.gif" } }
DEF P1 Prop1 {}
}
... right, that is illegal-- a Texture2 may not be a child of a Frame. But:
Frame {
PROTO Prop1 { Texture2 { filename="sand.gif" } }
Cube { texture DEF P1 Prop1 {} }
}
... I think should be perfectly legal.
Open Attaching behaviors
Note: This issue depends on the outcome of behavior proposals, and deciding
it shouldn't be required before moving this proposal forward.
-
Mitra:
While there are open questions at to the relationship between behaviors
and Leafs, it should be assumed that should behaviors be defined as ScriptNodes
attached to something, then that something can only be a Frame or an Leaf
an not a Property, Transform or Geometry since to do so would assume the
retention of these nodes. Note that ROUTE's or FieldEvents may be attached
to these points via the Leafs they are a part of, with the semantics that
the event is sent to the Leaf which decides internally what the meaning
of its "Texture2" is.
-
Gavin:
In my view, behaviors ARE part of the VRML .wrl file, but ARE NOT part
of the scene graph structure. They are not attached to any one object in
particular, but express relationships between objects (things like "When
these buttons are pressed, do this and that and the other thing").
They are "nodes" (they can be prototyped, and contain fields) but are
NOT "leafs", "frames" or "properties".
ROUTES are used to create the communication paths between the objects
that ARE in the scene graph and behaviors.
Prototypes may be used to create higher-level objects that encapsulate
both a scene graph and a behavior. Prototypes may also be used to create
higher-level objects with only a scene graph or only behavior.
So, in my model of the world, this Switch frame:
Switch {
SCRIPT { ... }
DEF BAR SCRIPT { ... }
}
contains zero children. Script nodes may appear anywhere a node appears,
but aren't considered part of the scene graph.
In which case it doesn't really make sense to DEF/USE Scripts:
Switch {
USE BAR
}
Since BAR isn't considered a child of either Switch, the DEF/USE was pretty
meaningless.
I think this is really important for some "language lawyer" reasons.
The position of a Script in the scene graph means nothing; scripts are
not affected by transforms or properties. Scripts are not necessarily executed
when the scene is traversed for rendering, so having several Script nodes
underneath a Switch doesn't mean anything (but people might be misled into
thinking that they can turn behaviors on and off by using a Switch).
In fact, maybe Scripts and ROUTES should be moved to the bottom of either
the PROTO definition or VRML file. My gut feeling is that separating the
geometry from the behavior in this way might save us some trouble.
Switch
What can be switched? Switches are equivalent to Frames, i.e. they can
switch between Leafs or Frames which are their children, but cannot switch
between Properties. Since changing a switch requires a behavior anyway,
then that behavior can as easily either set the relevant property directly,
or switch between two Leafs.
Open WWWInline
-
Mitra:
At this point there does not appear to be anything to be gained by
WWWInlining anything other than a Frame (or possibly an Leaf). This is
because Texture2 can already have a URL in it, and WWWInlining a Material
is pointless. It MIGHT make sense to allow WWWInlining of Geometry, but
a EXTERNPROTO would probably achieve the same effect as easily.
-
Gavin:
I'm torn-- on one hand, it might be nice to WWWInline any node. On
the other hand, WWWInline already has bboxCenter and bboxSize fields that
make absolutely no sense for properties. Giving up the ability to WWWInline
a single Material or Texture2 isn't a big deal, though, especially if I
can use EXTERNPROTO instead (that's assuming that I get my way and any
node can be prototyped).
Sensors
Sensors, and/or EventHandlers, should be attached to children of Frames
or Leafs, with the semantic being that they are sensing all the children
of the Frame. They should not have children. The goal of this, is that
it allows multiple event handlers to be attached to a single peice of the
scene graph, and also allows removal or addition of Sensors without changing
the hierarchy of the scene graph.
Open
-
Mitra
For example, using Mitra's EventHandler syntax.
Frame {
EventHandler { eventType PICK actionObject foo }
Leaf {
Cube { }
}
}
Gavin:
I'd rather see:
Switch {
sensors [ ClickSensor { ... }, ... ]
Cube { }
Sphere { }
}
Rather than overload the children concept. That is, Frames would have an
MFNode sensors field that was the list of sensors detecting user input
in that Frame's coordinate system. Again, users will be confused and think
that they can use a Switch frame to turn sensors on/off (which would be
annoying to implement).
Open Interpolators
-
Mitra
Interpolators need to be rethought in this context, its probably that
they could be handled by routing their outputs as events to the Leaf or
Frame which they were trying to change, for example using Gavin's syntax
for Routes.
DEF Bar1 Frame {
Leaf { Cube { } }
}
DEF Bar2 RotationInterpolator { ... }
ROUTE Bar2.output TO Bar1.Rotation
A nice default syntax, would be to assume that a RotationInterpolator was
connected to its containing Frame unless ROUTED in some other way, so that
the above could be written.
Frame {
Leaf { Cube { } }
RotationInterpolator { ... }
}
allowing trivial Rotors etc.
Gavin
They're equivalent to prototyped behaviors, and all my arguments about
Script/Logic nodes apply.
Open Adding New Properties
-
Gavin
What if we later want to add a new property to VRML-- perhaps a "bumpMap"
to specify rough surfaces (equivalent to a texture, but affects the normals
of the surface instead of the color)? We could add a field to the standard
VRML nodes, but we will be unable to make existing models (used via EXTERNPROTO
or WWWInline) become bump-mapped, because they won't be specified with
anything in their bumpMap field. In the current scheme, you can just do:
BumpMap { ... }
Cube { ... }/WWWInline { ... }
... to get a bump-mapped cube/inline, but that will be impossible in the
new model because arbitrary properties can't be applied "from the outside".
Mitra
In my scheme, adding a new property that affects a WWWInline is as
hard as in Gavin's, however within a file adding a new property is just
adding new Properties underneath the Leaf node, there is no need to redefine
all of the Geometry Nodes. Browsers will ignore the Properties they don't
implement.