## 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.