If you want to operate on the VRML graph, for
some purposes it's enough to load your scene to a
This way you know the root node of the scene. Each node points
Children property and
MFNode fields) to it's children nodes,
so if you know the root node of the scene, you know the whole
TVRMLNode class gives you
many methods to operate on the nodes graph, and sometimes this is all you need.
However, some operations cannot be implemented in
TVRMLNode class. The basic reason is that the node
doesn't “know” the state of VRML graph where it
is used. Node's state is affected by other nodes that may be it's
parents or siblings. Moreover, a node may be used many times in the
same scene (by DEF / USE mechanism),
so it may occur many times in a scene with different states.
That's why many
methods described in Section 3.7, “Geometry nodes features”) require
State: they are not able to figure it
These are the reasons why an additional class, called
TCastleSceneCore, was created. It is essentially
just a wrapper around a VRML root node (kept inside it's
RootNode property) adding a lot of useful
and comfortable methods to operate and investigate the scene as a whole.
First, let's introduce a building block for our scene class:
a shape. Instance of
class. Shape is basically two pieces of information: a geometry node
TVRMLGeometryNode) and it's state
For VRML >= 2.0, this usually corresponds to
a single instance of actual VRML
that's the reason for it's name.
Shape contains absolutely all the information needed to render and generally deal with this piece of VRML graph. It's completely independent from other shapes.
For VRML 2.0, some shape features were
already available. That's because of smart definitions of
children fields of grouping nodes, as explained earlier in
Section 1.5.1, “Why VRML 2.0 is better”: we don't
need so much state information in VRML 2.0 and we can pick
children of grouping nodes in any order. Still, our shape provides
the more complete solution: it includes also accumulated transformation matrix and
“global” properties (fog and active lights).
This is the main property of
The idea is simple: to overcome
the problems with VRML state, we can just use
method from the root node (see Section 3.6, “Traversing VRML graph”)
and store every geometry node (descendant of
see Section 3.7, “Geometry nodes features”) along with it's state.
As a result we get a simple list of shapes.
This list is, to some extent, an alternative “flattened”
representation of the VRML graph.
Actually, we can't really have a completely flat list of shapes.
Instead, we create
a simple, usually quite flat tree of shapes, in
Reason: some things, like
Switch node, require some
processing each time we want to browse the tree (this way, we keep track
of shapes in inactive
Switch children, which allows
us very fast switching of
that is: replacing/adding/removing large parts of VRML graph).
So we take VRML nodes graph, and transform it into another graph (shapes tree)... But the resulting tree is really much simpler, it's just as simple representation of VRML visible things as you can get.
This way we solve various problems mentioned in Section 1.5, “VRML 1.0 state”: we get full accumulated VRML state readily available for each shape. Also, given a tree of shapes, we can pick our shapes in any order, and we can pick any of them. This is crucial for various OpenGL rendering features and optimizations.
Additional advantage of looking at our shapes tree
is that resources completely not used (for example
node not used by any node in VRML 1.0) are not present there.
They don't occur in a state of any shape.
So unused textures will not be even loaded from their files.
Finally, remember that in Section 1.5, “VRML 1.0 state”
we mentioned a practical problem of simple VRML 1.0 implementation
in OpenGL: OpenGL stack sizes are limited. Our scene solves this,
because there is no unlimited push/pop hierarchy anymore.
Features of nodes like VRML 1.0
TransformSeparator are already handled
at this stage. And they are handled without using any OpenGL stacks,
since this unit can't even depend on OpenGL. Features of VRML 2.0
Transform nodes that apply transformation
to all it's children are already handled here too.
TCastleSceneCore is responsible for implementing
most of the events mechanism of VRML / X3D.
property to true.
Some underlying parts of events mechanism are in fact implemented
at the lower level, that is inside
and friends. For example, event routes are instantiated when reading VRML file
and they become attached to VRML graph. So passing events through routes
is already working at this point. Also, exposed events
are implemented directly inside
TX3DField. So setting
an exposed field by
eventIn causes appropriate behavior
value and generating proper
all these routes and exposed events are useless, since nothing initially
“fires” the event. Routes and exposed events are mechanisms
to process events, but they cannot generate events “on their own”,
that is they generate events only when other events push them to it.
The way to make an “initial event” in VRML / X3D is to use
sensor nodes. Various sensor nodes
emit events at specified situations, for example
TimeSensorfires events continuously when time changes,
KeySensorfires events when user presses a key within VRML browser,
TouchSensorand others from “pointing device sensor component” in X3D fire events when user clicks / drags with mouse,
TransformSensorfire events on collision (of viewer or normal objects within VRML world) with user-defined boxes in space, thus allowing collision detection to VRML authors.
TCastleSceneCore.ProcessEvents to true
TCastleSceneCore.KeyDown and others) you make sensors
work. Thus initial events are generated when appropriate, and
routes and exposed events take care of spreading them, changing VRML graph
Numerous other features are available in our scene class:
Methods to calculate bounding box, vertexes count and triangles count of the whole scene. They work simply by summing appropriate results of all shapes.
Methods to calculate triangles list (triangulate all shapes in the scene) and to build octrees for the scene. There are also comfortable properties to store the build octree associated with given scene — although our engine doesn't limit how you manage the constructed octrees, you can create as many octrees for given scene as you want and store them where you want.
More about octrees in Chapter 4, Octrees.
Methods to find
Viewpointor camera nodes, transform them, and calculate simple (position, direction, up) triple describing camera setting.
Methods to find
Fognode and calculate it's transformation.
Some scene properties are quite time-consuming
to calculate. Calculating the tree of shapes
requires traversing whole scene graph. Calculating scene bounding
box is even more difficult, since for each shape we must calculate
it's bounding box
(in fact calculation of scene bounding box as implemented
simply uses the shapes tree). Obviously we cannot repeat
these calculations each time we need these values. So the results
are cached inside
Most of the properties are cached: shapes, bounding boxes, vertexes and triangles counts, fog properties. Even triangles' lists may be cached if you want.
Also various properties for single shapes are cached
TShape instance: bounding box,
bounding sphere and triangle and vertexes counts. After all,
some of these operations are quite time-consuming by themselves.
For example to calculate bounding box of
we have to iterate over all it's coordinates.
Direct changes to actual VRML nodes are not
automatically detected. In other words cache is not automatically
cleared on changes. Instead you have to manually call
after changing some parts of the scene. Scene analyzes how this change
affects the rendered scene, and invalidates as few as possible parts
of the cache.
For example changes to VRML 1.0 nodes like
Material will affect
only the shapes that have these nodes in their
state. So the whole shapes tree doesn't need to be
regenerated, also the information about other shapes
(like their bounding boxes) is still valid.
For simple scene changes, you can also use
methods. This will change the value of the field,
and automatically notify all interested scenes.
You can also just send events instead of directly modifying fields,
see the next section.
In Section 6.4, “VRML scene class for OpenGL” we will introduce the
that descends from
It adds various OpenGL methods and caches various OpenGL resources
related to rendering particular scene parts.
This means that our
will have even greater impact.
At the low level, passing events works by
TX3DEvent.Send method and
Both input and output events can be send and received:
for input events, it's the outside world (routes, scripts)
that sends the event, and handling of the event is specific
to containing node. For output events, it's the other way around:
sending the event is specific to containing node, and the event
is received by connected routes.
When exposed fields are changed through events,
TCastleSceneCore takes care to automatically
internally call appropriate
This means that events mechanism automatically updates everything
as necessary, and you don't have to worry about it — the VRML
TCastleSceneCore will just magically
change by itself, assuming
is on. This also means that
implement the “cherry-picking optimizations”
when VRML graph is changed: they know about what changed, and they
know how it affects the rest of the VRML graph, and so they decide
what needs to be recalculated. For example, when
Coordinate node changed through event,
we know that only geometry using this coordinate node has changed,
so only it's resources need to be recomputed.
There are a lot
of possibilities to optimize here by using knowledge about
what specific node does, what it possibly affects etc. VRML 2.0 things
are easier and probably more optimized in this regard
— reasons were given in
Section 1.5, “VRML 1.0 state”
and Section 1.5.1, “Why VRML 2.0 is better”.
So we have three methods of changing the field value. Do it directly, like
Field.Value := 666; Scene.ChangedField(Field);
or do it by sending event, like
or use the simplest
that sends an event (or directly changes value, if events processing is turned off),
This will trigger all event callbacks, so the field value will change,
and everyone interested will be notified about this: output event of exposed
field will be generated and sent along the routes,
TCastleSceneCore will be notified about the change.