Extensible 3D (X3D)
Part 1: Architecture and base components
17 Lighting component
The name of this component is "Lighting". This name shall be used when referring to this component in the COMPONENT statement (see 7.2.5.4 Component statement).
This clause describes the Lighting component of this documentthis part of ISO/IEC 19775. This includes how light sources are defined and positioned as well as how lights effect the rendered image. Table 17.1 provides links to the major topics in this clause.
The following node types are light source nodes:
PointLight and SpotLight illuminate all objects in the world that fall within their volume of lighting influence regardless of location within the transformation hierarchy (by default, when their global field is TRUE). PointLight defines this volume of influence as a sphere centred at the light (defined by a radius). SpotLight defines the volume of influence as a solid angle defined by a radius and a cut-off angle. DirectionalLight nodes illuminate only the objects descended from the light's parent grouping node, including any descendent children of the parent grouping nodes (by default, when their global field is FALSE).
Shape nodes are illuminated by the sum of all of the lights in the world that affect them. This includes the contribution of both the direct and ambient illumination from light sources. Ambient illumination results from the scattering and reflection of light originally emitted directly by light sources. The amount of ambient light is associated with the individual lights in the scene. This is a gross approximation to how ambient reflection actually occurs in nature.
Any node used as a source of illumination is derived from X3DLightNode. All light sources contain an intensity, a color, and an ambientIntensity field. The intensity field specifies the brightness of the direct emission from the light, and the ambientIntensity specifies the intensity of the ambient emission from the light. Light intensity may range from 0.0 (no light emission) to infinity. The color field specifies the spectral colour properties of both the direct and ambient light emission as an RGB value. The on field specifies whether the light is enabled or disabled. If the value is FALSE, the light is disabled and will not affect any nodes in the scene. If the value is TRUE, the light will affect other nodes according to the 17.2.1.2 Scoping of lights.
Typically lighting intensity values are within range [0,1] for consistent composability of multiple scenes with independent lights.
In the physical lighting model (see 17.2.2.6 Physical lighting model) the intensity value should correspond to:
In the physical lighting model, the ambientIntensity value is unused.
In the case of the unlit lighting model all lights are ignored. See the 17.2.2.4 Unlit lighting model.
Each light type defines a global field that determines whether the light is global or scoped. Global lights illuminate all objects that fall within their volume of lighting influence. Scoped lights only illuminate objects that are in the same transformation hierarchy as the light; i.e., only the children and descendants of its enclosing parent group are illuminated. This allows the creation of realistic effects such as lights that illuminate a single room.
The X3D lighting model provides detailed equations that specify the colours to apply to each geometric object. For each object, the values of the material, color, and/or texture currently being applied to the object are combined with the lights illuminating the object and the currently bound X3DFogObject (if specified). These equations are designed to simulate the physical properties of light striking a surface.
If a programmable shader is defined for an Appearance node, the lighting model shall be disabled and replaced by the functionality implemented by the shader program. See 31 Programmable shaders component for more information.
NOTE Geometry nodes that represent lines or points do not support lighting.
A grayscale texture is exactly equivalent to using an RGB texture with all 3 components (red, green, blue) equal.
A texture without an alpha channel is exactly equivalent to using a texture with an alpha channel filled with 1 (indicating opaque).
The declarations and definitions below are presented using pseudocode similar to shading language code (see 31.2.2.1 Shader language options).
x · y = max(0.0, dotProduct(x, y))
The mixTexture(vector4color,X3DTextureNodetexture) function, used in the equations below, takes care of mixing an RGBA color with the RGBA value sampled from the texture at the given shape point.
mixTexture(color, texture) = color × textureSample(texture)
The textureSample(texture) is a function sampling the texture (recovering a single color from an array of pixels), with the correct texture coordinates and transformation.
In effect the color modulates the color from the texture.
The alpha (opacity) values are multiplied too, hence:
The lerp(floatfactor,vectorAnyx,vectorAnyy) function performs a standard linear interpolation, applicable to scalars or vectors of any dimension:
lerp(factor, x, y) = x * (1 - factor) + y * factor = x + (y - x) * factor
The occlusion(vector4color) function, used in the equations below for Phong and physical lighting model, is used to apply the occlusionTexture effect that can be specified in these nodes.
occlusion(color) = lerp(occlusionStrength, color, color * textureSample(occlusionTexture).r)
In effect, the occlusionTexture multiplies the input color when occlusionStrength is 1.0. the occlusionTexture has no effect when when occlusionStrength is 0.0. Values in-between of occlusionStrength allow to smoothly interpolate between these two states.
The applyColorPerVertex(vector4color) is used to change the color in case geometry uses Color or ColorRGBA nodes. All the lighting models use this function, although it affects a different parameter: emissiveParameter in case of unlit model, diffuseParameter in case of Phong model, and baseParameter in case of physical model. The function returns:
Resulting rgb is derived from the values in the Color node.
Resulting a (alpha component) is taken from input color.a in this case.
Resulting rgba vector is derived from the values in the ColorRGBA node.
The future X3D versions may introduce an option for Color and ColorRGBA to multiply the input color, instead of replacing it.
Moreover we define the following vectors:
The following definitions are specific to a light source i, which is indicated by a subscript in this text:
attenuationi= 1 / max(c1 + c2 × lightDistance + c3 × lightDistance2 , 1)
where
c1, c2, c3 are the values from light i attenuation field.
lightDistance is the distance from light to point on geometry, in light's coordinate system.
The following conditions indicate that light source i does not affect this geometry:
shadowTesti scales down the light contribution if the light source is obscured by a shape casting shadow.
shadowTesti is 1.0 if the light source i has shadows field equal FALSE.
Otherwise, shadowTesti is 1.0 if the light source i has shadows field equal TRUE but nothing obscures the light. That is, there is no Shape (that has visible and castShadow equal TRUE) between the light source position and the given point. The DirectionalLight is treated like a point in infinity for this purpose, which means that shadow rays are all parallel to the light direction.
Otherwise, shadowTesti is 1.0 - shadowIntensity. This case occurs when shadows field equals TRUE and the light is obscured. For example, shadowIntensity equal 1.0 (the default) means that light contribution drops to zero when the light is obscured by the shadow caster.
Table 17.4 — Calculation of the spotlight factor
Condition (in order) | spot i = |
---|---|
lighti is PointLight or DirectionalLight | 1 |
spotAngle ≥ SpotLight.cutOffAngle | 0 |
spotAngle ≤ SpotLight.beamWidth | 1 |
SpotLight.beamWidth < spotAngle < lightSource.cutOffAngle | (spotAngle - SpotLight.cutOffAngle) / (SpotLight.beamWidth - SpotLight.cutOffAngle) |
The applyFog(vector4color) is used to change the color using the fog. Is it used by all lighting models, as the last operation performed on the color. The definition is:
applyFog(color) = lerp(fogInterpolant(fogDistance), fogColor, color)
where:
Table 17.5 — Calculation of the fogInterpolant(FogDistance) function:
Condition | fogInterpolant(fogDistance) = |
---|---|
no fog | 1 |
fogType "LINEAR", fogDistance < fogVisibility | (fogVisibility - fogDistance) / fogVisibility |
fogType "LINEAR", fogDistance > fogVisibility | 0 |
fogType "EXPONENTIAL", fogDistance < fogVisibility | exp(- FogDistance / (fogVisibility - fogDistance)) |
fogType "EXPONENTIAL", fogDistance > fogVisibility | 0 |
A Shape node is unlit if either of the following is true:
In the first two cases above, the rendering is exactly equivalent as if the Appearance node was provided (not NULL), and the material field inside contained an UnlitMaterial with all the fields at their default. Effectively, it means a white untextured unlit material is the default.
NOTE Geometry nodes that represent lines or points do not support lighting if the normal vectors for them are not provided.
If the shape is unlit, the RGBA color of the shape at each point on the shape's geometry is calculated using this equation:
fragmentColor = applyFog(mixTexture(applyColorPerVertex(emissiveParameter), emissiveTextureParameter))
where:The Shape node is lit with a Phong lighting model if the Appearance node is specified for the Shape, and the material field contains a Material node.
NOTE This node is simply called Material for historical reasons. Conceptually, you should think about it now as a PhongMaterial.
The rendered fragment (pixel) color is determined by these equations:
fragmentColor = applyFog(emissiveParameter + occlusion(sumOverAllLights(lightContributioni)))
lightContributioni= oni × shadowTesti × lightColori × attenuationi × spoti × (ambienti+ diffusei+ speculari)
An ideal X3D implementation will evaluate the following lighting equation at each point on a lit surface. The means that we advise using Phong shading and assume it when writing equations below. For implementations that perform Gouraud shading see 17.2.2.8 Gouraud shading section.
The meaning of all the terms is explained below.
Material parameters
First, the parameters whose value does not depend on the light source:
The material diffuseParameter is calculated as follows:
diffuseParameter = mixTexture(applyColorPerVertex(diffuseParameter), diffuseTextureParameter) where:
The remaining parameters are defined below:
ambientParameter = ambientIntensity ×diffuseParameter.rgb× textureSample(ambientTexture).rgb
emissiveParameter = emissiveColor × textureSample(emissiveTexture).rgb
specularParameter = specularColor × textureSample(specularTexture).rgb
shininessParameter = shininess × textureSample(shininessTexture).a × 128
In the above equations, if the given texture is NULL then behave as if the textureSample(texture) returned a white opaque value (1, 1, 1, 1).
Light parameters
Now we can define terms that depend on the light source:
ambienti= lightSource.ambientIntensity × ambientParameter
diffusei = lightSource.intensity × diffuseParameter × (N· L)
speculari = lightSource.intensity × specularParameter × (N· ((L + V) /| L+ V|))shininessParameter
The Phong lighting equations are based on the simple illumination equations given in [FOLEY] and [OPENGL].
The Shape node is lit with a Physical lighting model if the Appearance node are specified for the Shape, and the material field contains a PhysicalMaterial node. We perform in this case a physically-based rendering.
The rendered fragment (pixel) color is determined by these equations:
fragmentColor = applyFog(emissiveParameter + occlusion(sumOverAllLights(lightContributioni)))
lightContributioni= oni × shadowTesti × lightColori × attenuationi × spoti × physicalLightContributioni
The input values used by the physical lighting equation are as follows:
baseParameter = mixTexture(applyColorPerVertex(baseParameter), baseTextureParameter) where:
metallicParameter = PhysicalMaterial.metallic × textureSample(PhysicalMaterial.metallicRoughnessTexture).b
roughnessParameter = PhysicalMaterial.roughness × textureSample(PhysicalMaterial.metallicRoughnessTexture).g
If the metallicRoughnessTexture is NULL, then metallicParameter and roughnessParameter are just equal to (respectively) metallic and roughness values given by the PhysicalMaterial node.
The physical lighting model uses the baseParameter, metallicParameter and roughnessParameter to calculate the physicalLightContributioni value in accordance with the physically based rendering equations as specified in 2.[GLTF].
An ideal X3D implementation will evaluate the lighting equation at each point on a lit surface. The lighting equations in previous sections assume that you use Phong shading (not to be confused with Phong lighting model). In case of Phong shading, lighting is calculated at each fragment (pixel of the screen).
However, some implementations perform Gouraud shading, either by default, or as an option for the user (for efficiency), or as a fallback for an older GPUs. In such case, the lighting equations given above cannot be reproduced precisely. In Gouraud shading, you calculate lighting per-vertex, which means that it does not make sense to use texture information to modify material parameters.
In case when Gouraud shading is used we recommend this algorithm:
If the given texture is NULL, then use the Appearance.texture. If the Appearance.texture is also NULL, no texture is used.
All channels (RGB and alpha) are affected by the main texture.
This method of determining the main texture is deliberately 100% consistent with:
This recommendation tries to preserve the intended look as much as possible in Gouraud shading.
NOTE This recommendation actually does not change anything in case of UnlitMaterial. And this is correct, Gouraud shading actually does not change how the UnlitMaterial can be implemented.
NOTE When using PhysicalMaterial on older hardware, some implementations may fall back to the Phong lighting model. If this is necessary, we recommend using PhysicalMaterial.baseColor as the Phong diffuse factor, and PhysicalMaterial.baseTexture as the texture to multiply the resulting color.
Geometric objects can cast shadows, meaning that the amount of light reaching a given surface is decreased if a light source is obscured by occluding geometry. Intervening geometry is only considered for occlusion effects when the X3DShapeNode field castShadow is TRUE.
Multiple light sources can have shadows enabled. Lighting contributions from each light source, and the intensity of corresponding shadows that reduce light available at end points, are each computed independently before reaching lit surface points.
High-fidelity physical effects such as umbra, penumbra and antumbra may be optionally applied. X3D browser implementations are allowed some variations in shadow rendering.
X3DLightNode : X3DChildNode { SFFloat [in,out] ambientIntensity 0 [0,1] SFColor [in,out] color 1 1 1 [0,1] SFBool [in,out] global FALSE SFFloat [in,out] intensity 1 [0,∞) SFNode [in,out] metadata NULL [X3DMetadataObject] SFBool [in,out] on TRUE SFBool [in,out] shadows FALSE SFFloat [in,out] shadowIntensity 1 [0,1] }
The X3DLightNode abstract node type is the base type from which all node types that serve as light sources are derived. A description of the ambientIntensity, color, intensity, and on fields is in 17.2.1 Light source semantics. A description of the global field is in 17.2.1.2 Scoping of lights.
The shadows field indicates whether or not lighting from this node casts a shadow behind illuminated X3DShapeNode geometry.
The shadowIntensity field defines how much light is obscured by shapes that cast shadows, ranging from 0 (light not obscured, no visible shadows) to 1 (light completely obscured, full-intensity shadows). The shadowIntensity field has no effect when the shadows field is FALSE.
DirectionalLight : X3DLightNode { SFFloat [in,out] ambientIntensity 0 [0,1] SFColor [in,out] color 1 1 1 [0,1] SFVec3f [in,out] direction 0 0 -1 (-∞,∞) SFBool [in,out] global FALSE SFFloat [in,out] intensity 1 [0,∞) SFNode [in,out] metadata NULL [X3DMetadataObject] SFBool [in,out] on TRUE SFBool [in,out] shadows FALSE SFFloat [in,out] shadowIntensity 1 [0,1] }
The DirectionalLight node defines a directional light source that illuminates along rays parallel to a given 3-dimensional vector. A description of the ambientIntensity, color, intensity, and on fields is in 17.2.1 Light source semantics. A description of the global field is in 17.2.1.2 Scoping of lights.
The direction field specifies the direction vector of the illumination emanating from the light source in the local coordinate system. Light is emitted along parallel rays from an infinite distance away. A directional light source illuminates only the objects in its enclosing parent group. The light may illuminate everything within this coordinate system, including all children and descendants of its parent group. The accumulated transformations of the parent nodes affect the light.
DirectionalLight nodes do not attenuate with distance. A precise description of X3D's lighting equations is contained in 17.2.2 Lighting model.
PointLight : X3DLightNode { SFFloat [in,out] ambientIntensity 0 [0,1] SFVec3f [in,out] attenuation 1 0 0 [0,∞) SFColor [in,out] color 1 1 1 [0,1] SFBool [in,out] global TRUE SFFloat [in,out] intensity 1 [0,∞) SFVec3f [in,out] location 0 0 0 (-∞,∞) SFNode [in,out] metadata NULL [X3DMetadataObject] SFBool [in,out] on TRUE SFFloat [in,out] radius 100 [0,∞) SFBool [in,out] shadows FALSE SFFloat [in,out] shadowIntensity 1 [0,1] }
The PointLight node specifies a point light source at a 3D location in the local coordinate system. A point light source emits light equally in all directions; that is, it is omnidirectional. PointLight nodes are specified in the local coordinate system and are affected by ancestor transformations. A description of the global field is in 17.2.1.2 Scoping of lights.
Subclause 17.2.1 Light source semantics, contains a detailed description of the ambientIntensity, color, and intensity fields.
A PointLight node illuminates geometry within radius length base units of its location. Both radius and location are affected by ancestors' transformations (scales affect radius and transformations affect location). The radius field shall be greater than or equal to zero.
PointLight node's illumination falls off with distance as specified by three attenuation coefficients. The attenuation factor is:
1/max(attenuation[0] + attenuation[1] × r + attenuation[2] × r 2, 1)
where r is the distance from the light to the surface being illuminated. The default is no attenuation. An attenuation value of (0, 0, 0) is identical to (1, 0, 0). Attenuation values shall be greater than or equal to zero. A detailed description of X3D's lighting equations is contained in 17.2.2 Lighting model.
SpotLight : X3DLightNode { SFFloat [in,out] ambientIntensity 0 [0,1] SFVec3f [in,out] attenuation 1 0 0 [0,∞) SFFloat [in,out] beamWidth π*3/16 (0,π/2] SFColor [in,out] color 1 1 1 [0,1] SFFloat [in,out] cutOffAngle π/2 (0,π/2] SFVec3f [in,out] direction 0 0 -1 (-∞,∞) SFBool [in,out] global TRUE SFFloat [in,out] intensity 1 [0,∞) SFVec3f [in,out] location 0 0 0 (-∞,∞) SFNode [in,out] metadata NULL [X3DMetadataObject] SFBool [in,out] on TRUE SFFloat [in,out] radius 100 [0,∞) SFBool [in,out] shadows FALSE SFFloat [in,out] shadowIntensity 1 [0,1] }
The SpotLight node defines a light source that emits light from a specific point along a specific direction vector and constrained within a solid angle. Spotlights may illuminate geometry nodes that respond to light sources and intersect the solid angle defined by the SpotLight. Spotlight nodes are specified in the local coordinate system and are affected by ancestors' transformations. A description of the global field is in 17.2.1.2 Scoping of lights.
A detailed description of ambientIntensity, color, intensity, and the lighting equations of X3D is provided in 17.2.1 Light source semantics. More information on lighting concepts can be found in 17.2.2 Lighting model, including a detailed description of the X3D lighting equations.
The location field specifies a translation offset of the centre point of the light source from the light's local coordinate system origin. This point is the apex of the solid angle which bounds light emission from the given light source. The direction field specifies the direction vector of the light's central axis defined in the local coordinate system.
The on field specifies whether the light source emits light. If on is TRUE, the light source is emitting light and may illuminate geometry in the scene. If on is FALSE, the light source does not emit light and does not illuminate any geometry.
The radius field specifies the radial extent of the solid angle and the maximum distance from location that may be illuminated by the light source. The light source does not emit light outside this radius. The radius shall be greater than or equal to zero.
Both radius and location are affected by ancestors' transformations (scales affect radius and transformations affect location).
The cutOffAngle field specifies the outer bound of the solid angle. The light source does not emit light outside of this solid angle. The beamWidth field specifies an inner solid angle in which the light source emits light at uniform full intensity. The light source's emission intensity drops off from the inner solid angle (beamWidth) to the outer solid angle (cutOffAngle) as described in the following equations:
angle = the angle between the Spotlight's direction vector and the vector from the Spotlight location to the point to be illuminated if (angle ≥ cutOffAngle): multiplier = 0 else if (angle ≤ beamWidth): multiplier = 1 else: multiplier = (angle - cutOffAngle) / (beamWidth - cutOffAngle) intensity(angle) = SpotLight.intensity × multiplier
If the beamWidth is greater than the cutOffAngle, beamWidth is defined to be equal to the cutOffAngle and the light source emits full intensity within the entire solid angle defined by cutOffAngle. Both beamWidth and cutOffAngle shall be greater than 0.0 and less than or equal to π/2. Figure 17.1 depicts the beamWidth, cutOffAngle, direction, location, and radius fields of the SpotLight node.
SpotLight illumination falls off with distance as specified by three attenuation coefficients. The attenuation factor is:
1 /max(attenuation[0] + attenuation[1] × r + attenuation[2] × r2 , 1 )
where r is the distance from the light to the surface being illuminated. The default is no attenuation. An attenuation value of (0, 0, 0) is identical to (1, 0, 0). Attenuation values shall be greater than or equal to zero. A detailed description of X3D's lighting equations is contained in 17.2.2 Lighting model.
The Lighting component provides three levels of support as specified in Table 17.6.
Table 17.6 — Lighting component support levels
Level | Prerequisites | Nodes/Features | Support |
---|---|---|---|
1 | Core 1 Shape 1 |
||
X3DLightNode (abstract) | n/a | ||
DirectionalLight | Not scoped by parent Group or Transform. | ||
Support for Gouraud and Phong shading. | |||
2 | Core 1 Shape 1 |
||
All Level 1 Lighting nodes | All fields as supported in Level 1. | ||
PointLight | radius optionally supported. Linear attenuation. | ||
SpotLight | beamWidth optionally supported. radius optionally supported. Linear attenuation. | ||
3 | Core 1 Shape 2 |
||
All Level 2 Lighting nodes | All fields fully supported. | ||
EnvironmentLight | All fields fully supported. | ||
Support for Physical and Unlit lighting models. |