In a previous post, I published a method to distort an image by its corners with proper perspective distortion, using the new drawTriangle() methods from Flash 10. That was used for a website I had to develop about an year ago at Firstborn, where we had (mostly) static content projected to 3d screens.
It just happened that, recently, I had to re-apply the technique to another website I was developing. This time around, however, the distorted image had to be interactive so using drawTriangle() wouldn’t work.
Luckily, wonder.fl user wh0 had already derived a method, quite different from my implementation, that instead took the corner coordinates and created a proper Matrix3D instance. This 3D transformation matrix could then be applied to an Interactive Object, that could then work as if it had been transformed by using the standard transformation properties (rotateX, rotateY, etc).
I had to adapt the feature a bit to fit my needs, so I’ve created a wrapper for that technique that allows you to create a distorted sprite – called a PerspectiveSprite – and then add children to it directly. It works like so:
// Creates a container of assumed width 200 and assumed height 100 container = new PerspectiveSprite(200, 100); addChild(container); // Moves the top right corner a bit container.topRight = new Point(250, 10); // Adds an object to the container myBox = new Box(200, 100); container.addChild(myBox);
The container needs assumed width and assumed height parameters just so it’ll calculate the graphics correctly. In theory, you can use anything in there, but then you will need to assume the instance created is a rectangle of that same width and height when adding content. And, of course, the higher the assumed width and height, the higher the resolution when transforming the plane (since Flash pre-renders the content before projecting it).
You can find PerspectiveSprite here on my account on GitHub.
Here’s an example of that in action, using our Meet Firstborn video in a loop as the distorted plane and some simple elements as examples of seamless user interaction (since it’s just that, a standard DisplayObject container):
Works well and is a better, more dynamic solution than redrawing a bitmap. Props to wh0 again for first finding the equations and coming up with the calculation for AS3’s Matrix3D.
Update (June 13th, 2011): the above, as it turns out, isn’t as precise as I thought. On extreme perspective transformations, the transformed Sprite can be a bit skewed vertically or horizontally. The problem seems to be at the projectionCenter of the perspectiveProjection of the Sprite. In such cases, using the (very manual but perfectly accurate) drawPlane() is a better option, at least until a correct matrix3d calculation is found.
Update II (July 6th, 2011): apparently distortions will only happen in some very specific cases. I think it’s a combination of being loaded inside another SWF, and stage alignments different than top left (any of these, isolated, won’t be a problem). I can’t even replicate it consistently. So my recommendation is instead to use the above code anywhere necessary, but resort to drawPlane() in case it’s not precise enough.