In our implementation of the empirical Blinn-Phong shading model, we are facing a problem with light-bleeding of the specular component.

The model defines the half-vector $\vec{h} = \frac{\vec{v} + \vec{l}}{||\vec{v} + \vec{l}||}$, with:

  • $\vec{v}$ the unit view vector
  • $\vec{l}$ the unit light vector (defined from surface-point to light-source).

and the specular component is proportional to ${(\vec{n} \cdot \vec{h})^+}^p$ (with $p$ as Phong exponent)

Specular light bleeding situation

Light bleeding occurs in certain configurations when the light vector $\vec{l}$ is facing away from the surface (i.e. >90° angle from the normal $\vec{n}$).

Such a configuration is illustrated by the diagram below:

enter image description here

Here, we can see that although the light should not contribute to the surface lighting, the computed half-vector is close to the normal, and thus an important specular contribution will be added by the model.

We followed implementation advices from Fundamental of Computer Graphics and Real-Time Rendering, but we missed any mention of this potential problem:

  • Are we misunderstanding how to implement this shading model?
  • Or is this an inherent issue, and what would be the canonical approach to address it?

Edit bonus question:

  • What tools to draw geometric diagrams would you recommend?
  • $\begingroup$ I changed my comment to an answer $\endgroup$
    – pmw1234
    Commented Jun 11 at 11:45

1 Answer 1


N dot L will be less then zero and must be computed for the diffuse component and is typically clamped to zero. This can be incorporated into the specular highlight calculation to resolve the issue. What you are describing doesn't come up always in descriptions of Blinn-Phong lighting, I assume, because the writers want to keep things simple. But it is a real issue, I wouldn't go so far as to call it a problem with the lightning model though.

A typical way to resolve it is to add this to the specular compuation (or something like it):

specular = specular * (float)(ndotl>0.0);

  • 1
    $\begingroup$ Brilliant, thank you for the practical solution (we were wondering how to do it without branching). (Plus, the bit of confirmation this is an real issue which does not always get addressed by authors makes us feel more sane.) $\endgroup$
    – Ad N
    Commented Jun 11 at 13:36
  • $\begingroup$ Sadly, this can lead to an abrupt cut-off of the specular contribution between adjacent polygons where the change of ndotl sign occurs, which is very noticeable on smooth surfaces. Maybe some sort of windowing function might be used on ndotl and the result used as the operand in place of (float)ndotl to smooth things out. $\endgroup$
    – Ad N
    Commented Jun 11 at 14:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.