“Easily create two sided 3D DisplayObjects and flip card effects using Flash Player 10 and the new 3D API …”

PaperSprite Demo

I’ve made a couple of small improvements to the PaperSprite class:

  1. The visible face of the plane is updated automatically only when required. This saves on processing load and also means you can just set up the PaperSprite and not have to worry about anything else, just tween the crap out of all its properties and it won’t mind one bit. (Thanks to Jesse for the pointers re. using stage.invalidate for this process)
  2. The back face is now automatically flipped horizontally, so text and graphics are no longer mirrored and will display correctly
  3. I’ve changed the logic which sets the dynamic registration point for the pivot. This should now correctly line up the front and back faces of the 3D plane, regardless of where their individual registration points are.

Also, some people have asked how to use it, so here is a really quick example to get you up and running with PaperSprite if you are not familiar with using classes and are using the Flash IDE to compile your movie:

  1. First, download the PaperSprite class and put the soulwire folder in the same directory as your FLA or source code.
  2. Then paste this code into the main timeline of your FLA:

// Import the PaperSprite class

import soulwire.display.PaperSprite;

/*
Create a new PaperSprite:

If your front and back faces already exist, you can pass them straight
into the constructor, like so:

myPaperSprite = new PaperSprite( myFrontMc, myBackMc );
*/

var myPaperSprite:PaperSprite = new PaperSprite();

/*
Optionally specify a pivot point, in this example the centre is used
(this is also the default so there is no need to set this normally).

To pivot around the top left use:
myPaperSprite.pivot = new Point(0,0);

or for bottom right:
myPaperSprite.pivot = new Point(1,1);

and so on...
*/

myPaperSprite.pivot = new Point(0.5,0.5);

// Centre it on the stage

myPaperSprite.x = stage.stageWidth / 2;
myPaperSprite.y = stage.stageHeight / 2;

/*
Set the front and back faces:

These can be any type of DisplayObject, for example, to use a MovieClip
from your library use:

myPaperSprite.front = new MyLibraryClip();
*/

myPaperSprite.front = createSprite(0x66FF00);
myPaperSprite.back = createSprite(0xFF3399);

// Add the PaperSprite to the display list

addChild ( myPaperSprite );

// This method just creates coloured boxes for the demo

function createSprite (colour:uint):Sprite
{
	var mySprite:Sprite = new Sprite();
	mySprite.graphics.beginFill ( colour );
	mySprite.graphics.drawRect (0,0,100,100);
	mySprite.graphics.endFill ();
	return mySprite;
}

// Listen for the enterFrame event

addEventListener ( Event.ENTER_FRAME, spin );

/*
Move and rotate your PaperSprite in any way you want - it will
update it's visible face automatically!
*/

function spin ( event:Event ):void
{
	var mX:Number = ((mouseX / stage.stageWidth) - 0.5) * 360;
	var mY:Number = ((mouseY / stage.stageHeight) - 0.5) * 360;

	myPaperSprite.rotationY += (mX - myPaperSprite.rotationY) / 40;
	myPaperSprite.rotationX += (mY - myPaperSprite.rotationX) / 40;
}

Publish the movie and you’re all done!

Background

Flash Player 10’s new 3D capabilities are a much welcomed and exiting addition, and although their implementation at first seemed a little obtuse after using libraries such as Papervision3D, Adobe’s implementation is beginning to make a lot more sense to me. Rather than being handed a complete 3D library, developer’s have been given the necessary building blocks to use 3D, or 2.5D with less ‘hacks’ and arguably better performance where it matters.

Time will tell, but I personally think this will be a positive development for existing frameworks like Papervision and Sandy, because whilst Flash can now natively handle certain tasks like triangle drawing, 3D matrices etc – implementing cameras and shaders, loading and building meshes and so on is something which developers will still require. If this can plug neatly into Flash Player’s capabilities and possibly yield increased performance then all the better.

In more basic situations though, the ability to rotate a DisplayObject around its X, Y and Z axis, as well as finally having a Z property, is useful for adding basic 3D effects, even if your project doesn’t require anything more sophisticated than that.

But this is where some gaps begin to arise. Z sorting, for example, will be required, and Ralph Hauwert (a member of the Papervision3D team) has already written a useful script for this.

Two Sided DisplayObjects

Another common use for Flash Player 10’s 3D capabilities is to create double sided sprites or planes, than can be rotated to reveal alternate content on either side. Again, I would have expected this to be a new property of DisplayObjectContainer, so that front and back could be passed to it as DisplayObjects. This isn’t the case though, so it requires some minimal work around.

Lee Brimelow demonstrated one approach to this, which was to monitor the rotation of a DisplayObject, and swap the visible faces accordingly (Jesse Freeman also used this technique). This works great in many cases, however it doesn’t give the desired results when the parent DisplayObject is off centre and therefore subject to the perspective of the 3D environment. It also means that if you are rotating the DisplayObject around multiple axis then the calculations required get slightly more complex.

The Solution

As ever, the wise and prolific Senocular came to the rescue. He described a technique whereby 3 points are placed on the surface of the DisplayObject, and by determining the winding direction of these points when translated from 3D to 2D space; one is able to determine which way the DisplayObject is facing. Because this is relative to the perspective used to produce this transformation, the result is true to the point of view of the user.

Senocular published his helper class which will return a Boolean value indicating whether a given DisplayObject is front facing or not, and so I wish to stress that all credit is his for his solution and wonderfully clear explanation of the process.

I did feel that it might be beneficial though to wrap this up, along with other functionality, into a class which solved the double sided DisplayObject issue, and so I introduce the PaperSprite class (I chose to call it PaperSprite so that it isn’t confused with Sprite3D if you use another 3D library).

How to use PaperSprite

Creating a two sided Plane using PaperSprite is simple:

import soulwire.display.PaperSprite;

var mySprite:PaperSprite = new PaperSprite();

// Any type of DisplayObject can be used for each face
mySprite.front = new Sprite();
mySprite.back = new Bitmap( myImage );

So you can use any DisplayObject for the front and reverse sides; MovieClips, Sprites, Bitmaps, Shapes, Loaders etc. These can also be set via the constructor

Another property of PaperSprite is whether is updates it’s display automatically. If true, once the PaperSprite is added to the stage it will update its visible face autonomously, however if you have a more general render loop where you’re controlling your 3D scene from, you can set this to false and then call the update method when calculating the visible face is required:

Thanks to Jesse Freeman for suggesting a method to limit unnecessary calls to the update method. By overriding the setters for the position and rotation properties and using stage.invalidate(), then listening for the render event (Event.RENDER), the calculations needed to determine the visible face of the PaperSprite need only be made if one or more properties have been changed and if the PaperSprite needs to be rendered. Therefore there is no longer a need for autoUpdate, everything is handled internally by the PaperSprite class. Cheers Jesse! :)

…The other useful feature is the pivot property. By default, a PaperSprite will pivot (rotate around) its centre point, which will be automatically calculated for each face depending on its respective dimensions. Alternatively, if you want the PaperSprite to rotate around the top left corner, bottom right, or indeed any point on its surface, you can set the pivot property, which is a Point object and requires 2 normalised values, representing the fraction of the width and height of the PaperSprite at which you want to place the pivot.

So to set the PaperSprite to rotate around its centre (this is set by default) you can use:

mySprite.pivot = new Point( 0.5, 0.5 );

And its Top Left corner:

mySprite.pivot = new Point( 0.0, 0.0 );

And its top centre:

mySprite.pivot = new Point( 0.5, 0.0 );

And so on!

You can also access its isFrontFacing property at any time:

if ( mySprite.isFrontFacing )
{
	doSomethingGood();
}

An finally, removing the front or back face from its display list (or indeed not defining one at all) will cause the PaperSprite to display the available face at all times, essentially giving it the default behaviour of a one sided Sprite.

Download the PaperSprite class

Again, this is really just a glorified augmentation of Senocular’s solution to finding the front facing side of a DisplayObject in 3D. All credit should go to him for creating such an elegant solution. I built this class in order to simplify its use and provide the extra functionality needed to quickly start working with a two-sided DisplayObject.

Download: PaperSprite Class & Demo
Posted on 30 Dec 2008
101 Comments
10 Trackbacks

Meta

Double Sided 3D Plane in FP10 was posted on December 30th 2008 in the category Code / Actionscript 3.0, Code, Flash, Lab, Open Source and tagged; , , , , , , .

You can Leave a comment.

Discussion

108 Responses to Double Sided 3D Plane in FP10

Leave a Reply

Pingbacks / Trackbacks

  1. 3 years ago Senocular’s Two Sided 3D Clip

    [...] technique. The class is worth checking out – it’s nicely designed… read more about it here. This entry was posted in 3D, MovieClip and tagged actionscript, cross product, flash, polygon [...]

  2. 2 years ago 3D Cards in Flash « Bird In The City.com

    [...] Link Filed under: 3D, AS 3.0, Flash Leave a comment Comments (0) Trackbacks (0) ( subscribe to comments on this post ) [...]

  3. 2 years ago MARK/SAM » Blog Archive » Really Cool Two Sided 3D

    [...] found this test on Soulwire. It is an extension of papervision written by Soulwire called PaperSprite. It’s unique [...]

  4. 2 years ago Flash 10 3D example | dehash

    [...] December 23rd, 2009 | Author: dehash 3D Flash Player 10 example and code using PaperSprite and the new built in 3D instead of PaperVision. The output is similar to similar to the [...]

  5. 1 year ago 14lox blog » Blog Archive » New site update

    [...] that was essential for my project. While researching, I stumbled across Soulwire’s great PaperSprite class, which solves this problem by allowing you to add DisplayObjects, one to the front and one on to [...]

  6. 1 year ago Flash vs HTML5+JavaScript Libraries: And Don’t Forget The Tables « Nookeen Media

    [...] OK!nteractif made this section of a website for Musee de la Civilisation (Quebec). Also, I like this class of rotating objects – outstanding job! You can make such a cool animation with this technique. By saying NO to [...]

  7. 1 year ago flashVT » GameJam II: Cards are flipping and shuffling

    [...] cards are now flipping and I added some shuffling for testings. Thanks to soulwire for the PaperSprite class. Next up, limiting to 2 flips per turn and checking [...]

  8. 1 year ago I cannot (will not) use TLF text fields in Flash CS5 | harveyline blog

    [...] before releasing them to my website. (I recently replaced a Papervision component with the PaperSprite Class from SoulWire, thereby saving [...]

  1. Soulwire 3 years ago

    Hi Christian,

    There are purely mathematical ways to do this, but perhaps the simplest approach would be to use nested transformations. If you imaging placing a clip inside a holder clip and offsetting it by a certain amount (on any or all of its axis), you can then rotate the holder clip and the nested clip will orbit the center of the holder.

    Just to give you an example; publish this code for Flash Player 10:

    var holder:Sprite = new Sprite();
    holder.x = stage.stageWidth >> 1;
    holder.y = stage.stageHeight >> 1;
    addChild(holder);
    
    var box:Shape = new Shape();
    box.graphics.beginFill(0x000000);
    box.graphics.drawRect(0,0,80,80);
    box.graphics.endFill();
    
    box.x = 200;
    box.z = -200;
    
    holder.addChild(box);
    
    addEventListener( Event.ENTER_FRAME, run );
    
    function run( event:Event ):void
    {
    	holder.rotationY++;
    	holder.rotationZ -= 0.5;
    }
    

    Hope that helps.

    Reply to this comment

  2. Clonedesign 3 years ago

    Fantastic…
    Simple and effective!

    Thanks…

    Reply to this comment

  3. christian 3 years ago

    THANKS!!! A LOT!!! … the funny part? i was lost on cos() and sin() equations xD Maybe i have to go back to ockham’s teachings. Thanks, really, i needed that leading. I’ll send you a link when i have something working.

    Reply to this comment

  4. Digression 3 years ago

    I am having some trouble with this class, maybe you can help?

    I am generating some dynamic movieclips on my first frame and then moving on to the second frame once they are all loaded (via XML). On the second frame, I am implementing your class with a for loop in order to make a PaparSprite object for every single clip I have. My intent is to use these in a gallery and eventually be able to scroll through them with a mouse drag.

    My problem seems to be that the class will only make a SINGLE PaperSprite object, and only of the very LAST movieclip I pass it (via an array of my movieclips). I don’t have time to post my code today, but I can post it tomorrow, if it will help.

    Thank you in advance!

    Reply to this comment

  5. Soulwire 3 years ago

    Hi digression,

    The problem you are having is likely because a PaperSprite is essentially a container for two DisplayObjects. Once you create a PaperSprite, the front and back DisplayObjects which you pass to it are added to it’s display list. This means that the instances you created will remain only in the last PaperSprite, as they will be removed from any previous PaperSprite to be placed on the new one’s display list.

    For the demo above, I created the front and back faces from single MovieClip instances, and then each time I created a new PaperSprite I copied the original MovieClip to a bitmap and used the bitmap as the front / back faces of the PaperSprite.

    If you’re creating exactly as many MovieClips as you are PaperSprites (x2 for front and back) you should be ok.

    If you don’t think this is the problem, it would definatley be useful to see your code.

    If you think it might be the problem, perhaps Senocular’s duplicateDisplayObject class will help?

    Reply to this comment

  6. Digression 3 years ago

    I can release part of my code with no problems.

    To start with, I load 2 images via XML (and an exported movieclip MyMC) and add them as children to a movieclip called containerMC that is as big as the stage (550 x 400). I also push both of them into the array “clips”. There are no errors.

    On my next frame, I import your class (and know its working) followed by a for loop:

    for(var j=0;j<clips.length;j++){ //loops through number of images
    var myPaperSprite:PaperSprite = new PaperSprite();
    myPaperSprite.pivot = new Point(0,0.5);
    myPaperSprite.x = 0;
    myPaperSprite.y = 0;

    myPaperSprite.front = clips[j];
    myPaperSprite.back = createSprite(0xff0000); // Don’t need an image on the back.

    myPaperSprite.addEventListener ( Event.ENTER_FRAME, spin );

    containerMC.addChild(myPaperSprite);
    }

    ————

    The only thing I get is a single PaperSprite, using my second image and a red back.

    What would you suggest? Also, I’m not exactly sure how/where you would use the duplicate function (I’ve tried in both inside and outside the PaperSprite class to no avail).

    Thanks for the help!

    Reply to this comment

  7. Rob 3 years ago

    Your class seems really great, I was using it with some success but I’ve run into a road block and I’m not sure what’s happening.

    I made a few paperSprites and everything was working fine, but now when I try to create one it puts my back face on the front and mirrors it. I feel like this must be a 3D setting I accidentally tweaked somewhere (I’m new to CS4).

    Any help would be greatly appreciated. You can download my source files here: http://stationarynotes.com/paperSprite/PaperTest.zip

    And I’m pasting my code below.

    Thank you!!!

    
    import soulwire.display.PaperSprite;
    
    var myFrontCover:Cover1 = new Cover1();
    var myBackCover:Cover2 = new Cover2();
    
    var myPaperSprite:PaperSprite = new PaperSprite(myFrontCover, myBackCover);
    
    myPaperSprite.x = stage.stageWidth / 2;
    myPaperSprite.y = stage.stageHeight / 2;
    
    addChild(myPaperSprite); 

    Reply to this comment

  8. Rob 3 years ago

    *UPDATE*

    Ok it’s definitely a 3D setting that I screwed up. If I drag an object on stage and click the button to restore my defaults in the transform panel, everything works fine. I guess I’m transforming objects around a certain point but don’t know it.

    - Rob

    Reply to this comment

  9. Rob 3 years ago

    Ok, sorry to keep posting but I found that if I explicitly set the back face first and then the front face everything seems to work.

    Ex:

    myPaperSprite.back = myBackCover;
    myPaperSprite.front = myFrontCover;
    

    instead of…

    myPaperSprite.back = myBackCover;
    myPaperSprite.front = myFrontCover;
    

    When I try to use the constructor to set my faces, it still only shows a mirrored back face.

    I think that perhaps my front face is not loading or displaying but the back one is. Hence, it’s flipped like it’s supposed to be, but without a front face it becomes the only plane to display so everything is mirrored.

    Reply to this comment

  10. Rob 3 years ago

    ugh, sorry for the sloppy cut/paste up there ^^^ Second block should be reversed.

    Reply to this comment

  11. daz 3 years ago

    Hi,
    Fantastic works !
    is there a code snippet to mimic the OS.X Widget horizontal flip effect with a “go” button on the front and “back” button on the back side to flip and back, will be great :-)

    daz

    Reply to this comment

  12. Will 3 years ago

    This is really great. Thanks for making this. I have a suggestion though. I think it would be really great if you provided methods to flip a side either horizontally or vertically.

    For example if both my front and back sides contain text and I then rotate the PaperSprite 180 degrees along the X axis the text on the back side appears upside down. I tried flipping my display object BEFORE adding it to the back property but ran into trouble. I haven’t spend much time investigating it but you are probably flipping the back side somewhere in your code.

    Some ‘helper’ methods like flipBackHorizontally(), flipBackVertically() etc… could be really helpful.

    Reply to this comment