Crisp Rasterizations with Flash 10’s 3D

Preserve your designer's hard work

My last post was about guaranteeing beautiful vector graphics in Flash. Unfortunately, the project I’m working on that uses these graphics (which again I’ll talk about at length some other time) transforms them in 3D space. Unsurprisingly this leads to some complications.

Most people forget that Flash can do native 3D, and when they see it in use usually they think it’s “innovative”. Frankly it’s not; Flash has had a 3D API since late 2008, but there are reasons why most people don’t see much of it:

  • Most designers and developers aren’t taught much about 3D transformations, or even 3D aesthetics.
  • The tools Adobe’s released to design 3D Flash content are in their first lifecycle, and are only in one product (Flash CS4), which has a ton of other new features too, competing for user’s attention.
  • There are plenty of classic techniques for producing 3D media that does not require Flash’s 3D API
  • Perspective projection of objects means that a 3D object has to be redrawn each time it is moved in 2D space, unlike a 2D object

And the sneaky one which I’ll be talking about,

  • Flash’s beautiful vector graphics may become fuzzy or pixelated when you transform them in 3D.

Thus a skilled and determined designer-developer team who find themselves in the right scenario could end up producing 3D Flash content. But if they ignore the last issue, their output might have a lower visual quality than what they’d like. Let’s look at why that is.

Along with the 3D API, Flash Player 10 introduced some enhancements and additions to its 2D API, most notably the Graphics.drawTriangles() method. This function accepts a series of triangles to draw in 2D, along with an optional series of texture coordinates for mapping an image onto those triangles. Whatever low-level code underlies the drawTriangles() function, it is also responsible for drawing 3D objects in the display list; when you transform a 2D DisplayObject in 3D, its bounding box’s corners are transformed in space, projected onto the screen and passed to the triangle drawing system. Those points are joined into two 2D triangles drawn onscreen.

Next comes the texture. The original 2D object is drawn to a bitmap the size of its bounding box, and the texture coordinates given to the triangle drawing system are the four corners of the bitmap. This rasterization– drawing your graphics to a bitmap the size of its local bounds– is where your graphic quality is capped; like any other bitmap, your graphics’ resolution is limited by the number of pixels in the texture, and if that texture is drawn to triangles with greater area, the resulting image will be blurry or pixelated.

If you’re only transforming one object in 3d, there is a simple solution, which I call the CrisperDrawer. It’s a subclass of Sprite with “child” and “resolution” properties. It only takes one child display object; when you assign it a resolution, it scales the child up by that amount in the X and Y dimensions, and scales itself down the same amount as well. You then transform the CripserDrawer in 3D.

The reason why this works is, by scaling up the 2D object, it is drawn to a larger bitmap than it normally would be. That bitmap is then used to texture the same projected triangles as before, because they will be derived from the bounding box of the CrisperDrawer, which is the same as the original bounding box. Usually you won’t need a resolution much higher than 3, but if your resolution is too high Flash won’t be able to represent the 2D graphic as a bitmap. You can also use the CrisperDrawer to lower the resolution of your graphics, if that’s your cuppa joe.

There are two limitations to the CrisperDrawer system. First, it only works on one 2D graphic; the DisplayObject you passed into it. That means for each 2D graphic with resolution issues in your application, you will need to work with a separate CrisperDrawer. You may write some handy recursive functions for making CrisperDrawers from existing 3D display lists, but that’s something you would typically wish to program on a per-project basis.

The other limitation is that bitmap filters you use in your 2D graphics will need to be tweaked when you use a CrisperDrawer. Adjusting the scaleX and scaleY of a 2D object that has filters applied to it will not affect the filter’s properties; for instance, a circle with a 10-pixel horizontal blur will look less blurry when you double its size. You will want to change the filter’s horizontal blur to 20 pixels, in that case. But as long as your 2D graphic stays in the CrisperDrawer and you don’t adjust its resolution, you’ll only need to modify your filters once.

Here’s a link to that CrisperDrawer class. Look it over, and if you use it, fantastic.

You can leave a response, or trackback from your own site.

2 Responses to “Crisp Rasterizations with Flash 10’s 3D”

  1. Brian Asento Says:

    I’ve been trying very diligently to incorporate your crisperdrawer class, it sounds like the perfect solution for my blurry 3D text problem. I am doing something wrong with the implementation however, and it’s over my head. Maybe you could explain things line by line, or take a look at my file? I know the script is acting because if I specify the wrong depth the text object I apply it to isn’t drawn. The issue I’m having though is the blurriness doesn’t go away.

    Any help would be greatly appreciated. I have looked over other fixes but scaling things up and down seem to be an indirect solution to the problem!

    October 25th, 2013 at 7:47 PM

  2. Jeremy Says:

    It’s been a while since I’ve worked with this stuff, but if you email me a snippet of your code, I could look through it and try to isolate the problem, as well as provide an example where it works.

    If CrisperDrawer works properly with non-text graphics, then I would immediately suspect Flash’s TextField, which uses system-provided text rendering and sometimes misbehaves in the display list. I believe that my 2010 project that used CrisperDrawer worked exclusively with text composed of flash.text.engine.TextLine properties for the simple reason that old TextFields weren’t cutting it for me.

    I’ll keep an eye on my inbox. Good luck!

    October 26th, 2013 at 2:01 PM

Leave a Reply