**Intro**

Here’s a CS4 Flat Shaded Tie Fighter. I built the tie fighter in Blender, and used drawTriangles to render the model in CS4. The shaders come directly form Ralph Hauwert’s fast light maps … thanks Ralph. Here I only treat flat shading, but in the book (and its website). I treat the rest of them: cell, gouraud, phong, and envmap.

Since I’ve treated bringing Blender and 3DSMax models into CS4 ad nauseum, I won’t belabor the point. This program culls, has its own light class with brightness (here it alternates in brightness), depth sorts, and displays concavity with no problems.

The perlin noise clouds came from flepstudio … thanks flepstudio!

CS4 Flat Shaded Tiefighter using drawTriangles

Source

Demo

YouTube

**Discussion**

Here’s a brief explanation of flat shading in CS4.

The light class is a point light with brightness (contained in the org/lively3d/lights/ folder of your download). It gives you the position of your light source, brightness, light color, ambient color, and specular level.

**Here’s the Hack**

The lightColor variable is the color of your light source. The ambientColor variable is not true ambient light. It’s the first and second parameter in a gradient fill (the third one is your light color), and it governs the color that your object will take on. The specularLevel variable adjusts the number of shades between your middle ambient color and light color. And gives the appearance of making your surface shiny at low numbers-hey, it’s a great hack!

Here’s how the gradient fill works:

The beginGradientFill method has several parameters but only the ones used here are listed below: type, color, alphas, ratios, and matrix.

beginGradientFill(type, colors, alphas, ratios, matrix)

They do the following:

- type-specifies which gradient type to use: linear or radial
- colors-an array of color values used in the gradient
- alphas-an array of alpha values corresponding to the colors
- ratios-defines the percentage of the width where the color is sampled at 100%.
- matrix- a transformation matrix which controls scale, skewing, and location of your gradient appearance.

Here’s how the light map is implemented:

A bitmapdata object is created named tempmap which is just a simple strip 255 pixels long and 1 pixel wide, the gradient is calculated using the ambient and light colors, and the gradient is drawn into the tempmap and returned.

The process described above is demonstrated in the code below, which comes from Ralph Hauwert’s LightMaps class and is used to create the light maps for flat, cell, phong, and gouraud.

var tempmap:BitmapData = new BitmapData(255,1,false,0);

var s:Sprite = new Sprite();

var m:Matrix = new Matrix();

m.createGradientBox(255,1,0,0,0);

s.graphics.beginGradientFill(GradientType.LINEAR, [ambientColor,ambientColor,lightColor],[1,1,1],[0,255-specularLevel,255],m);

s.graphics.drawRect(0,0,255,1);

s.graphics.endFill();

tempmap.draw(s);

return tempmap;

Now that you understand how a simple light map is created the steps to creating a flat shade are easy:

** Step 1**: Create your light map

_colors = LightMaps.getFlatMapArray(lightColor, ambientColor, specularLevel );

** Step 2:** Return a cosine (zd) from the dot product of your light vector with your triangle normal vector. This gives the cosine of the angle of your triangle face normal to your light source. If your light source is at 90 degrees to your object triangle (no light hitting it) then the cosine value (zd) is zero. If your triangle is directly facing the light source then your cosine is 1 (completely lit).

AVect[0]=new Vector3D(dispVec[facesVec[curFace][0]].x,dispVec[facesVec[curFace][0]].y,dispVec[facesVec[curFace][0]].z);

AVect[1]=new Vector3D(dispVec[facesVec[curFace][1]].x,dispVec[facesVec[curFace][1]].y,dispVec[facesVec[curFace][1]].z);

AVect[2]=new Vector3D(dispVec[facesVec[curFace][2]].x,dispVec[facesVec[curFace][2]].y,dispVec[facesVec[curFace][2]].z);

AVect[3]= AVect[0].subtract(AVect[1]);

AVect[4]= AVect[1].subtract(AVect[2]);

AVect[5]=AVect[4].crossProduct(AVect[3]);

AVect[6]=new Vector3D(light.x, light.y, light.z);

var mag1:Number=AVect[5].length;

var mag2:Number=AVect[6].length;

var zd:Number = AVect[6].dotProduct(AVect[5])/(mag1*mag2);

In CS4, you totally eliminate Papervision’s Numbers class since all the calculations provided by that class are now internal to CS4.

So for example a dot product of two matrices in CS4 is given by

var zd:Number = AVect[6].dotProduct(AVect[5])/(mag1*mag2);

**Step 3**: Calculate the index value from your zd by multiplying it by 255 (hex 0xff) and grab the respective color from your “_colors” array. Essentially as your triangle turns away from your light source the hex value is reduced: effectively darkening your pixels.

zAngle = zd*0xff; //0xff if hex for 255

currentColor = _colors[zAngle];

** Step 4**: Render your triangle and fill it with your calculated light map color.

spObjImage.graphics.beginFill(currentColor);

spObjImage.graphics.drawTriangles(vertices);

The code above uses drawTriangles exclusively, where PV3D draws individual lines. The big advantage here is that you can make the triangles blow up – can’t wait to show you that!!! And theoretically, it should be faster than PV3D.

Figure 4-4 The Four Steps to Flat Shading

This probably seems like a lot to absorb, but the good news is that the rest of the shaders follow pretty much of the same process (with the addition of a few matrix methods).

To see the complete code download the source above or click on the more button below:

** Read the rest of this entry »**