Creating 3D Fills

As you might imagine, a large part of the work for fills has already been done. Youve already created the points for a shape and connected them from one end to the other with a line. All you really need to do is add a beginFill and endFill to the drawing code. The code in the ch16_06.fla file does just that; see Figure 16-7 for the results. Heres the relevant section of code with the changes in bold:

 clear(); lineStyle(1, 0, 100);  beginFill(0xffcccc, 100);  moveTo(points[0].xPos, points[0].yPos); for (var i:Number=1;i<numPoints;i++) {       var point:MovieClip = points[i];       lineTo(point.xPos, point.yPos); } lineTo(points[0].xPos, points[0].yPos);  endFill();  
image from book
Figure 16-7: First 3D fills

This comes right at the end of the onEnterFrame function.

At this point, its a good idea to look at how traditional 3D programs model shapes and solids. In the previous examples, both the square and the letter E are poly gons . A polygon is simply a closed shape made of at least three line segments. Thus, a triangle is the simplest polygon. Youll find that in most, if not all, 3D modeling and rendering programseven those that use patches, meshes, nurbs, and complex polygonsall 3D forms are finally reduced to a set of triangles just prior to being rendered.

Using triangles

There are a number of advantages to using trianglesprobably more than I know, but Ill cover a few here. First, with a triangle, you can be sure that all the points of the polygon are always on the same plane, since a triangle defines a plane. If you are still not sure why this is important, take the letter E example and randomly change around some of the z values of its points. While you may get some interesting results, they can also quickly become unexpected and unpredictable.

Second, using triangles, it is sometimes easier to draw complex shapes. Consider Figure 16-8, for example.

image from book
Figure 16-8: More complex 3D shape

This type of shape would be kind of tough to create with a single polygon. Youd have to double back on yourself at least once. Youd also get into the situation where every polygon you create would have a different number of points and require special handling. On the other hand, with triangles, you can model the A as shown in Figure 16-9.

image from book
Figure 16-9: The same shape as in Figure 16-8, rendered with triangles

You can then set up a function that takes three points and renders a single triangle. You just need a list of points and then a list of triangles. One loop goes through the list of points, positions them, and applies perspective. Another loop goes through the triangle list and renders each one.

This isnt to say that you have to go with a triangle-only approach. You could make a function that dynamically renders a polygon of any number of sides. But to keep things simple and flexible here, youll go with the triangles. Lets try it out with the letter A example. First, you need to define all of your points and triangles. As shown in Figure 16-10, Ive laid out the shape, and numbered all of its points and each of its triangles.

image from book
Figure 16-10: The points and polygons that make up this shape

When you graph out all the points, you get the following values:

 points[0] =  {x: -50, y:-250, z:100}; points[1] =  {x:  50, y:-250, z:100}; points[2] =  {x: 200, y: 250, z:100}; points[3] =  {x: 100, y: 250, z:100}; points[4] =  {x:  50, y: 100, z:100}; points[5] =  {x: -50, y: 100, z:100}; points[6] =  {x:-100, y: 250, z:100}; points[7] =  {x:-200, y: 250, z:100}; points[8] =  {x:   0, y:-150, z:100}; points[9] =  {x:  50, y:   0, z:100}; points[10] = {x: -50, y:   0, z:100}; 

Next , you need to define the triangles. Each triangle is simply a list of three points; lets call them a , b , and c . You can make an object to hold each one and another array to hold the whole list. So, up top, you create the array:

 var triangles:Array = new Array(); 

Then, in the init function, after defining all the points, you define the triangles:

 triangles[0] =  {a:0, b:1,  c:8}; triangles[1] =  {a:1, b:9,  c:8}; triangles[2] =  {a:1, b:2,  c:9}; triangles[3] =  {a:2, b:4,  c:9}; triangles[4] =  {a:2, b:3,  c:4}; triangles[5] =  {a:4, b:5,  c:9}; triangles[6] =  {a:9, b:5,  c:10}; triangles[7] =  {a:5, b:6,  c:7}; triangles[8] =  {a:5, b:7,  c:10}; triangles[9] =  {a:0, b:10, c:7}; triangles[10] = {a:0, b:8,  c:10}; 

One thing youll notice is that I ordered the points of each triangle to go in a clockwise direction. That isnt important at this stage of the game, but it will become very important in the next chapter, so its a good habit to get into.

By the way, if youre thinking that plotting and entering all these points and tri angles by hand is tedious , thats because it is tedious. And its going to get worse when you get into modeling solid forms. Thats why most 3D programs have visual modeling front ends to them, which give you all kinds of tools to create forms and extract all the points and polygons for you. Creating such a modeling front end might be possible in Flash, but its well beyond the scope of this book!

Now, your rendering loop will look like this (dont worry, Im going to give you the whole thing to look at in a bit):

 clear(); var numTriangles:Number = triangles.length; for(var i:Number =0;i<numTriangles;i++) {       renderTriangle(triangles[i]); } 

The last thing you need is a renderTriangle function that will draw a single triangle based on the three points given to it. That looks like this:

 function renderTriangle(tri:Object):Void {       lineStyle(1, 0, 100);       beginFill(0xffcccc, 100);       moveTo(points[tri.a].xPos, points[tri.a].yPos);       lineTo(points[tri.b].xPos, points[tri.b].yPos);       lineTo(points[tri.c].xPos, points[tri.c].yPos);       lineTo(points[tri.a].xPos, points[tri.a].yPos);       endFill(); } 

This code may look somewhat confusing, so let me explain it. The object passed in, tri , contains three values, a , b , and c . These are the points used to make up that particular triangle. But what are these numbers , actually? Theyre indexes to the points array. Lets take triangle 0. Its defined like so:

 triangles[0] =  {a:0, b:1, c:8}; 

So, a , b , and c will equal 0, 1, and 8, respectively. Thus, the drawing code gets evaluated as such:

 moveTo(points[0].xPos, points[0].yPos); lineTo(points[1].xPos, points[1].yPos); lineTo(points[8].xPos, points[8].yPos); lineTo(points[0].xPos, points[0].yPos); 

What youre doing is moving to point 0, and then drawing a line from there to point 1, to point 8, and back to point 0 again. That completes the triangle. This setup allows you to draw much more complex shapes, such as the A with a hole in it. When you run the code, youll see something like Figure 16-11.

image from book
Figure 16-11: The A shape, rendered in 3D

Now at this point, these lines are too much, so you probably want to get rid of them by removing the lineStyle statement, leaving you with just the fills, as shown in Figure 16-12.

image from book
Figure 16-12: The A shape, with lines removed

And, just to keep you up-to-date on things, heres the code found in ch16_07.fla :

 var points:Array = new Array(); var triangles:Array = new Array(); var fl:Number = 250; var vpX:Number = Stage.width / 2; var vpY:Number = Stage.height / 2; var zOffset:Number = 200; init(); function init() {       points[0] = {x:-50, y:-250, z:100};       points[1] = {x:50, y:-250, z:100};       points[2] = {x:200, y:250, z:100};       points[3] = {x:100, y:250, z:100};       points[4] = {x:50, y:100, z:100};       points[5] = {x:-50, y:100, z:100};       points[6] = {x:-100, y:250, z:100};       points[7] = {x:-200, y:250, z:100};       points[8] = {x:0, y:-150, z:100};       points[9] = {x:50, y:0, z:100};       points[10] = {x:-50, y:0, z:100};       triangles[0] =  {a:0, b:1,  c:8};       triangles[1] =  {a:1, b:9,  c:8};       triangles[2] =  {a:1, b:2,  c:9};       triangles[3] =  {a:2, b:4,  c:9};       triangles[4] =  {a:2, b:3,  c:4};       triangles[5] =  {a:4, b:5,  c:9};       triangles[6] =  {a:9, b:5,  c:10};       triangles[7] =  {a:5, b:6,  c:7};       triangles[8] =  {a:5, b:7,  c:10};       triangles[9] =  {a:0, b:10, c:7};       triangles[10] = {a:0, b:8,  c:10}; } function onEnterFrame():Void {       var angleY:Number = (_xmouse - vpX) * .001;       var cosY:Number = Math.cos(angleY);       var sinY:Number = Math.sin(angleY);       var angleX:Number = (_ymouse - vpY) * .001;       var cosX:Number = Math.cos(angleX);       var sinX:Number = Math.sin(angleX);       var numPoints:Number = points.length;       for (var i:Number=0;i<numPoints;i++) {             var point:MovieClip = points[i];             var x1:Number = point.x * cosY - point.z * sinY;             var z1:Number = point.z * cosY + point.x * sinY;             var y1:Number = point.y * cosX - z1 * sinX;             var z2:Number = z1 * cosX + point.y * sinX;             point.x = x1;             point.y = y1;             point.z = z2;             var scale:Number = fl / (fl + point.z + zOffset);             point.xPos = vpX + point.x * scale;             point.yPos = vpY + point.y * scale;       }       clear();       var numTriangles:Number = triangles.length;       for(var i:Number =0;i<numTriangles;i++)       {             renderTriangle(triangles[i]);       } } function renderTriangle(tri:Object):Void {       beginFill(0xffcccc, 100);       moveTo(points[tri.a].xPos, points[tri.a].yPos);       lineTo(points[tri.b].xPos, points[tri.b].yPos);       lineTo(points[tri.c].xPos, points[tri.c].yPos);       lineTo(points[tri.a].xPos, points[tri.a].yPos);       endFill(); } 

Defining the triangles colors

Now that you have everything functioning pretty well, lets go back and see if you can improve the code a bit. One thing that bugged me was the fact that the color for the fills was hard-coded in the renderTriangle function. That means that every triangle has to be the same color, unless you start making multiple functions, such as renderRedTriangle , renderBlueTriangle , and so forth, which would just be silly.

A better solution might be to pass in the color you want as a parameter, which would look like this:

 function renderTriangle(tri:Object  , col:Number  ):Void {       beginFill(  col  , 100);       moveTo(points[tri.a].xPos, points[tri.a].yPos);       lineTo(points[tri.b].xPos, points[tri.b].yPos);       lineTo(points[tri.c].xPos, points[tri.c].yPos);       lineTo(points[tri.a].xPos, points[tri.a].yPos);       endFill(); } 

Then you could pass in a color when you call the function. But thats really just moving the hard-coded value from one function to another one. Since that call to renderTriangle is in a for loop, all the triangles are still going to get the same color.

What you really want to do is have a color defined for each triangle. Well, why not just put that in the triangle object, along with the list of points? Then you can come up with something like this in the list of triangles:

 triangles[0] =  {a:0, b:1,  c:8,  col:0x6666cc}; triangles[1] =  {a:1, b:9,  c:8,  col:0x66cc66}; triangles[2] =  {a:1, b:2,  c:9,  col:0x66cccc}; triangles[3] =  {a:2, b:4,  c:9,  col:0xcc6666}; triangles[4] =  {a:2, b:3,  c:4,  col:0xcc66cc}; triangles[5] =  {a:4, b:5,  c:9,  col:0xcccc66}; triangles[6] =  {a:9, b:5,  c:10, col:0xcccccc}; triangles[7] =  {a:5, b:6,  c:7,  col:0x666666}; triangles[8] =  {a:5, b:7,  c:10, col:0x6666cc}; triangles[9] =  {a:0, b:10, c:7,  col:0x66cc66}; triangles[10] = {a:0, b:8,  c:10, col:0x66cccc}; 

Now each triangle has its own color. Since the renderTriangle function has a reference to each triangle object, it can easily use this color value in its beginFill call:

 function renderTriangle(tri:Object):Void {       beginFill(  tri.col  , 100);       moveTo(points[tri.a].xPos, points[tri.a].yPos);       lineTo(points[tri.b].xPos, points[tri.b].yPos);       lineTo(points[tri.c].xPos, points[tri.c].yPos);       lineTo(points[tri.a].xPos, points[tri.a].yPos);       endFill(); } 

This is much cleaner and more portable, and it even opens up the idea of storing the point and triangle data in an external text or XML file, which could be loaded, parsed, and rendered at run time.

Figure 16-13 shows the result of ch16_08.fla . Not that you would necessarily want to color the triangles for a letter A like that, but it shows that you now have complete control over the color of each one, which will be useful when you start building more-complex models.

image from book
Figure 16-13: The A shape, with individually colored polygons


Foundation ActionScript. Animation. Making Things Move
Foundation Actionscript 3.0 Animation: Making Things Move!
ISBN: 1590597915
EAN: 2147483647
Year: 2005
Pages: 137
Authors: Keith Peters

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net