The code for the UI lighting tutorial is located in the LightingTutorial project of the distribution. You can find different materials with their own lighting effects.

Bling's support for lighting is based on simple or local lighting model in computer graphics. Here we implement the diffuse reflection, the specular reflection, the one-time refraction and the simple diffraction. Basically, we use normal mapping to make the 2D object looks like in a 3D environment with more realistic lighting effect. Bling supports most of the lights and materials specified by WPF 3D. The documentation for these classes in WPF 3D applies to Bling.

Light Sources

As we know, without light, we can't see any color. One of the light source we used in Bling is point light, like the light bulb. The class “SpotLight” defines the point light, it has properties like position, direction, color, and inner and outer cone angles. The higher the light is, the bigger range it can illuminate, but the brightness would be weaker. We consider the diffuse color and the specular color of light are the same which is realistic for the most, which is defined by the. Usually we set the color of light to be white. In fact, the spot light also has the property called "attenuation quotient", but we set it as the parameter of the lighting shader to adjust the lighting effect more freely. Another kind of the light source is direction light like the sunshine. usually this means the light source is very very far from all the object, so the directions from any object to source are the same, that's why one of the property of direction light that lacks a position and only relies on direction for its effect.

Simple lighting of paper

First, we can implement the simplest lighting only with diffuse color of the flat surface, like a piece of paper, the surface of desk, etc. We just need to add sentences in the pixel shader like this:
DiffuseMaterialCl diffMaterial = new DiffuseMaterialCl();
SplotLightCl light = new SpotLightCl() {
  Position = new Point3DBl(thumbB.CenterPosition - UseImage.LeftTop, 170),
  Direction = new Point3DBl(1, 0, -0.8).Normalize,
  InnerConeAngle = 5.ToDegrees(), OuterConeAngle = 15.ToDegrees(),
Point3DBl eyePosition = new Point3DBl(eyeThumb.CenterPosition - UseImage.LeftTop, 100);
MyCanvas.Background = Colors.CornflowerBlue;
MyCanvas.Effect.Custom = (input, uv) => diffMaterial.Apply(light)
  [new Point3DBl(uv * MyCanvas.Size, 0), new Point3DBl(0, 0, 1), eyePosition][input, uv];


All the shaders to calculate lighting is in the class LightingTechniques, including this one. You can find these codes in light.cs, the function LightTest_Paper() in the class LightTest.
Here CornflowerBlue means the color of the paper or anything you think it is. LightSource0 is the lightsource to brighten the world. We use the lefttop position and the size of the current object you’re drawing in the shader to do some transformation. Because usually many objects share one light source, we should uniform their coordinate systems and also the light source’s. Finally the point3DBl(X, Y, Z) gives the setting of attenuation Quotient, which is described as a quadratic equation like "1.0/(X * d^2 Y * d Z), where d is the distance between the lightSource and the point". The numbers are bigger, the attenuation goes bigger with the distance, so the darker the object is. Usually the number X,Y,Z are between 0 and 1, but you can adjust them as you wish to get a good vision effect.

Here, with this simplest case, you can see how two kinds of light source effect the different results:
On the left is a spot light with the color white, on the right is a direction light with the color Ivory, and the color of paper itself is CornflowerBlue. Because the normal of the paper is only straight up, so the color is the same. Relatively, different attenuation and different direcion from point to light source make the lighting effct has a obvious change on the paper.

The diffuse color of object is set similar to the paper, just add more inrfomation like normal, height and so on.

Specular color
Specular color comes from the reflection of the light on the smooth surface like mirror, glass, some kind of metal, etc. Or you will more familiar with the word “highlight”. In fact little object only has the specular color, but we still implement this interface to simplify some calculation in UI but with effect as good. For example, we made the 2.5D bubble wrap on some image just with specular color:
bubblewrap.jpg bubblewrap-bump.jpg

We use these codes to finish it:
newCanvas.CustomEffect = (input, uv) => {
  return LightingTechniques.SpecularColor(uv, normalMap, heightMap, 20.0, LightSource0, 
    eyePos, newCanvas.LeftTop, newCanvas.Size, 10, 1.0) + baseMap[uv];
Here, the normalMap defines the normal of every pixel point, in the lase case, the normal of paper is thought to be (0, 0, 1), a default value. In the 2D window, all the object have the same height:0, but with Heightmap, you can define the height of pixel in a fake 3D space. As the height saved in HeightMap must be between 0 and 1(from black to white), use the next parameter to scale the height as you want, here we enlarge the height to 20 times. You can see the normalMap and HeightMap above. These two maps help to calculate the lighting more realistic. The next parameter , a double value 20, is the reflective index,usually from 1 to 2000. The higher this number is, the surface looks more smoother, so that the highlight spot smaller and brighter. The last one is often between 0 ans 1, is called specularity factor which can control the entire strength of the specular color. And you’ll find that the specular color just relative to the light source’s color, so we add baseMapuv to adjust the whole effect.

Both diffuse and Specular color
Most things in real world have both diffuse and specular color, so we provide the function to get the both, just like this:
newCanvas.CustomEffect = (input, uv) => {
  return LightingTechniques.DiffuseSpecularColor(uv, baseMap, normalMap, LightSource0, eyePos, newCanvas.LeftTop, 
              newCanvas.Size, new Point3DBl(4e-6, 2e-3, 0.5), 2, 0.8);
It’s just the combination of the above two functions. Here we omit heightmap and heightScale with the overloaded function. We can also use some color to instead of the image baseMap. Below is the effect of this funciton of a brick wall, compare with the ordinary texture on the right.

Simulate the glass
The glass only has specular color because of its smooth surface. And it also generates refraction as its transparency. So we add a background behind our glass to show these effects.
Here is the code of pixel shader:
newCanvas.CustomEffect = (input, uv) => {
  return LightingTechniques.GlassColor(uv, Colors.LightBlue, backgroundMap, normalMap, LightSource0, eyePos, 
     newCanvas.LeftTop, newCanvas.Size, 1.0, 0.9, 1.5, 2.5,  newBackgound.LeftTop, newBackgound.Size, slider.Value);
The second parameter defines the color of glass itself. The next one describes the background image behind the glass. Then a series of similar parameters we’ve ever seen. After the reflective index (1.0) and the specularity factor(0.9), there are some new things: 1.5 is the relative refractive index (RI). “Relative” means this one equals to RI of refracting medium / RI of incident medium, here 1.5 is a value we often used to describe glass’s relative RI, means: RI of glass(1.5~1.9,generally) / RI of air(1.0). The nest one is the thickness of glass, usually between 1 and 100, it determine the level of refraction. The thicker the glass is, the effect of refraction is more obvious. The next two parameter give us the location of background image. The last one defines the transparency of glass, usually from 0.0 to 1.0, the bigger transparency means the more light can across the glass and brighten the background. If the transparency is 0, you can only see the color of glass. Here are pictures with different transparency(0.2 → 0.6 → 1.0):

Simulate the diffraction of CD surface
For surfaces with small-scale detail such as a CD, the small-scale surface detail causes the reflected waves to interfere with one another. This phenomenon is known as diffraction. Diffraction causes the reflected light from these surfaces to exhibit many colorful patterns, as you can see in the subtle reflections from a CD. We simulate it using the method in the book GPU Gems.

In the calculation of diffraction, the tangent vectors are needed to supply the local direction of the narrow bands on the surface. For a CD, they are in the direction of the tracks, so we can get them in the pixel shader. If you want more complicated tangent vectors, more calculation or a texture should be helpful.
Here is our code:
newCanvas.CustomEffect = (input, uv) => {
  return LightingTechniques.DiffractionCD(uv, input, rainbow, LightSource0, eyePos, 
    newCanvas.LeftTop, newCanvas.Size);
If you just want to render a CD only with diffraction, just call the function in shader like this simple way. We just meet two strange parameters: the second one ”input” supplies the basic image of a piece of CD, and the “rainbow” is a 1D texture in which we can map the color corresponding to a given wavelength, we use a simple approximation of a rainbow map that range from violet to red and include most colors in the rainbow. And we assume that the normal of surface is (0, 0.5, 0.866) with a little lean to show the diffraction better.

Last edited Oct 23, 2009 at 12:37 AM by mcdirmid, version 11


No comments yet.