Charles Petzold

The Mysterious Normals Property (Part 1)

December 16, 2006
Roscoe, NY

These two figures are known as square cuboids:

But notice how differently they're colored. The one on the left has gradiated shades of blue with highest intensity in the upper-left-front vertex. In the one on the right, each of the three visible faces is colored uniformly.

Both figures were defined in WPF 3D in the following XAML file:

Both figures have the same light sources, which is a combination of AmbientLight and DirectionalLight. The figure on the left is defined with a mesh geometry with a Positions property that contains the 8 points for the four vertices of the cuboid:

<MeshGeometry3D Positions="0 0  0, 1 0  0, 1 1  0, 0 1  0,
0 0 -4, 1 0 -4, 1 1 -4, 0 1 -4"

TriangleIndices="0 1 2, 0 2 3
0 3 4, 3 7 4,
2 6 3, 3 6 7,
1 5 2, 2 5 6,
0 5 1, 0 4 5,
4 6 5, 4 7 6" />

The one on the right defines separate vertices for each of the three visible faces:

<MeshGeometry3D Positions="0 0 0, 1 0 0, 1 1  0, 0 1  0,
1 1 0, 0 1 0, 1 1 -4, 0 1 -4,
0 0 0, 0 1 0, 0 0 -4, 0 1 -4"

TriangleIndices="0 1 3, 1 2 3
4 6 5, 5 6 7
8 9 10, 9 11 10" />

The three hidden faces are not defined in this markup (they would require 12 more 3D points and 6 additional integer triplets), but they wouldn't make any difference in the appearance.

So, why does a cube defined with 8 vertices look so different from a cube constructed from separate flat surfaces? It all has to do with the most mysterious property of MeshGeometry3D: Normals.

Forget everything you may have read read in the WPF 3D documentation about Normals being a collection of vectors that determine how faces of 3D figures are oriented. It's just not true. The Normals collection is in a one-to-one correspondence with the Positions collection and determines how vertices — and the edges and faces around these vertices — are oriented and hence, how they reflect directional light. If you don't supply a Normals collection, one is provided for you, which is what's causing the behavior illustrated in this program.

I have made it my short-term goal in life to "crack" the Normals property and figure out how to use it intelligently. I'll be reporting my progress right here.