One of the new features in the next release of the XNA Framework is the addition of per-pixel lighting support in BasicEffect.
In the original version of the framework, BasicEffect always evaluated its lighting per-vertex. That means for every vertex in your model it looked up the vertex normal, evaluated the lighting equation to produce a color, and then linearly interpolated the resulting vertex colors across each triangle.
Per-vertex lighting is efficient, and it looks good on models that contain lots of highly tessellated triangles or which don’t use too much specular. It can look pretty bad on lower resolution meshes, though, such as this approximation of a sphere:
Notice how ugly and square the specular highlight appears, and how the triangle edges are painfully visible. This happens because we are only bothering to evaluate the lighting equation once per vertex. When the specular highlight is small compared to the size of the triangles this can easily miss details of the highlight shape. If the highlight falls exactly in the middle of a triangle it can even disappear entirely, since none of the vertices overlap with the highlight at all!
The solution is to move the lighting computation from the vertex shader into the pixel shader. Instead of linearly interpolating lighting results across the triangle, we interpolate normal vectors and then recompute the entire lighting equation for every single pixel. This produces a beautifully smooth specular falloff regardless of the triangle edges:
Every ointment has a fly, however, and per-pixel lighting does have some disadvantages:
- It requires a graphics card that supports pixel shader 2.0.
- It can be slower than per-vertex lighting, because there are usually more pixels than vertices.
BasicEffect leaves per-pixel lighting off by default, because of the potential performance impact. If you want to use this you must explicitly set the PreferPerPixelLighting property to true.
You don’t need to bother checking whether the graphics card has shader model 2.0, though, because the framework will do that for you and automatically fall back on per-vertex lighting if it is not available. This is why we named the property Prefer rather then Enable.
If you use BasicEffect for lighting, try setting PreferPerPixelLighting to true. Your lighting will look better, and most games won’t even notice the performance difference.