How feSpecularLighting Creates 3D SVG Highlights
The feSpecularLighting SVG filter primitive simulates
realistic 3D surface highlights by calculating specular reflection
across a 2D graphic using the Phong reflection model. By treating the
alpha channel or luminance of an input image as a heightmap, the filter
calculates surface normals and simulates how a virtual light source
reflects directly into the viewer’s eye, adding depth, gloss, and
metallic or plastic textures to otherwise flat vector artwork.
The Virtual Surface Heightmap
To create a three-dimensional effect from a two-dimensional object,
feSpecularLighting generates an elevation map (bump map)
based on the opacity of the input element (in="SourceAlpha"
or in="SourceGraphic").
- Alpha-to-Height Conversion: Fully opaque pixels represent the highest elevation, while transparent pixels represent the lowest.
- Surface Normals: The filter calculates gradient slopes across neighboring pixels (\(\frac{\partial z}{\partial x}\) and \(\frac{\partial z}{\partial y}\)) to determine the 3D surface normal vector (\(\vec{N}\)) for every point on the shape.
surfaceScaleAttribute: This value acts as a height multiplier. A highersurfaceScalesteepens the calculated slopes, making the simulated 3D geometry appear taller and more pronounced.
Light Source Computation
The specular calculation requires a directional light vector (\(\vec{L}\)). In SVG, this is defined by
nesting one of three light source elements inside
feSpecularLighting:
<feDistantLight>: Simulates light from an infinite distance (like the sun) with constant angle and intensity viaazimuthandelevationattributes.<fePointLight>: Simulates an omnidirectional light bulb at a specific 3D coordinate (x,y,z).<feSpotLight>: Simulates a focused cone of light directed at a specific target point.
The Phong Reflection Model
feSpecularLighting calculates light intensity using the
Phong reflection model, which isolates the sharp, mirror-like
reflections (specular highlights) that occur when light bounces off a
glossy surface toward the viewer’s eye vector (\(\vec{V}\)).
The brightness at any given pixel is determined by: \[I = k_s \cdot (\vec{N} \cdot \vec{H})^{\text{specularExponent}} \cdot \text{LightColor}\]
Where: * \(\vec{H}\)
(Halfway Vector): The vector halfway between the light
direction and the viewer direction. *
specularConstant (\(k_s\)): Controls the reflection
coefficient. Values greater than 1.0 boost highlight
brightness, producing metallic finishes. *
specularExponent: Controls surface
shininess or smoothness. Lower values (e.g., 5 to 10) spread the
highlight across a wide, soft area, simulating matte or dull materials.
Higher values (e.g., 50 to 100+) narrow the highlight into a tight,
sharp glint, simulating polished glass or wet surfaces. *
lighting-color: Defines the RGB color of
the reflected highlight.
Compositing the Result
The raw output of feSpecularLighting is not the lit
graphic itself, but an isolated light map containing only the calculated
highlights against a transparent or black background.
To complete the 3D simulation, the highlight layer must be combined
with the underlying artwork using <feComposite> or
<feMerge>. Typically, developers use
<feComposite operator="in"> to restrict the highlight
to the element’s boundaries and
<feComposite operator="arithmetic"> to add the
specular highlights directly over the original color layer and any
ambient/diffuse lighting generated by
<feDiffuseLighting>.