Skip to content

29. Mathematics of Lighting and Shading part 3

Dated: 01-07-2025

Traditional 3D Hardware-accelerated Lighting Models

The traditional approach in real time computer graphics has been to calculate lighting at a vertex as a sum of the ambient,1 diffuse,1 and specular light.1

\[i_{\text{total}} = k_a \cdot i_a + \sum (k_d \cdot i_d + k_s \cdot i_s)\]

This is called a local lighting model since the only light on a vertex is from a light source, not from other objects. The reflection coefficients \(k\) are in the \([0, 1]\) range and are specified as part of the material property.

However, it does fail to take into account any gross roughness or anything other than perfect isotropic reflection.

Ambient1 Light

It is a light which comes from all directions (i.e. the environment) but there are too many sources and it would talk a lot of resources to compute so we just have an \(x\) value for simplicity and we call it ambient light1 which equally illuminates all objects.

\[i_a = m_a \otimes s_a\]

Where \(i_a\) is ambient light intensity, \(m_a\) is ambient material color and \(s_a\) is light source ambient color.

Diffuse light

Diffuse light1 is the light that is absorbed by a surface and is reflected in all directions. Regardless of the direction from which we view an object with a stationary diffuse light1 source on it, the brightness of any point on the surface will remain the same. Thus, unlike ambient light,1 the intensity of diffuse light1 is directional and is a function2 of the angle of the incoming light and the surface. This type of shading is called Lambertian shading after Lambert's cosine law, which states that the intensity of the light reflected from an ideal diffuse1 surface is proportional to the cosine of the direction of the light to the vertex normal.3
There are per-vertex normals3 in with each vertex has a normal3 associated with it and then there are per-polygon normals3 which have one normal3 shared across all vertices of the polygone.

OpenGL can specify per-polygon normals3 but Direct3D cannot.

\[i_d = (\hat n \cdot \hat l) i_a\]
\[i_d = (\hat n \cdot \hat l) (m_d \otimes s_d)\]

here \(\hat l\) is the direction to the light source.

Practically speaking, we don't want vertices where light cannot shine on

cs602_e_29_1.svg

Dotted line illustrates direction of light from source to surface. The dot product4 for light inside the surface will be negative.

\[i_d = \max(0, (\hat n \cdot \hat l) (m_d \otimes s_d))\]

Problem with diffuse light1 alone is that, it is independent of the viewing angle.

Specular light

While ambient light1 gives the object an illuminated matte surface, specular light is what gives the highlights to an object. These highlights are greatest when the viewer is looking directly along the reflection angle from the surface.

cs602_i_29_1.png

Comparison between specular1 and diffused1 reflection

Phong's Specular light Equation

Warnock [WARNOCK 1969] and Romney [ROMNEY 1969] were the first to try to simulate highlights using a \(\cos (n \theta)\) term. Phong Bui-Tong [BUI 1998] reformulated this into a more general model that formalized the power value as a measure of surface roughness that we approach the terms used today for specular highlights.

cs602_e_29_2.svg

\(i_s = (m_s \otimes s_s) (\hat r \cdot \hat v)^{m_s}\)

The \(m_s\) factor

The larger \(m_s\) value is, the tighter the specular highlights are.

The \((\hat r \cdot \hat v)^{m_s}\) for \(m \in [0, 1]\) doesn't get any brighter.

\[\vec r = \frac{2(\vec n \cdot \vec l) \vec n}{|n|^2} - \vec l\]
Proof
  • \(\vec r \cdot \vec n = \vec l \cdot \vec n\)
  • \(2(\vec r \cdot \vec n) = 2(\vec l \cdot \vec n)\)
  • \(2(\vec r \cdot \vec n) \cdot \vec n = 2(\vec l \cdot \vec n) \cdot \vec n\)
  • \((\vec r \cdot \vec n) \cdot \vec n + (\vec r \cdot \vec n) \cdot \vec n = 2(\vec l \cdot \vec n) \cdot \vec n\)
  • \(\vec r \cdot \vec n \cdot \vec n + \vec l \cdot \vec n \cdot \vec n = 2(\vec l \cdot \vec n) \cdot \vec n \quad \because (\vec r \cdot \vec n) = (\vec l \cdot \vec n)\)
  • \(\vec r |n|^2 + \vec l |n|^2 = 2(\vec l \cdot \vec n) \cdot \vec n\)
  • \(|n|^2(\vec r + \vec l) = 2(\vec l \cdot \vec n) \cdot \vec n\)
  • \((\vec r + \vec l) = \frac{2(\vec l \cdot \vec n) \cdot \vec n}{|n|^2}\)
  • \(\vec r = \frac{2(\vec l \cdot \vec n) \cdot \vec n}{|n|^2} - \vec l\)

The equation simplifies if \(\vec n\) and \(\vec l\) are normalized

\[\implies \hat r = 2(\hat n \cdot \hat l) \hat n - \hat l\]

Blinn's Simplification: OpenGL and DirectX Lighting

\[i_s = (m_s \otimes s_s)(\hat n \cdot \hat h)^{m_s}\]

where \(\vec h\) is the half angle vector4 and is defined as

\[\vec h = \frac{\vec l + \vec v}{|\vec l + \vec v|}\]

References


  1. Read more about lighting types

  2. Read more about functions

  3. Read more about surface normals

  4. Read more about vectors