I’ve done tons of 3D in ActionScript over the years. I wrote 3 chapters about 3D in Making Things Move. I could code that kind of simple 3D in my sleep. When I say 3D, I’m not talking about the insane light map, bump map, texture map insanity that the likes of Andy Zupko and Ralph Hauwert get up to, but just scaling objects in a 3D space to give the illusion of depth.
So naturally, when Flash 10 came out with built in 3D, I was pretty excited. It offers just about the same level of stuff that I always do in code, but built in. Now instead of setting a focal length and making some new class to keep track of z, and calculating a scale value and a vanishing point, all that is done for me. Great!
But… maybe it’s not so great. I’ve found that a lot of stuff that I do with Flash 10 3D just doesn’t look as good as the stuff that I code by hand. The reason for this has to do with bitmaps. It seems that when you apply any 3D transformation to a display object, it turns it into a bitmap – same as applying filters. Unfortunately, this results in some pretty crappy results.
As an example, let’s make a bunch of circles and randomly place them in 3D space. We’ll use the same coordinates but do it once with Flash 10 3D, and once with hand-coded 3D. An interesting thing to note is that you can access perspectiveProjection.focalLength from the main container, and use that in your own 3D code with the exact formulas I gave in Making Things Move and get the exact same 3D projection. This really is a science!. Here’s the code I’m using:
[as]var h:Sprite = new Sprite();
h.x = 400;
h.y = 200;
var h1:Sprite = new Sprite();
h1.x = 400;
h1.y = 600;
root.transform.perspectiveProjection.projectionCenter = new Point(400, 200);
var focalLength:Number = root.transform.perspectiveProjection.focalLength
for(var i:Number = 0; i < 100; i++)
var s:Sprite = new Sprite();
s.x = Math.random() * 2000 - 1000;
s.y = Math.random() * 400 - 200;
s.z = Math.random() * 8000
s.graphics.drawCircle(0, 0, 50);
var s1:Sprite = new Sprite();
var scale:Number = focalLength / (focalLength + s.z);
s1.x = s.x * scale;
s1.y = s.y * scale;
s1.scaleX = s1.scaleY = scale;
s1.graphics.drawCircle(0, 0, 50);
I'm adding two containers: h and h1. Setting the vanishing point of the first to the center of the h container. Then drawing 100 random circles in each one, at the same location for each. This gives you the following picture:
Note that the two pictures geometrically, are exact duplicates. But the top one, done with Flash 10 3D had some really HORRIBLE artifacting. This is due to the fact that the circles are no longer represented as vectors, but as poorly scaled bitmaps. We can zoom in on them a bit:
Or even a bit more:
to see the problem. Note that the bitmap is regenerated each time you scale. The small circles in the full size image don’t have nearly that resolution. If you control-scroll (on a Mac), or otherwise zoom your screen without using the Flash player’s zoom in feature, you’ll see it looks even crappier up close.
Contrast that with the handcoded version, which never stops being vector. Zoomed in all the way:
You can’t actually tell how zoomed in you are. It’s just vector circles.
Of course, the vector version looks a bit harsh as the far away circles are just as dark and crisp as the close up ones. But it’s easy enough to apply a bit of aerial perspective. The easiest way to do it is use the calculated scale value to adjust alpha – either the alpha of the sprite itself, or the alpha of the line drawing it.
Adding this one line between lines 29 and 30:
s1.alpha = scale;
gives us this:
That’s just a simple example. The best part about this handcoded 3D is that you can adjust the aerial perspective however you want. You can apply it directly as above, or just use that scale value in a more complex equation to change the dropoff. Or you can use it to apply a blur filter. Or change the color or width of the line you are drawing. In other words, you have complete control.
Another weird thing related to this Flash 10 3D rendering happened with these images at my other site, Art From Code:
These were all done with Flash 10 3D. All are done with an unbroken series of lines running left to right, and scaled back as a number of layers, using various sine wave expressions to affect the shape of the lines. But notice the holes. The tops of some of the curves got cut off. I left them that way, as it was an interesting effect, but it is really just an artifact, horrible enough to even be called a bug.
So, I’m not saying that Flash 10 3D is useless. It’s fast and easy, and the examples here involve mainly line drawing, where the effect is massively amplified. If you are drawing straight fills or bitmaps, the effects may be barely noticeable. And there may be some way of compensating for this that I am not aware of. I’ve messed with cacheAsBitmap and LineScaleMode, and some other stuff, none of which seems to make any difference.
So all I’m saying is, don’t throw out your old 3D code yet. Evaluate both methods and see which works best. I think it’s great to spike ideas using Flash 10 3D and then make it look better by converting it to handcoded 3D. And, maybe it’s something for Adobe to look at in Flash 11.