6 min read

Understanding the Different Types of Light Source Filters in SVG

Table of Contents

Introduction

There are multiple light source-related filters in SVG, and they can seem a bit complex. Today, I’m going to take the time to study them thoroughly and find ways to understand them all—who knows, I might need to use them someday!


fePointLight Filter

As the name implies, this is a point light source filter effect.

Like many other light source filters, it needs to be used within lighting filter elements to take effect.

In SVG, lighting filters refer to the <feDiffuseLighting> and <feSpecularLighting> elements.

The former refers to diffuse reflection, and the latter to specular reflection.

In fact, SVG light source filters are quite simple: first, determine the type of light source—whether it’s a point light (bulb), parallel light (sun), or spotlight (floodlight)—and second, decide what type of reflection occurs on the surface—either diffuse or specular. These are basic concepts from physics classes.

To better understand this, it’s necessary to first explore the <feDiffuseLighting> and <feSpecularLighting> elements.


Example Using the <feSpecularLighting> Element

Let’s start with an example.

We’ll use <feSpecularLighting>, the element for specular reflection, to create a point light source button effect.

Here’s the related SVG code (copy and paste it into any part of your page):

<svg
  width="0"
  height="0"
  xmlns="http://www.w3.org/2000/svg"
  xmlns:xlink="http://www.w3.org/1999/xlink">
  <defs>
    <filter id="spotlight">
      <feSpecularLighting
        result="spotlight"
        specularConstant="0.5"
        specularExponent="50"
        lighting-color="#FFF">
        <fePointLight x="20" y="10" z="50" />
      </feSpecularLighting>
      <feComposite
        in="SourceGraphic"
        in2="spotlight"
        operator="arithmetic"
        k1="0"
        k2="1"
        k3="1"
        k4="0" />
    </filter>
  </defs>
</svg>

Next, just apply the CSS code to the element that will use the filter effect, like this:

 button.apply-filter {
  filter: url(#spotlight);
}

Now, you’ll see the lighting effect at the top left corner of the button(Let’s assume you have a button element in your HTML that needs the effect applied.).

Here’s the effect you’ll see:

effect1

Attributes

Supports the following five attributes:

AttributeDescription
inThe ID of the input light source element, which can be omitted if the light source element is a child element.
surfaceScaleRepresents the surface height of the light source element.
specularConstantRepresents the specular reflection constant. The higher this value, the brighter and more noticeable the light and shadow effect.
specularExponentThe specular reflection exponent.
kernelUnitLengthThis attribute is deprecated. It defines the core unit length but is no longer recommended for use.

Here is the syntax for the <fePointLight> element:

The syntax for the <fePointLight> filter is simpler. It takes three values: x, y, and z, which represent the x and y coordinates, and the height of the light source.


Now, let’s talk about the <feDiffuseLighting> element.

Now, let’s discuss the diffuse lighting filter.

Using the same example, if we want to apply a diffuse lighting effect to the button, how should we handle it? Here’s a use case:

<svg
  width="0"
  height="0"
  xmlns="http://www.w3.org/2000/svg"
  xmlns:xlink="http://www.w3.org/1999/xlink">
  <defs>
    <filter id="spotlight">
      <feDiffuseLighting
        result="spotlight"
        diffuseConstant="1"
        lighting-color="#FFF">
        <fePointLight x="20" y="10" z="40" />
      </feDiffuseLighting>
      <feComposite
        in="SourceGraphic"
        in2="spotlight"
        operator="arithmetic"
        k1="1"
        k2="0"
        k3="0"
        k4="0" />
    </filter>
  </defs>
</svg>
button.apply-filter {
  filter: url(#spotlight);
}

Now, the button’s lighting effect will look like this:

effect2

You can see that a shadow appears, while the specular reflection is a bright light overlay.

Attributes

AttributeDescription
inSame as <feSpecularLighting>.
surfaceScaleThe surfaceScale attribute represents the height of the surface in the light source element.
diffuseConstantRepresents the kd value in the Phong lighting model. In SVG, this can be any non-negative number.
kernelUnitLengthSame as <feSpecularLighting>.

Phong reflection model

reflection model (also called Phong illumination or Phong lighting) is an empirical model of the local illumination of points on a surface designed by the computer graphics researcher Bui Tuong Phong. In 3D computer graphics, it is sometimes referred to as “Phong shading”, particularly if the model is used with the interpolation method of the same name and in the context of pixel shaders or other places where a lighting calculation can be referred to as “shading”.

For a more detailed explanation, refer to the wiki entry. Phong reflection model.


In addition, there are <feDistantLight> and <feSpotLight>

Finally, let’s go over directional light and spotlight sources. We’ll use examples to see how each one affects a button.

Here is a screenshot of the final effects for each different light source:

effect3

feDistantLight syntax

feDistantLight represents distant or directional light, with the sun being a typical example. It supports two parameters:

azimuth

This specifies the azimuth angle. The image below shows the diffuse shadow effect at 0 and 240 degrees (applied to a circular shape).

effect4

elevation

This specifies the height angle between the light source and the surface being illuminated. For example, sunrise or sunset would have an angle of 0, while the sun directly overhead would be 90. The image below shows the effect at elevation angles of 0 and 45 degrees (assuming a default azimuth angle of 0, meaning light is coming from right to left).

effect5

feSpotLight Syntax

feSpotLight represents a spotlight source, such as a theater stage spotlight or a flashlight, which can also be considered a concentrated light source.

The syntax is as follows:

  • x, y, z

    • Coordinates of the light source.
  • pointsAtX, pointsAtY, pointsAtZ

    • Coordinates of the light’s target point.
  • specularExponent

    • The specular exponent attribute, controlling the light’s focus. The higher the value, the more intense the light.
  • limitingConeAngle

    • The angle (in degrees) between the spotlight’s axis (the line from the light source to its target) and the cone of light. This effectively defines a limiting cone that restricts the area where light is cast; no light appears outside this cone.

All of the values above can be animated with SVG’s <animate> and <set> elements for dynamic effects.

Finally

Alright, those are the main SVG lighting filters related to shadows.

These filters open up new possibilities for creating dynamic effects. For instance, when presenting card elements, could you use a spotlight effect, similar to the dramatic lighting in a movie opening scene? Absolutely.

Here’s a small task for you: Can you create an effect using SVG that’s similar to Pixar animation?

effect6

Here’s an example I created for you, which could give you a hint.

effect7

<html>
    <head>
        <style>
           button.apply-filter {
  filter: url(#lightMe3);
}
        </style>
    </head>
    <body>
      <svg
  width="0"
  height="0"
  xmlns="http://www.w3.org/2000/svg"
  xmlns:xlink="http://www.w3.org/1999/xlink">
  <defs>
    <filter id="lightMe3">
      <feDiffuseLighting in="SourceGraphic" result="light" lighting-color="white">
        <feSpotLight
          id="spotlight"
          x="100"
          y="5"
          z="30"
          limitingConeAngle="20"
          pointsAtX="10"
          pointsAtY="10"
          pointsAtZ="0" />
      </feDiffuseLighting>
  
      <feComposite
        in="SourceGraphic"
        in2="light"
        operator="arithmetic"
        k1="1"
        k2="0"
        k3="0"
        k4="0" />
    </filter>
  </defs>
  <animate 
    xlink:href="#spotlight" 
    attributeName="pointsAtX" 
    from="10" 
    to="100" 
    dur="2s" 
    repeatCount="indefinite" 
    keyTimes="0; 0.5; 1" 
    values="10; 90; 100"/>
</svg>
        <button>default button</button>
        <button class="apply-filter">apply filter button</button>
    </body>
</html>