Rendering component

This component defines the basic properties of geometric objects, and nodes to render triangles, lines and points. See Geometry3D component for more comfortable geometric objects like polygons and spheres.

See also X3D specification of the Rendering component.


1. Supported nodes

  • Coordinate(Pascal API: TCoordinateNode),
    Color(Pascal API: TColorNode),
    ColorRGBA(Pascal API: TColorRGBANode),
    Normal(Pascal API: TNormalNode)

    These nodes provide information about positions/colors/normal vectors to various geometry nodes. They are used e.g. by various nodes in this component (like IndexedTriangleSet(Pascal API: TIndexedTriangleSetNode)), and in Geometry3D component (like IndexedFaceSet(Pascal API: TIndexedFaceSetNode)).

  • Triangles:

    IndexedTriangleSet(Pascal API: TIndexedTriangleSetNode),
    TriangleSet(Pascal API: TTriangleSetNode),

    IndexedTriangleFanSet(Pascal API: TIndexedTriangleFanSetNode),
    TriangleFanSet(Pascal API: TTriangleFanSetNode),
    IndexedTriangleStripSet(Pascal API: TIndexedTriangleStripSetNode),
    TriangleStripSet(Pascal API: TTriangleStripSetNode)


    • If you're looking for quads, use instead IndexedQuadSet, QuadSet from CAD geometry component.

    • If you're looking for polygons (with arbitrary number of vertexes for each face), use instead IndexedFaceSet from Geometry3D component.

    • The geometry nodes have many fields to specify positions, and various per-vertex information (normal vectors, colors, attrib with per-vertex attributes for shaders, fogCoord with per-vertex fog depth).

    • The TriangleFanSet and TriangleStripSet nodes have a special limitation: if you will use colors (colors are always per-vertex on these primitives, according to X3D spec) and request generation of per-face normals at the same time, and the shape is lit (has material), then shading results will be slightly incorrect. Like this:

      #X3D V3.0 utf8
      PROFILE Interchange
      Shape {
        appearance Appearance { material Material { } }
        geometry TriangleFanSet {
          coord Coordinate { point [ 0 0 0, 1 0 0, 1 1 0, 0.5 1.5 0.5 ] }
          fanCount 4
          color Color { color [ 1 0 0, 0 1 0, 0 0 1, 1 1 1 ] }
          normalPerVertex FALSE

      Unfortunately, this is unfixable without falling back to worse rendering methods (instead of using triangle fan/strip on GPU). Shading has to be smooth to interpolate per-vertex colors, and at the same time the same vertex may require different normals on different faces. One day we will implement a special fallback for this case (to internally convert fans and strips to IndexedTriangleSet in such special case).

    • X3D specification doesn't specify what to do for triangle/quad sets when appearance specify a texture but no texCoord is given. Our engine currently takes the IndexedFaceSet approach for automatic generation of texture coords in this case.

  • Lines:

    LineSet(Pascal API: TLineSetNode),
    IndexedLineSet(Pascal API: TIndexedLineSetNode)

  • Points:

    PointSet(Pascal API: TPointSetNode)

    Using PointSet is the fastest and easiest way to render points. See an example X3D file. You can write the points in an X3D file or define the nodes using Pascal code, as always, see an example how to build X3D graph in Pascal.

    To control the size of the point, set Scene.RenderOptions.PointSize.

    This uses OpenGL(ES) rendering of points. So:

    • It's really fast (milions of points are not a problem, when placed in one PointSet).

    • There are GPU-specific (OpenGL-implementation specific, actually) limits on the possible point sizes. For desktop OpenGL, small sizes like 1-8 are usually supported, but (strictly speaking) only size 1 is absolutely guaranteed to be supported (see GL_POINT_SIZE_RANGE). For mobile OpenGLES, controlling the point size is not possible (so it's always like 1).

    • Using anti-aliasing affects how the large points look (as a rect or circle). See glPointSize docs.

    This is the fastest method to render points (fastest to use, and fastest to render) but you need to watch for the limitations mentioned above.

    Note: To display a number of 2D points, you can also use DrawPrimitive2D procedure with Mode = pmPoints. It has a parameter where you specify PointSize. Note that this also uses native OpenGL(ES) points, so controlling the point size is limited, just like noted above.

  • ClipPlane(Pascal API: TClipPlaneNode)

    This node allows to clip the geometry by an arbitrary plane in 3D space. In effect, the geometry is "cut" in the middle, with only one part visible.


    • There is a limit on the number of clipping planes that may be enabled at the same time on a single shape. This limit is at least six (see view3dscene "Help -> OpenGL Information", look at "Max clip planes" line, to know the limit of your GPU). Following X3D spec, we treat the "more global" clipping planes as more important.

    • Clipping planes are a purely visual effect. The clipped (invisible) geometry is still taken into account for collision detection, mouse picking, bounding volume calculation etc.

    • Clipping planes don't affect background nodes (X3DBackgroundNode).

2. Example of creating a PointSet in Pascal

This is an example how to construct in Pascal a scene with points in a PointSet and render them or save to file:

uses CastleVectors, CastleWindow, X3DNodes, X3DLoad, CastleScene, CastleViewport,
  PointSet: TPointSetNode;
  PointCoordinates: TCoordinateNode;
  PointShape: TShapeNode;
  Root: TX3DRootNode;
  Window: TCastleWindow;
  Scene: TCastleScene;
  Viewport: TCastleViewport;
  Window := TCastleWindow.Create(Application);
  Viewport := TCastleViewport.Create(Application);
  Viewport.FullSize := true;
  Viewport.AutoCamera := true;
  PointCoordinates := TCoordinateNode.Create;
    [Vector3(0, 0, 0),
     Vector3(0, 1, 0),
     Vector3(1, 1, 0),
     Vector3(1, 0, 0),
     Vector3(0.5, 0.5, 0)
  PointSet := TPointSetNode.Create;
  PointSet.Coord := PointCoordinates;
  PointShape := TShapeNode.Create;
  PointShape.Geometry := PointSet;
  Root := TX3DRootNode.Create;
  { You can now save Root to X3D file,
    or render Root (loading it to Scene, adding Scene to TCastleViewport).
    Or both, as the example below shows.
    Notes about memory management:
    - the PointCoordinates are owned by PointSet,
    - PointSet is owned by PointShape,
    - PointShape is owned by Root,
    - Root is owned by Scene (because we call Scene.Load with 2nd parameter "true"),
    - and Scene is owned by Application.
    So in this example, everything will be automatically freed when
    Application is freed (which happens in CastleWindow unit finalization).
    If you would not call "Scene.Load(Root, true)", then you should free Root
    manually at the end, by "FreeAndNil(Root)".
  SaveNode(Root, 'my_points.x3d');
  Scene := TCastleScene.Create(Application);
  Scene.Load(Root, true);
  Scene.PreciseCollisions := true;
  Scene.RenderOptions.PointSize := 10;