Extensible 3D (X3D)
Part 1: Architecture and base components

31 Programmable shaders component

--- X3D separator bar ---

cube 31.1 Introduction

31.1.1 Name

The name of this component is "Shaders". This name shall be used when referring to this component in the COMPONENT statement (see 7.2.5.4 Component statement).

31.1.2 Overview

This clause describes the Programmable Shaders component of this document. This includes how programmable shaders are specified and how they affect the visual appearance of geometry. Table 31.1 provides links to the major topics in this clause.

Table 31.1 — Topics

cube 31.2 Concepts

31.2.1 Overview

Programmable shading provides a method for authors to directly specify how an object is rendered by providing a method of programmatically modifying sections of the rendering pipeline. This allows replacement of the traditional fixed function pipeline of the graphics API to support a variety of visual effects that typically cannot be implemented using other node components in this standard.

Shaders are typically defined by two separate program pieces. One piece is used to modify the vertex values. This piece may also generate values that can be interpolated between vertex values. Such program pieces are termed vertex shaders. The other piece is used to modify individual pixels as they are drawn to screen. These program pieces are termed fragment shaders or pixel shaders. Although not currently defined, future extensions may include other types of shaders that fit into other places in the graphics pipeline.

31.2.2 Shader languages

31.2.2.1 Shader language options

Shader programs can be written in several shading languages. Each language is specific to the underlying rendering API. Typically a language for one API ( e.g., Microsoft DirectX) is not usable in another rendering API ( e.g., OpenGL) and therefore there is no mandatory requirement for an X3D browser to implement any specific language. A browser implementing this component shall be required to support at least one shading language. The following annexes defines the interface to three popular shader languages:

Shader programs are either defined in a file that can be externally loaded or defined internally within the X3D world. Typically, a separate file is used to specify each type of shader (fragment or vertex) although this is not required.

Some formats are being developed that allow all shaders to be collected together into a single file and used directly by the rendering API. For these file types, a separate PackagedShader node is used. This node is independent of the underlying rendering API, though the specific file format used within a PackagedShader node may be specific to a particular rendering API.

31.2.2.2 Node representation

Each shading language option has a node that implements its functionality. Since each language is quite different, it is not possible to define a single set of nodes that can represent the entire capabilities offered. Each language has its own set of nodes that pertain only to that shading language.

For each set of nodes for a given shading language, there are language-specific behaviours. Mappings for each of the languages are defined in their own annex to this document as described in 31.2.2.1 Shader language options. Table 2 lists the nodes and which annex shall be used to define language-specific behaviours:

Table 31.2 — Shader language node specifications

Shading Language Nodes Annex
OpenGL GLSLang GLSLShader
GLSLShaderObject
Annex I
Direct3D HLSL HLSLShader Annex J
nVidia Cg CgShader Annex K

31.2.2.3 Selecting an appropriate shader

Browsers are not expected to be able to handle all the different forms of shading languages. In fact, most are incompatible with any rendering API apart from the one for which they are defined.

To allow the author to specify a collection of shader options for the X3D browser to select and for the X3D browser to choose the shader version it can run, a fallback mechanism is defined for the shader field of the Appearance node.

The shader field is an MFNode field that defines the collection of pertinent shader nodes of various languages in the order of preference. The first node declared is the highest preference. If the X3D browser does not support the language defined for the current preference level, the X3D browser shall set the node’s isSelected field output to FALSE, and move to the next preference. A X3D browser implementation shall support all nodes if the Programmable Shader component is supported, but is not required to execute the contained script in every shader node. Ignored nodes shall remain a functional part of the scene graph, continuing to interact with the event model as required by the field access types.

When a shader is found that can be executed by the X3D browser, it shall set the isSelected field output to TRUE.

An X3D browser may select an appropriate shader on grounds other than just the shading language used.

EXAMPLE  The local hardware not supporting some of the features requested or the shader running in software rather than hardware are considered valid reasons for not selecting a shader to run.

31.2.2.4 Per-vertex attributes

Advanced vertex shaders often need to provide extra information on a per vertex basis ( e.g., temperature information in an analysis system or weighting values for a skin and bones system). Per-vertex attributes may be supplied for any geometry that extends X3DComposedGeometryNode as described in 11.3.2 X3DComposedGeometryNode. Both matrix and vector values may be supplied on a per-vertex basis through nodes that are extended from X3DVertexAttributeNode.

Each shading language uses a different method of mapping per-vertex attributes to the user-provided shading language code. The definition of how to interpret the name field value to the individual shading language file is defined in the language-specific annex (see Table 31.2).

Per vertex attributes are mapped 1:1 to each vertex value. When used in a node derived from X3DComposedGeometryNode, the number of values defined in the node containing the attribute values shall be identical to the number of coordinate values specified for the geometry node. If the number of values does not match, the visual result is implementation specific.

31.2.2.5 Per-object attributes

Shaders often need to provide specific per-object values ( e.g., the colour of the light). The most common name for one of these values is uniform variable. Uniform variables are defined using custom field definitions that allow objects to be set as required. The placement of these fields depends on the shading language itself, as the amount of customizability is dependent on the shading language.

Field names shall be mapped to the shading API as the uniform variable name of the identical name in the shader file.

NOTE  Some shading languages cannot handle the full UTF-8 character set required by this document.

For fields of type SFNode or MFNode, the mapping to the shading language is dependent on the individual shading language. The applicable language binding annex specifies the required behaviour (see Table 31.2).

31.2.2.6 Handling errors

If a shader program does not have valid syntax or the environment does not contain enough information for the shader to render, implementations shall track errors during all stages of the shader process and display them to the X3D browser's console.

A shader that fails during run-time or during the compilation or validation stages shall not run. A X3D browser shall use the rendering API's default behaviour for this situation. If a user requires some fallback behaviour, such as the browser not supporting the shader capabilities requested, other nodes such as LoadSensor, Script, and/or Switch can be used to specify the required visual output.

31.2.3 Interaction with other nodes and components

31.2.3.1 Overview

Programmable shaders typically replace large amounts of functionality that would be traditionally implemented by the X3D browser. The effect of each shader language varies depending on the amount of processing that the user will be required to perform. Some languages may completely disable anything that would be automatically generated ( e.g., texture coordinates or normals) while others may not. A reasonable assumption is that everything is disabled for any geometry that has a shader associated with it. Each language shading definition annex specifies exactly the semantics that can be expected of the underlying rendering API, and by implication, the X3D browser.

31.2.3.2 Lighting

If the user provides a fragment shader, the shader shall be responsible for all lighting associated with the affected geometry. The lighting definitions in 17 Lighting component shall be ignored. Where possible, all of the lighting information such as the currently set lights, material colours and textures shall be made available to the shader. Some rendering APIs may not be able to make available all of this information. In this case, it is acceptable to provide alternative mapping hints as part of the node definition. The individual shading language annexes contain more information (see Table 31.2).

31.2.3.3 Geometry

Since a vertex shader may move the vertex from its original location in the local coordinate system, it can produce many large-scale side effects. A major problem is that the X3D browser implementation may have no idea where the final geometry has been placed. Any action that relies on knowing the exact position of vertices may fail to act properly. In particular, terrain following, collision detection and sensors can be adversely affected.

Because a vertex may be shifted in world space, it is recommended that if a user requires this ability, a means of giving a rough approximation of the geometry to the X3D browser should be provided, either through setting an explicit bounding box on the containing Shape node or by providing the source geometry as close to the final output shape as possible.

EXAMPLE  A fuzzy rabbit shape would start with the source vertices in the shape of the base rabbit geometry.

31.2.3.4 LoadSensor

A shader is considered loaded when the source for the shader program has been downloaded successfully. A shader is considered valid when the downloaded file has been compiled and registered with the rendering API, which then considers it a valid object.

31.2.4 Conformance

31.2.4.1 Component support

An implementation shall indicate support for this component if and only if the user's particular hardware is capable of supporting this component, either through direct hardware support or software emulation. If the user's machine is not capable of supporting this component, the X3D browser shall indicate a failure by stopping at the appropriate PROFILE or COMPONENT statement of the file, in accordance with 7.2.5.3 PROFILE statement or 7.2.5.4 COMPONENT statement.

31.2.4.2 Node support

A conformant X3D browser for this component shall support all the nodes at a given level. However, a conformant X3D browser is not required to support the corresponding shading language for that node. If a X3D browser is not supporting the language, the nodes that provide access to that language shall be read and ignored. These ignored nodes shall still exist as part of the X3D scene graph, and shall still honour the X3D event model.

EXAMPLE  Any inputOutput fields shall still be required to implement output events if a value is written to the input.

31.2.4.3 Language support

A X3D browser conformant to this component shall support at least one shading language as listed in Table 31.2.

31.2.4.4 Scene graph interaction

A shader containing a vertex shader shall be required to be conformant only to either the explicit bounding boxes or the original source geometry definition. It is not required to obtain the output vertex information for use within the scene graph.

cube 31.3 Abstract types

31.3.1 X3DProgrammableShaderObject

X3DProgrammableShaderObject {
}

This abstract interface is the marker for all shader-related node types that specify arbitrary fields for interfacing with per-object attribute values.

A concrete X3DProgrammableShaderObject node instance is used to program behaviour for a shader in a scene. The shader is able to receive and process events that are sent to it. Each event that can be received shall be declared in the shader node using the same field syntax as is used in a prototype definition:

inputOnly    type name

The type can be any of the standard X3D fields (as defined in 5 Field type reference). The name shall be an identifier that is unique for this shader node and is used to map the value to the shader program's uniform variable of the same name. If a shader program does not have a matching uniform variable, the field value is ignored.

OutputOnly fields are not required to generate output events from a shader. Current hardware shader technology does not support this capability, though future versions may.

It is recommended that user-defined field or event names defined in shader nodes follow the naming conventions described in Part 2 of ISO/IEC 19775.

31.3.2 X3DShaderNode

X3DShaderNode : X3DAppearanceChildNode {
  SFBool   [in]     activate
  SFNode   [in,out] metadata   NULL [X3DMetadataObject]
  SFBool   [out]    isSelected
  SFBool   [out]    isValid
  SFString []       language   ""   ["Cg"|"GLSL"|"HLSL"|...]
}

This abstract node type is the base type for all node types that specify a programmable shader.

The activate field forces the shader to activate the contained objects. The conditions under which an activate event may be required are described in OpenGL I.5 Event model, Microsoft High Level Shading Language (HLSL) J.5 Event model, and nVidia Cg K.6 Event model.

The isSelected output field is used to indicate that this shader instance is the one selected for use by the X3D browser. A TRUE value indicates that this instance is in use. A FALSE value indicates that this instance is not in use. The rules for when a X3D browser decides to select a particular node instance are described in 31.2.2.3 Selecting an appropriate shader.

The isValid field is used to indicate whether the current shader objects can be run as a shader program.

EXAMPLE  There are no syntax errors and the hardware can support all the required features.

The definition of this field may also add additional semantics on a per-language basis.

The language field is used to indicate to the X3D browser which shading language is used for the source file(s). This field may be used as a hint for the X3D browser if the shading language is not immediately determinable from the source ( e.g., a generic MIME type of text/plain is returned). A X3D browser may use this field for determining which node instance will be selected and to ignore languages that it is not capable of supporting. Three basic language types are defined for this document and others may be optionally supported by a browser.

31.3.3 X3DVertexAttributeNode

X3DVertexAttributeNode : X3DGeometricPropertyNode {
  SFNode   [in,out] metadata NULL [X3DMetadataObject]
  SFString []       name     "" 
}

This abstract node type is the base type for all node types that specify per-vertex attribute information to the shader.

The required name field describes a name that is mapped to the shading language-specific name for describing per-vertex data. The appropriate shader language annex (see Table 31.2) annex contains language-specific binding information.

cube 31.4 Node reference

31.4.1 ComposedShader

ComposedShader : X3DShaderNode, X3DProgrammableShaderObject {
  SFBool    [in]     activate
  SFNode    [in,out] metadata   NULL [X3DMetadataObject]
  MFNode    [in,out] parts      []   [ShaderPart]
  SFBool    [out]    isSelected
  SFBool    [out]    isValid
  SFString []        language   ""   ["Cg"|"GLSL"|"HLSL"|...]

  # And any number of:
  fieldType []       fieldName
  fieldType [in]     fieldName
  fieldType [out]    fieldName
  fieldType [in,out] fieldName
}

The ComposedShader node defines a shader where the individual source files are not individually programmable. All access to the shading capabilities is defined through a single interface that applies to all parts.

EXAMPLE  OpenGL Shading Language (GLSL)

The isValid field adds an additional semantic indicating whether the current shader parts can be linked together to form a complete valid shader program.

31.4.2 FloatVertexAttribute

FloatVertexAttribute : X3DVertexAttributeNode {
  SFNode   [in,out] metadata      NULL [X3DMetadataObject]
  MFFloat  [in,out] value  		  []   (-∞,∞)
  SFString []       name          ""
  SFInt32  []       numComponents 4    [1..4]
}

The FloatVertexAttribute node defines a set of per-vertex single-precision floating point attributes.

The numComponents field specifies how many consecutive floating point values should be grouped together per vertex. The length of the value field shall be a multiple of numComponents.

The value field specifies an arbitrary collection of floating point values that will be passed to the shader as per-vertex information. The specific type mapping to the individual shading language data types is in the appropriate language-specific annex (see Table 31.2).

31.4.3 Matrix3VertexAttribute

Matrix3VertexAttribute : X3DVertexAttributeNode {
  SFNode     [in,out] metadata NULL [X3DMetadataObject]
  MFMatrix3f [in,out] value    []   (-∞,∞)
  SFString   []       name     ""
}

The Matrix3VertexAttribute node defines a set of per-vertex 3×3 matrix attributes.

The value field specifies an arbitrary collection of matrix values that will be passed to the shader as per-vertex information. The specific type mapping to the individual shading language data types shall be found in the appropriate language-specific annex (see Table 31.2).

31.4.4 Matrix4VertexAttribute

Matrix4VertexAttribute : X3DVertexAttributeNode {
  SFNode     [in,out] metadata NULL [X3DMetadataObject]
  MFMatrix4f [in,out] value    []   (-∞,∞)
  SFString   []       name     ""
}

The Matrix4VertexAttribute node defines a set of per-vertex 4×4 matrix attributes.

The value field specifies an arbitrary collection of matrix values that will be passed to the shader as per-vertex information. The specific type mapping to the individual shading language data types shall be found in the appropriate language-specific annex (see Table 31.2).

31.4.5 PackagedShader

PackagedShader : X3DShaderNode, X3DUrlObject, X3DProgrammableShaderObject {
  SFBool    [in]     activate
  SFTime    [in,out] autoRefresh          0.0  [0,∞)
  SFTime    [in,out] autoRefreshTimeLimit 3600.0  [0,∞)
  SFString  [in,out] description          ""
  SFBool    [in,out] load                 TRUE
  SFNode    [in,out] metadata             NULL [X3DMetadataObject]
  MFString  [in,out] url                  []   [URI]
  SFBool    [out]    isSelected
  SFBool    [out]    isValid
  SFString  []       language             ""   ["Cg"|"GLSL"|"HLSL"|...]

  # And any number of:
  fieldType [in]     fieldName
  fieldType [in,out] fieldName initialValue
  fieldType [out]    fieldName
  fieldType []       fieldName initialValue
}

A PackagedShader node describes a single file that may contain a number of shaders and combined effects.

EXAMPLE  The Microsoft .fx file format represents this type of shader (see [FX]).

The shader source is read from the URL specified by the url field. When the url field contains no values ([]), this object instance is ignored. The url field is defined in 9.2.1 URLs.

The PackagedShader node's url field shall allow for both inline scripting and script reference via a URL. The MIME-type of the returned data defines the language type. Additionally, instructions can be included in-line using scripting language protocols as defined in 9.2.3 Scripting language protocols for the specific language (from which the language type is inferred).

No file formats are required to be supported for this node.

The language field may be used to optionally determine the language type if no MIME-type information is available.

If the autoRefresh field results in a new script getting loaded or the prior script getting reloaded, then all fields are re-initialized to their initially defined values, and the initialize() method is invoked, if provided.

WARNING  Automatically reloading content can have security considerations and needs to be considered carefully.

31.4.6 ProgramShader

ProgramShader : X3DShaderNode {
  SFBool   [in]     activate
  SFNode   [in,out] metadata   NULL [X3DMetadataObject]
  MFNode   [in,out] programs   []   [ShaderProgram]
  SFBool   [out]    isSelected
  SFBool   [out]    isValid
  SFString []       language   ""   ["Cg"|"GLSL"|"HLSL"|...]
}

The ProgramShader node defines a shader that can consist of one or more individually programmable, self contained pieces. Each piece, represented by a ShaderProgram node, shall be a self-contained source that does not rely on any other source file and can manage one part of the programmable pipeline ( e.g., vertex or fragment processing).

The programs field consists of zero or more ShaderProgram node instances. In general, only two ShaderProgram instances are needed:  one each for vertex and fragment processing. Each shader language annex shall define the required behaviour for processing this field.

The isValid field may add an additional semantic to indicate whether all parts are available.

EXAMPLE  Microsoft's HLSL requires that both vertex and fragment programs be provided. It specifies that it is an error to provide one and not the other.

31.4.7 ShaderPart

ShaderPart : X3DNode, X3DUrlObject {
  SFTime   [in,out] autoRefresh          0.0      [0,∞)
  SFTime   [in,out] autoRefreshTimeLimit 3600.0      [0,∞)
  SFString [in,out] description          ""
  SFBool   [in,out] load                 TRUE
  SFNode   [in,out] metadata             NULL     [X3DMetadataObject]
  MFString [in,out] url                  []       [URI]
  SFString []       type                 "VERTEX" ["VERTEX"|"FRAGMENT"|...] 
}

The ShaderPart node defines a portion of source code to be used by a ComposedShader node. The source code is not required to be a complete shader for all of the vertex/fragment processing.

The type field indicates whether this object shall be compiled as a vertex shader, fragment shader, or other future-defined shader type.

The shader source code is read from the URL specified by the url field. When the url field contains no values ( i.e., is an empty list), this object instance is ignored. The url field is defined in 9.2.1 URLs. Shader source files shall be plain text encoded as specified for MIME type text/plain and interpreted according to the type field.

If the autoRefresh field results in a new script getting loaded or the prior script getting reloaded, the initialize() method is invoked, if provided.

WARNING  Automatically reloading content can have security considerations and needs to be considered carefully.

31.4.8 ShaderProgram

ShaderProgram : X3DNode, X3DUrlObject, X3DProgrammableShaderObject {
  SFTime    [in,out] autoRefresh          0.0      [0,∞)
  SFTime    [in,out] autoRefreshTimeLimit 3600.0      [0,∞)
  SFString  [in,out] description          ""
  SFBool    [in,out] load                 TRUE
  SFNode    [in,out] metadata             NULL     [X3DMetadataObject]
  MFString  [in,out] url                  []       [URI]
  SFString  []       type                 "VERTEX" ["VERTEX"|"FRAGMENT"|...] 

  # And any number of:
  fieldType [in]     fieldName
  fieldType [in,out] fieldName            initialValue
  fieldType [out]    fieldName
  fieldType []       fieldName            initialValue
}

The ShaderProgram node provides the source and interface to a self contained program that occupies one part of the rendering process: either a vertex or fragment shader.

The type field indicates whether this object shall be compiled as a vertex shader, fragment shader, or other future-defined shader type.

The shader source is read from the URL specified by the url field. When the url field contains no values ([]), this object instance is ignored. The url field is defined in 9.2.1 URLs. Shader source files shall be plain text encoded as specified for MIME type text/plain and interpreted according to the containing node's language definition.

The ShaderProgram node's url field shall allow for both inline scripting and script reference via a URL. The language field in the closest parent node defines the shader language of interest, alternatively the MIME type of the returned data defines the language type. Additionally, instructions can be included in-line using scripting language protocols as defined in 9.2.3 Scripting language protocols for the specific language (from which the language type is inferred).

If the autoRefresh field results in a new script getting loaded or the prior script getting reloaded, then all fields are re-initialized to their initially defined values, and the initialize() method is invoked, if provided.

WARNING  Automatically reloading content can have security considerations and needs to be considered carefully.

cube 31.5 Support levels

The Programmable Shaders component defines a single level of support as specified in Table 31.3.

Table 31.3 — Programmable shaders component support levels

LevelPrerequisitesNodes/FeaturesSupport
1 Core 1
Grouping 1
Shape 1
Rendering 1
X3DProgrammableShaderObject n/a
X3DShaderNode n/a
X3DVertexAttributeNode n/a
ComposedShader All fields fully supported.
FloatVertexAttribute All fields fully supported.
Matrix3VertexAttribute All fields fully supported.
Matrix4VertexAttribute All fields fully supported.
PackagedShader All fields fully supported.
ProgramShader All fields fully supported.
ShaderPart All fields fully supported.
ShaderProgram All fields fully supported.
--- X3D separator bar ---