This is a follow-up of this.
![]()
Yeah well, I was more than optimistic to show those JS guys how fast Flash can be with the help of some brand new Adobe magic – but Pixel Bender was, unfortunately, quite disappointing:
- I spent hours to successfully migrate the code to Pixel Bender Toolkit (wasn’t that difficult actually, but a wrong character there and your math is all screwed up). So here the first letdown: Pixel Bender Toolkit is not a very nice coding environment. It’s a rough baby. But I’d do everything for speed :-)..
- Once I had it running (the above picture is captured from Pixel Bender) I tried to export it for Flash Player. But hoohoo! no support for loops in Flash Player! Yeah, well, ..(and also no custom functions by the way)
- But I didn’t give up. I just calculated how many max loops where needed (about 100) and replicated the while loop with many if-conditions (I love to do computer’s dummy job ;). Then finally: Export to Flash Player! But in Flash Player having the shader as Filter for a BitmapData just really fucked up the rendering. I even went down to 1fps, but still no luck. What a bummer! (sometimes I saw a few pixels blue, but very unusable: I’ve written to the Pixel Bender Forum - invited by @Pixelbender – but that led to nothing so far).
- Today, finally, I got it working by taking a more rough approach (not BitmapFilter, but ShaderJob). But hell is it slow!!! And it eats all my 8 cpu cores!! So I wondered how that could be: Fast as hell in Pixel Bender Toolkit (uses may be 2% of my cpu at full fps!), but slow as hell in Flash Player?! The answer is obvious: Adobe decided not to talk to the GCU (Graphics Card) for the calculations, probably to keep the Flash Player be as platform independent as possible – and as small as possible. But then I wonder.. WTF do you give us this toy if we can’t use it?!! It’s like Apple would say: «Great news: we have Core Graphics on the iPhone – without hardware acceleration..» Adobe, to me, this doesn’t make too much sense. (But I’m so very much pleased about the new Text Engine – *that* was a good job)
Here the result: (Click to start, it’ll eat your cpu!)
And for the geeks, here we go with the source codes:
<languageVersion : 1.0;> kernel MetaTunnel < namespace : "com.betabong"; vendor : "Betabong"; version : 1; description : "MetaTunnel Port"; > { parameter int size < minValue: 16; maxValue: 512; defaultValue: 128; >; parameter float time < minValue: float( 0.0 ); maxValue: float( 15.0 ); defaultValue: float( 0.0 ); >; input image4 src; output pixel3 dst; void evaluatePixel() { float cos1 = cos( time ); float cos0_5 = cos(time * 0.5); float cos0_7 = cos(time * 0.7); float sin1 = sin( time ); float sin0_2 = sin(time * 0.2); float sin_0_5 = sin(time * 0.5); float dim = float( size ); float2 point = outCoord() / dim; if ( point.x > 1.0 || point.y > 1.0 ) { dst.rgb = float3( 1.0 , 1.0 , 1.0 ); } else { float2 vp = float2( point.x * 2.0 - 1.0 , -point.y * 2.0 + 1.0 ); float s = float( 0.4 ); float3 op = float3( vp.x , vp.y * 1.25 , 0.0 ); float3 dp = float3( (vp.x + cos1 * 0.3) / 64.0 , vp.y/64.0 , 1.0/64.0 ); float f = float( 1.0 ); float tt = float( 0.0 ); float g = float( 1.0 ); float3 p = float3(1.0,1.0,1.0); while ( (g > s) && (tt<375.0) ) { p = op + ( dp * tt ); f = 1.0; f *= abs( distance( float3( cos1+sin0_2 , 0.3 , 2.0+cos0_5*0.5 ) , p ) ); f *= abs( distance( float3( -cos0_7 , 0.3 , 2.0+sin_0_5 ) , p ) ); f *= abs( distance( float3( -sin0_2*0.5 , sin1 , 2.0 ) , p ) ); f *= cos(p.y)*cos(p.x) - 0.1 - cos( p.z*7.0 + time*7.0 ) *cos(p.x*3.0)*cos(p.y*4.0)*0.1; g = f; tt += g * 4.0; } float color = 0.0; float3 dtt = op + ( dp * tt); p = float3( dtt.x , dtt.y , dtt.z ); f = 1.0; f *= distance( float3( cos1+sin0_2 , 0.3 , 2.0+cos0_5*0.5 ) , p ); f *= distance( float3( -cos0_7 , 0.3 , 2.0+sin_0_5 ) , p ); f *= distance( float3( -sin0_2*0.5 , sin1 , 2.0 ) , p ); f *= cos(p.y)*cos(p.x)-0.1-cos(p.z*7.0+time*7.0)*cos(p.x*3.0)*cos(p.y*4.0)*0.1; float objd = f; float3 np = float3( 0.0,0.0,0.0 ); p = float3( dtt.x + 0.01 , dtt.y , dtt.z ); f = 1.0; f *= distance( float3( cos1+sin0_2 , 0.3 , 2.0+cos0_5*0.5 ) , p ); f *= distance( float3( -cos0_7 , 0.3 , 2.0+sin_0_5 ) , p ); f *= distance( float3( -sin0_2*0.5 , sin1 , 2.0 ) , p ); f *= cos(p.y)*cos(p.x)-0.1-cos(p.z*7.0+time*7.0)*cos(p.x*3.0)*cos(p.y*4.0)*0.1; np.x = objd - f; p = float3( dtt.x , dtt.y + 0.01 , dtt.z ); f = 1.0; f *= distance( float3( cos1+sin0_2 , 0.3 , 2.0+cos0_5*0.5 ) , p ); f *= distance( float3( -cos0_7 , 0.3 , 2.0+sin_0_5 ) , p ); f *= distance( float3( -sin0_2*0.5 , sin1 , 2.0 ) , p ); f *= cos(p.y)*cos(p.x)-0.1-cos(p.z*7.0+time*7.0)*cos(p.x*3.0)*cos(p.y*4.0)*0.1; np.y = objd - f; p = float3( dtt.x , dtt.y , dtt.z + 0.01 ); f = 1.0; f *= distance( float3( cos1+sin0_2 , 0.3 , 2.0+cos0_5*0.5 ) , p ); f *= distance( float3( -cos0_7 , 0.3 , 2.0+sin_0_5 ) , p ); f *= distance( float3( -sin0_2*0.5 , sin1 , 2.0 ) , p ); f *= cos(p.y)*cos(p.x)-0.1-cos(p.z*7.0+time*7.0)*cos(p.x*3.0)*cos(p.y*4.0)*0.1; np.z = objd - f; float d = length( np ); np.y /= d; np.z /= d; color = max( -0.5 * np.z , 0.0 ) + max( -0.5 *np.y + 0.5 * np.z , 0.0 ) * 0.5; float3 rgb = float3(color + 0.1 * tt * 0.025 , color + 0.2 * tt * 0.025 , color + 0.5 * tt * 0.025 ); rgb.x = max( 0.0 , min( 1.0 , rgb.x ) ); rgb.y = max( 0.0 , min( 1.0 , rgb.y ) ); rgb.z = max( 0.0 , min( 1.0 , rgb.z ) ); dst.rgb = rgb; } } }
And here the Actionscript part:
package { import flash.display.*; import flash.events.*; import flash.filters.*; import flash.net.*; import flash.utils.ByteArray; import net.hires.debug.Stats; // SWF Metadata [SWF(width = "520", height = "128", backgroundColor = "#000000", framerate = "1")] public class MetaTunnelBender extends Sprite { [Embed("test/MetaTunnel-stupid.pbj", mimeType = "application/octet-stream")] private var TestFilter: Class; private var playing : Boolean; private var im: Bitmap; private var job:ShaderJob; private var shader: Shader; private var shaderfilter:ByteArray; private var time:Number = 0.0; private const SIZE:Number = 64; private const WHITE:BitmapData = new BitmapData( SIZE , SIZE , false , 0xffffff ); public function MetaTunnelBender() : void { stage.frameRate = 20; im = new Bitmap( WHITE.clone() ); im.scaleX = im.scaleY = 2; addChild(im); // stat info var s:DisplayObject = new Stats(); addChild( s ); s.x = 128; //Pass the embedded filter to the Shader as a ByteArray shaderfilter = new TestFilter() as ByteArray; shader = new Shader( shaderfilter ); shader.data.size.value = [ SIZE ]; //start shaderjob (async start won't work - bug?) job = new ShaderJob( shader , im.bitmapData , im.width , im.height ); job.start( true ); // let's start/stop on click stage.addEventListener( MouseEvent.CLICK , click ); // render first frame enterframe(); } private function enterframe( e:Event = null ) : void { time += 0.05; shader.data.time.value = [ time ]; trace( job.progress ); job = new ShaderJob( shader , im.bitmapData , im.width , im.height ); job.start( true ); } private function click( e:* = null ):void { if( !playing ) { addEventListener( Event.ENTER_FRAME , enterframe ); } else { removeEventListener( Event.ENTER_FRAME , enterframe ); } playing = !playing; } } }
No related posts.
One Comment, Comment or Ping
Jackson Dunstan
I get about 8 FPS on a 3.0 Ghz Intel Core 2 Duo on Windows XP. Your AS3 version is a ton faster, although there is no framerate counter so I can’t quantify that.
Oct 1st, 2009
Reply to “MetaTunnel with Pixel Bender”