Shape component - extensions


1. Toggle shape rendering (Shape.render)

This field is deprecated now. Use instead the standard (since X3D 4.0) field visible — it's a better name, and standardized. It is exactly equivalent to how render worked.

X3DShapeNode {
  SFBool     [in,out]      render      TRUE      

The field render allows to easily hide and show the given Shape. A hidden shape is not rendered, but otherwise it's still processed (for example, it is used for collision detection).

If you want to hide a particular shape, sometimes this may be a simpler method than using standard X3D Switch node. It doesn't require to wrap the Shape in a Switch node.

This is compatible with InstantReality Shape extension.

2. Specify shading (e.g. Gouraud, Phong or wireframe) for a shape (Shape.shading)

We add a shading field to the Shape node (more precisely, to the abstract X3DShapeNode):

X3DShapeNode {
  ... all normal X3DShapeNode fields ...
  SFString   [in,out]      shading     "DEFAULT"   # ["DEFAULT"|"GOURAUD"|"PHONG"|"WIREFRAME"]

The allowed values for the shading field:

  • DEFAULT: use the default shading.

    The default is to use Phong shading in the latest version of CGE.

    In view3dscene you control this using the "View -> Phong Shading on Everything" checkbox. In your own games you control this using the Scene.RenderOptions.PhongShading property in Pascal code.

  • GOURAUD: fast per-vertex lighting calculation.

    Specifying the "GOURAUD" indicates that this shape wants to use Gouraud shading, regardless if the default scene shading is Phong or Gouraud.

    Note that some features (like two-sided lighting, bump mapping, shadow maps, PBR) will override this and require Phong shading anyway, since it's impossible to realize them with Gouraud shading.

    Note that the "GOURAUD" shading can performs only one-sided lighting in the shader pipeline. So it is only allowed if the backface-culling is also used, by solid="TRUE". Otherwise two-sided lighting forces usage of Phong shading.

  • PHONG: pretty per-pixel lighting calculation. This also means always using shader pipeline to render this shape.

    This also works nicely with two-sided lighting, if both sides of the mesh are visible, by using solid="FALSE".

  • WIREFFRAME: render as a wireframe. The rendering model matches the IndexedLineSet specification, in particular: the shape is not lit.

    For now this is only honored by the Box, Sphere nodes. It will be extended to all geometry nodes when necessary in the future.

These shading names are consistent with "Browser options" in X3D spec (with DEFAULT added by us).

3. Specify alpha channel treatment (field alphaMode for Appearance)

Demo of alphaMode
Demo of alphaChannel

We add a new field to the Appearance node to request a specific alpha treatment when rendering.

Appearance {
  ... all normal Appearance fields ...
  SFString   [in,out]      alphaMode        "AUTO"      # "AUTO"|"OPAQUE"|"MASK"|"BLEND"

# deprecated way of doing the same:
SFString [in,out] alphaChannel "AUTO" # "AUTO"|"NONE"|"TEST"|"BLENDING" }

Test file of alphaMode feature.

The following values are allowed for the alphaMode:

  • Value AUTO (the default) means that we auto-detect the correct alpha treatment, looking at various things.

    • For backward compatibility, Castle Game Engine first checks whether the deprecated alphaChannel field is set to something else than AUTO. If yes, then we use alphaChannel value.

    • Material properties (whether the material uses Material.transparency > 0),

    • texture properties (whether some texture defines some alpha channel, and whether it's a yes-or-no alpha channel or smooth).

    • The interpretation of each texture may also be affected by it's ImageTexture.alphaChannel field.

  • OPAQUE: Ignore any alpha channel, render as opaque.

  • MASK: Use alpha-testing, which is good for textures having a sharp (yes-or-no) alpha channel contents.

  • BLEND: Use blending, which allows to show partial transparency of textures and/or materials.

4. Set shape bounding box (Shape.bboxCenter, Shape.bboxSize)

X3DShapeNode {
  SFVec3f    [in,out]      bboxCenter  0 0 0       # (-Inf,Inf)
  SFVec3f    [in,out]      bboxSize    -1 -1 -1    # [0,Inf) or -1 -1 -1

X3D specification of the X3DShapeNode (ancestor of Shape) already includes the fields bboxCenter, bboxSize. In CGE we make them [in,out] which means you can attach X3D routes to them, which means you can animate them.

This bounding box is useful e.g. by glTF skinned animation. When this box is not empty, it determines the shape bounding box, which means that the engine doesn't have to recalculate it every frame when the shape changes.

Note: In Pascal, you should access this by a single property TAbstractShapeNode.BBox, using the TBox3D type (this is used throughout CGE to express axis-aligned bounding boxes).

5. Specify shape collision mode (Shape.collision)

X3DShapeNode {
  SFString   []            collision   "DEFAULT"   # ["DEFAULT"|"BOX"|"NONE"]

The new field collision specifies how the shape collides:

  • "DEFAULT" means that we construct a triangle octree for this shape, to resolve collisions with it precisely, as a "set of triangles".

  • "BOX" means to use the shape bounding box. Which may be auto-calculated, or provided in shape's bboxCenter/Size fields.

    Colliding as a box is much faster, especially in case the shape is dynamic (e.g. changes each frame by skinned animation or morphing). This is automatically used by glTF meshes affected by skinned animation, although you can turn it off.

  • "NONE" means that shape does not collide.

In Pascal, the equivalent is to set TAbstractShapeNode.Collision, like MyShapeNode.Collision := scBox;.

Note that X3D has an alternative method of providing a different (usually simpler) shape for collision purposes: Collision node with enabled and proxy fields. Why is this extension still useful?

  • The collision="BOX" automatically works together with shape bboxCenter/Size.

    When bboxCenter/Size are not provided (or indicate empty box), then box is auto calculated.

    When bboxCenter/Size are provided (and do not indicate empty box), then they are used for both display optimization and for collisions.

    So it's more comfortable in both cases.

  • It can be easily toggled to "DEFAULT" (in Pascal: scDefault) if needed by the author (e.g. if performance drop is acceptable and you want recalculate spatial structure during glTF skinned animation), as described here.

  • "DEFAULT" meaning may change in the future when activated some global like NewPhysics, as we move to using physics engine for all collision detection, and will not automatically construct mesh colliders for everything.