Charles Petzold

How to Get SpotLight to Work

January 24, 2007
New York, NY

Several times over the past months, I've begun exploring the SpotLight class in System.Windows.Media.Media3D and become totally frustrated. As the name suggests and the documentation attests, SpotLight is a form of light that "projects its effect in a cone-shaped area along a specified direction." Besides the Direction property (a Vector3D object), SpotLight also defines InnerConeAngle and OuterConeAngle properties to define an area of full illumination, and an outer area where the illumination falls off.

Yet, in multiple attempts, when I directed a SpotLight on a flat surface, either I got full illumination or no illumination at all depending on the angle settings. The only sample XAML file for SpotLight (available online here) was like one of those weird experiments in quantum physics: Any attempt to examine how it works causes it to stop working.

And then a few days ago, I slapped myself on the forehead, tried something different, and voilà:

That's a square with sides of 4 units in length colored with a blue brush. The SpotLight is 6 units away, with an InnerConeAngle of 15° and an OuterConeAngle of 30°. Do the math and you should calculate a radius of 0.79 units [6 * tan(15 /2)] for the fully-illuminated circle and a radius of 1.6 units [6 * tan(30/2)] of the outer circle before the illumination ends.

How did I get it to work? Easy: That 4-unit square isn't composed of just 2 triangles as a rational person would construct it. It's actually 5,000 triangles that are halves of a grid of 50-by-50 small squares. Here's the huge XAML file:

Spotlight50x50.xaml (~100K)

Is it really necessary to have all those triangles? Pretty much so, yes, if you want to get SpotLight to work. Here's the result when you cut the squares down to an 8-by-8 grid with 128 triangles:


As you can see, some strange effects crop up. Let's go down to a 4-by-4 grid with 32 triangles:


And now 2-by-2 with 8 triangles:


And finally, when we go down to just two triangles — which is how I inevitably began my experimentation with SpotLight — the light disappears entirely:


Just what is going on here?

In the 3D subsystem of the WPF, illumination is based on vertices. For any point on any triangle, the amount of reflected light is calculated as an interpolation based on the illumination of the vertices of that triangle. If those vertices aren't illuminated at all (which is the case in the final example because the vertices are at the corners of the large square) then no part of the entire triangle reflects light. If the vertices are illuminated equally, then all points in the entire triangle reflect the same amount of light. If two vertices of a triangle are illuminated the same — which is the case for some of the later examples here — then the line connecting those two vertices reflects the same amount of light, which creates some interesting (but incorrect) patterns.

Conclusion: If you want SpotLight (and also PointLight) to work correctly, chop your figures up into lots of tiny triangles.