Scene Graph: X3D nodes

Close up shadows on the tree
Water reflections by optimized GeneratedCubeMapTexture
Mirrors by RenderedTexture by Victor Amat

1. Introduction: What is X3D?

X3D is an open standard that defines:

  1. A set of nodes that describe 3D and 2D content, like shapes (meshes, boxes, spheres), materials, lights, cameras, animations, interactions, shaders, sounds, cube maps (mirrors)…​

    These nodes are the important building block of our Castle Game Engine. You can load and display them using TCastleScene.

    In our engine, in addition to the standard X3D nodes, we also define a few extension nodes. E.g. we add nodes to make shader effects, screen (post-processing) effects, shadows and more.

  2. A file format to load and save these nodes in files.

    There are multiple encodings of X3D nodes, we support the two most common: XML encoding and classic encoding. Both these encodings are just text files — you don’t need any special software to edit them, any text editor will do just fine.

    Various 3D modeling applications can export to it. Unfortunately, current Blender exporter to X3D lacks a lot of important features (animations, PBR materials, any textures, metadata…​) so we don’t recommend using it.

    As a file format, we recommend using glTF instead.

In our engine, the first point is the most important: X3D nodes are the core building block of everything. That is, everything you see loaded into TCastleScene is a graph of X3D nodes. All 3D and 2D model formats are loaded into a graph of X3D nodes. You have Pascal API available to manipulate these nodes, to create and modify them at runtime.

2. Examples

See our demo models for example X3D models.

You can load and display any X3D model using:

  • Our Castle Model Viewer.

  • Any other Castle Game Engine tool. The engine even features a ready "3D Model Viewer" project template and we encourage you to use it to create your own custom viewer.

  • A number of other X3D viewers and tools are available (including free and open-source). To name a few:

3. Learning X3D

4. X3D in Pascal

X3D nodes are the scene graph of our engine. Once you load a 3D or 2D model into TCastleScene (whether it was in X3D format or anything else, like glTF), you have a graph of X3D nodes. The root of this graph is available as TCastleSceneCore.RootNode.

Every X3D node corresponds to a Pascal class with appropriate fields, and you can freely create and modify X3D nodes at runtime.

For example, consider an X3D node Box. This node in X3D has fields:

  • size (the X3D type is SFVec3f)

  • solid (the X3D type is SFBool).

In Pascal, this node corresponds to the class TBoxNode, with properties

You can create and edit instances of TBoxNode and use TCastleScene to render them.

See for example:

4.1. X3D node instance lifetime in Pascal

The X3D nodes have a reference-counting mechanism. The node (TX3DNode or any descendant) is freed when the reference count of it changes from non-zero to zero.

So in the usual case, if you set the node as a value of some property of the other node, then you no longer need to think about releasing this node — it will be released along with the parent. For example:

var
  Geometry: TBoxNode;
  Shape: TShapeNode;
  Root: TX3DRootNode;
begin
  Geometry := TBoxNode.Create;

  Shape := TShapeNode.Create;
  Shape.Geometry := Geometry;

  { Now you no longer need to worry about freeing Geometry.
    It will be freed along with Shape.
    Note that there's a shortcut for above 3 lines:

    Geometry := TBoxNode.CreateWithShape(Shape);
  }

  Root := TX3DRootNode.Create;
  Root.AddChildren(Shape);

  { Now you no longer need to worry about freeing Shape.
    It will be freed along with Root. }

  // to be continued ...

Moreover, when you load nodes into TCastleScene using Scene.Load(MyNodes, true) — the 2nd parameter equal true means that Scene takes ownership of the whole nodes tree. So the whole TX3DRootNode instance will be freed along with Scene.

So we can continue the example above:

  Scene := TCastleScene.Create(Application);
  Scene.Load(Root, true);

  { Now you no longer need to worry about freeing Root.
    It will be freed along with Scene. }

And Scene is a regular Pascal TComponent, with usual component ownership. In the above example, it is owned by the Application singleton. In larger application, when using views, it will often be owned by TCastleView.FreeAtStop. And you can always free the scene explicitly too, like FreeAndNil(Scene);.

Notes:

  • If a node is not referenced from anywhere, you are responsible for freeing it manually as usual. For example, if we would not load Root into Scene (if we remove the line Scene.Load(Root, true) from above example) then at some point you should call FreeAndNil(Root);.

  • If for some reason you do not want the node to be automatically freed, you can use TX3DNode.KeepExistingBegin and TX3DNode.KeepExistingEnd.


To improve this documentation just edit this page and create a pull request to cge-www repository.