Here's the revised and expanded explanation from the graphics team:
It is challenging to explain how all the properties of lights and shapes are combined to calculate final per-pixel colors seen on the screen. The light “scale and offset” values only affect the diffuse color component for a pixel. This pseudo-code shows how the diffuse color is calculated given a point, the surface normal at that point, the shape’s diffuse color at that point, and a collection of lights:
// IN: p is the surface point, n is the normal vector at that point, surfaceDiffuseColor is the color of the surface at that point.
// OUT: diffuse and specular colors are returned
Color CalculateGouraudLighting( const Point3D& p, const Vector3D& n, const Color& surfaceDiffuseColor, const LightArray& lights )
{
// Init RGBA diffuse color
Color diff( 0.0f, 0.0f, 0.0f, 1.0f );
for( int i = 0; i < lights.Count(); i++ )
{
// Get this light's colors.
const IModelLight& light = lights[ i ];
Color lightColor = light.GetColor();
// Get light direction
Vector3D lightDir = light.DirectionToPoint( p );
// Calc diffuse contribution if needed.
if( light.AffectsDiffuse() )
{
// Calc scalar dot product from surface normal and light direction
float dot = -( n * lightDir );
// Apply scale and offset to adjust light attenuation
dot = dot * light.GetWrapScale() + light.GetWrapOffset();
if( dot >= 1.0f )
{
// Add in full diffuse contribution
diff.r += surfaceDiffuseColor.r * lightColor.r;
diff.g += surfaceDiffuseColor.g * lightColor.g;
diff.b += surfaceDiffuseColor.b * lightColor.b;
}
else if ( dot > 0.0 )
{
// Add in diffuse contribution attenuated by the scalar dot product
diff.r += dot * surfaceDiffuseColor.r * lightColor.r;
diff.g += dot * surfaceDiffuseColor.g * lightColor.g;
diff.b += dot * surfaceDiffuseColor.b * lightColor.b;
}
} // end of diffuse calculation
} // end of loop over each light
return diff;
}
Here is where the scale and offset of individual key & fill lights contribute to the diffuse lighting calculation for a given surface point. Scale values < 1, or negative offset values, make the light illuminate the shape less. Scale values > 1, or positive offset values, make the light illuminate the shape more.
There are further factors that can affect the color ultimately shown on screen. We use a non-directional ambient light that provides a dim base lighting for the parts of a shape that aren’t facing the light, so they are never totally dark. Lights also contribute specular highlights, too. And if a shape has a metallic surface, the diffuse and specular colors are further blended.
I hope that is more helpful. Let me know if you have more questions.
Best regards,
Tom Jebo
Sr Escalation Engineer
Microsoft Open Specifications Support