When organizing your world, you often want to arrange your 3D objects in a hierarchy. We have two transformation hierarchies in our engine:
The "outer" tree containing scenes:
TCastleViewport.Items is a tree containing scenes. A scene is an instance of
which is probably the most important class in our engine.
It represents a 3D or 2D model.
You can group and transform the scenes using
TCastleScene is also a descendant of
so you can just transform a scene directly.
This is a very simple tree, that allows you to simply transform and group 3D objects.
Changing this tree dynamically has absolutely zero cost.
This includes changing transformations of items
(moving, rotating, scaling them),
or completely rearranging the tree (adding, removing items),
or hiding / showing the items (use the
It is ultimately fast and can be done as often as you need.
Downside: do not make this tree too deep and complicated. This tree needs to be traversed each time you render or check collisions with the 3D world. Although we successfully use it with hundreds of transformations, but be careful — at some point the processing time will become noticeable.
Summary: absolutely dynamic tree, but don't make it too deep and complicated.
The "inner" tree inside every scene, containing X3D nodes:
TCastleScene there is a transformation hierarchy of X3D nodes,
Loading the scene by
TCastleSceneCore.Load automatically builds a tree of X3D nodes based on 3D model contents.
You can also build (or process) the X3D nodes tree by code.
There are various grouping and transforming nodes,
TTransformNode (see X3D grouping component). Everything you see
is expressed as a combination of X3D nodes — meshes, materials,
textures, shaders, lighting, animations, collisions...
TCastleScene has a tree of X3D nodes.
In the simplest cases (if you load scenes using
you will create one
TCastleScene instance for each 3D model file you have.
But you're not limited to this approach, as you can split and merge
X3D graphs freely.
See an example code
for how to load multiple 3D model files into a single X3D graph
Properties of the X3D transformation hierarchy:
Changing the transformations in this tree is very fast and optimized, but may have a tiny cost at some point. Rebuilding this tree right now is poorly optimized (it may be improved in the future, but there's a limit to how much it can be done).
Upside: you can go wild with the transformation level here
(the actual rendering and many other read operations look only at flattened
TCastleScene.Shapes mentioned below).
3D collisions, and the "frustum culling" rendering optimization, use a tree (like an octree) to minimize the number of calculations. This is very efficient if you have a lot of 3D shapes.
Summary: this tree is somewhat less dynamic. It is very optimized for some changes, like changing transformations of existing objects, but poorly optimized for an arbitrary rearranging at runtime. Rendering and processing is always lighting fast, regardless of the tree depth or complication.
A natural question is should you combine multiple loaded models into one TCastleScene (like examples/viewport_and_scenes/combine_multiple_x3d_into_one_scene example does)?
At the beginning, don't merge the scenes. It's more natural, and in 90% cases perfectly fast, to use one
TCastleScene for each one model file you load. This allows to trivially load the model using
Scene.Load and is really advised for most cases. See also the relevant section in the manual about optimization.
100, or even 1000, or
TCastleScene instances visible should not be a problem. You should consider merging them if you have 10 000 or more. It depends on your use-case (how complicated are the scenes, how heavy is their rendering and which optimizations matter most).
For completeness, we should also mention another transformation tree.
The X3D nodes hierarchy is automatically reflected as (a little flattened and simplified)
tree of shapes in the
TCastleSceneCore.Shapes property.The visible nodes of this tree are X3D
with geometry nodes inside
This tree can be completely ignored by your code.
It is automatically created and managed inside the
Sometimes you can use this tree to speedup some operations — instead of traversing
the tree in
it's sometimes enough to traverse simpler tree
Copyright Michalis Kamburelis and Castle Game Engine Contributors.
This webpage is also open-source and we welcome pull requests to improve it.