Z-sorting 3D DisplayObjects for Flash Player 10
October 13th, 2008
The next release of the Flash Player has support for 2.5D- which boils down to 3D properties, appropriate perspective, but no depth sorting. This method takes a DisplayObjectContainer, transforms its children into world space and sorts them along that z-axis. It’s sloppy because it’s DisplayObject-based and so there will be noticeable “pop” when a DisplayObject is sorted onto the top of the display list in close proximity to another. That said it should be perfect for carousels and other views that aren’t super tight.
Here’s a demo
And here’s the algorithm:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | public static function simpleZSort3DChildren( doc:DisplayObjectContainer, recurse:Boolean = true ) : void { //transforms from local to world oordinate frame var transform:Matrix3D = doc.transform.getRelativeMatrix3D( doc.stage ); var numChildren:int = doc.numChildren; //v = ( n * 3 )- (x,y,z) set for each child var vLength:int = numChildren * 3; var vLocal:Vector.<Number> = new Vector.<Number>( vLength, true ); var vWorld:Vector.<Number> = new Vector.<Number>( vLength, true ); //insertion point for child’s coordinates into state vector var vIndex:int = 0; for( var i:int = 0; i <numChildren; i++ ) { var child:DisplayObject = doc.getChildAt( i ); if( recurse && child is DisplayObjectContainer ) simpleZSort3DChildren( DisplayObjectContainer( child ), true ); vLocal[ vIndex ] = child.x; vLocal[ vIndex + 1 ] = child.y; vLocal[ vIndex + 2 ] = child.z; vIndex += 3; } //populates vWorld with children coordinates in world space transform.transformVectors( vLocal, vWorld ); //bubble sorts children along world z-axis for( i = numChildren - 1; i > 0; i-- ) { var hasSwapped:Boolean = false; vIndex = 2; for( var j:int = 0; j < i; j++ ) { //z value at that index for each child var z1:Number = vWorld[ vIndex ]; vIndex += 3; var z2:Number = vWorld[ vIndex ]; if( z2> z1 ) { //swap doc.swapChildrenAt( j, j + 1 ); //swap z values (don’t need to change x and y because they’re not used anymore) vWorld[ vIndex - 3 ] = z2; vWorld[ vIndex ] = z1; //mark as swapped hasSwapped = true; } } //if there was no swap, we don’t need to iterate again if( !hasSwapped ) return; } } |

Cool, I love random colors!
notice how they can get really ugly with lots of green an violet
Nice example. Thanks for sharing.
I’m not able to view the example
I have to manually type the name to the SWF file to view it. Perhaps the embedding script is the culprit.
yeah, z-Sorting with Flash 10 is very dissatisfying.
anyhow, nice example!
I´ve setup my own little “3d debris pattern” with Flash10, and zorting all my cubes along the z-Axis was very sadly, ´cause of the fact you can see the clippings.
http://www.dasprinzip.com/prinzipiell/2008/12/04/debris-pattern/
cheers
-frank
nice! i’m also using this for thing i’m working on.
i had to add a couple of minor checks. the first one is to make sure that there’s already Matrix3D on the container (because, there are cases in which it hasn’t been initialized yet)… the second one is to make sure the component has been added to the display list before trying to sort anything.
the tests perform really well. thanks, man.
http://rojored.googlecode.com/svn/trunk/docs/example/carousel/c03/bin/Main.swf
I packed the method on a util class on a swc… are planning to release this stuff any other way?
http://rojored.googlecode.com/svn/trunk/docs/examples/carousel/c03/bin/Main.swf : / broken link.
Awesome, that looks really good, Gabo!
As far as doing checks for no Matrix3D and existence on display list, I think it makes a lot of sense to leave that up to the user. This is pretty hammered down and efficient. Maybe I’ll make a static class that allows the user to register for sorting so that I can avoid some of the complex type creation at important-time and handle those sorts of issues…
hi,
thanks for that great code! i’ve found your post on the flash blog where another z sorting class is discussed. i’ve putted your method into a static class for quick access. but one question popped up:
- why do you use getRelativeMatrix3D( container.stage ); wheres as getRelativeMatrix3D( container ); should work the same way?
thanks for your answer!
the idea is that it sorts in global coordinates. if the sort only accounted for the container’s transformations, any transformations above it in the display list would be neglected.
this’s great! thank you drew
there’s a change that child is null
i’ve try put a condition before doing recurse check
if(!(child==null && i==0)){ line 22 to 28 }
and everything seems to be fine
i wonder if there’s other way to solve this, any suggestion?
This is great code, but after I installed Flash 10.02 it stopped working on this line:
transform.transformVectors( vLocal, vWorld );
with this error message:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
Help!
Hey Philip,
It looks like the transformation matrix didn’t get defined which probably means your DisplayObjectContainer isn’t on the display list yet (makes use of its stage reference). Let me know if that’s the case.
i don’t think child should be able to be null… what are the circumstances??
@drew
Hi Drew,
It is a stage object – a movieClip (called “test”) with movieClips inside. The code is on the timeline (which worked fine before 10.02). I put a delay in to see if that would help, but no luck. I even tried using addChild for the object with no luck.
this.addEventListener(Event.ENTER_FRAME, sortZ);
var count = 0;
function sortZ(e) {
count++;
if (count > 100) {
simpleZSort3DChildren(test, false);
}
}
function simpleZSort3DChildren( doc:DisplayObjectContainer, recurse:Boolean = true ) : void
…rest of code copied exactly from yours…
This works really well for my 3d car experiments, thanks for putting up the code.
@drew
some more info on the error I’m seeing with Flash 10.02. This statement:
var transform:Matrix3D = doc.transform.getRelativeMatrix3D( doc.stage );
results in a null value for the var “transform”. But I’ve confirmed “doc” and “doc.stage” are valid objects. The same error occurs if I create a MovieClip in code, add it to the display list, and pass it to simpleZSort3DChildren. Anyone else seeing this problem?
@Philip van Allen
Okay, here’s a workaround. It seems the DisplayObjectContainer must have its “z” property set explicitly. Drew’s code works in Flash 10.02 if you insert the following line
doc.z = doc.z;
Before this line
transform = doc.transform.getRelativeMatrix3D( doc.stage );
Thanks. I am using CS3 to publish as Fp10 3D . Your Sorting code shows error in it. Should i get CS4 or is there any trick?
what is the error you’re getting? compile-time or run-time? a couple assumptions are made that could result in a run-time error. 1) the DisplayObjectContainer is on the display list. 2) as in Philip’s comments above, that a 3D property has been set on the DisplayObjectContainer.
Hi im new to AS3
I saved the code above as engine.as file, import engine; on the first line
I added a 3d cube made in a symbol
made a frame 2 -> 1 loop
//
addEventListener(Event.ENTER_FRAME,newlooper);
function newlooper(event:Event){
this.obj1.rotationX=mouseX
this.obj1.rotationY=mouseY
}
///
I dont see the sorting work at all. The box still see inside out.
Any ideas?
Can you give the source of a working example? I’m also getting a null value for transform = doc.transform.getRelativeMatrix3D( doc.stage ); even though 3D properties have indeed been set on my doc
I don’t think I have the demo source still, but it would be easy enough to recreate it if necessary. Is your object on the display list? Otherwise stage will be null.
Thank you!It helped me!