We affectionately refer to DiffuseMaterial.Color, DiffuseMaterial.AmbientColor, SpecularMaterial.Color, and EmissiveMaterial.Color as the “color knobs.” The color knobs are probably the least understood WPF3D feature because they were one of the last (if not the last) features we added and most of the things you can do with them are not obvious. Hopefully this article will give you insight into how the properties work and help you write better XAML exporters.
The full lighting equation used by WPF is definitely something we need to cover later, but essentially the final color for a single Material is going to be: Color * lighting result * Brush. DiffuseMaterial includes both ambient and diffuse lighting so it has two color properties making the equation: (AmbientColor * ambient lighting result + Color * diffuse lighting result) * Brush. From this equation, you can see that you can’t just set Color and be done — you also need a Brush. By default, all of the Color properties are white giving them no effect on the final appearance.
Now let’s look at a few ways to use these properties. (By the way, if I refer to a color channel going from 0.0 -> 1.0 it’s the same as 0 -> 255 if you’re using bytes)
Color Knobs as a Filter
Let’s say a GeometryModel3D with a DiffuseMaterial is being hit by a light containing red. If you set the red channel of the color knob to 0, the mesh won’t reflect any red light. If you set it to 1, it’ll reflect all of the red light the Brush reflects. By changing the value between 0 and 1 you can “dial in” how much you want to reflect back. This is how we started calling them “knobs.”
The color knobs are full colors so they do have alpha. Setting the alpha value does what you would expect (e.g. alpha of 0.5 makes it half transparent). There is one exception to things and, surprise, it’s DiffuseMaterial. Only DiffuseMaterial.Color.A affects the transparency of the Model. Turning down DiffuseMaterial.AmbientColor.A does make the ambient component transparent and increase the impact of the diffuse component, but it does not affect Model transparency.
DiffuseMaterial, SpecularMaterial, EmissiveMaterial… where’s AmbientMaterial? We don’t have it. What do you if you want a Model to respond to only ambient light? Before color knobs, it couldn’t be done. With color knobs, create a DiffuseMaterial, set Color to (0,0,0,0), and all diffuse contribution will be wiped out leaving you with just ambient!
Fully Illuminated Solid Colors
Say you wanted to make a Model look green. You have two good options: a white brush with a green color knob or a green brush with a white (the default value) color knob. Is there a difference between the two? It depends on how much light is hitting the Model. If the amount of light hitting isn’t greater than 1.0 in each channel, then they’re equivalent. If not, here’s what happens:
Both pictures are of a sphere mesh with a DiffuseMaterial and two full power point lights shining on it. On the left, the the Color is set to #ff006000 and the Brush is set to white. On the right, the Color is set to white and the Brush is a #ff006000 SolidColorBrush. Why is the one on the left so vibrant and the one on the right so lackluster?
In the graphics pipeline, lighting is calculated in the vertex processing stage and textures are sampled later on in pixel processing. In WPF, all Brushes applied to 3D are done as textures — even SolidColorBrushes. Unfortunately, the graphics card clamps colors coming out of the vertex stage to 1 so no matter how many hundreds of lights you have you will never be able to exceed the color of the SolidColorBrush. As you can see in the image on the right, the big solid color splotch in the middle has a value of #ff006000, the color of the SCB. The color knob value is incorporated during vertex processing so it is multiplied by the unclamped lighting result. For those of you used to per-vertex colors in other APIs, you can think of the color knob as a single vertex color for the entire mesh. This explanation is tricky and requires some knowledge of graphics hardware but hopefully it made some sense 🙂
In general, you may end up wanting to use the color knobs for all of your solid color needs*.
* There is one minor perf issue to take note of if you don’t have a Tier 2 graphics card: If you have a MaterialGroup with more than one DiffuseMaterial or more than one SpecularMaterial and those duplicate Materials have different color knob values, you will incur a performance penalty. For example, a MaterialGroup with two DiffuseMaterials one with Color (.5, .5, .5) and one with Color (1, 1, 1). Fortunately, this doesn’t happen too often. See this MSDN article for information about tiering.