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; } } |
