Quantcast
Viewing all articles
Browse latest Browse all 8

AS3 to Pixel Bender guide

When I set out to write a very simple Pixel Bender (PB) kernel/script thingy, I expected it to be relatively straight-forward, mostly because Adobe has been so good writing quality documentation for its products and/or there is a wealth of info on their products produced by their users. Unfortunately I didn’t find the dev guide in the Help menu and I missed some key AS3 bits from the links I’ll post below, but even so I still had a lot of trouble finding some info that really should already have been out on the interwebs. So this post is to fill in the gaps when going from AS3 to Pixel Bender.
Hope it helps Image may be NSFW.
Clik here to view.

Best resources for beginners

Here’s the best tutorials and explanations I’ve found so far:

Syntax overview

As a casual programmer of high-level languages and no mid- to low-level ones, I was thrown off by PB’s awkward syntax. It’s strongly typed, which is fine, except I’m not familiar with low-level languages like C or any previous shader language (PB is based on GLSL from what I hear). Here’s a basic difference:

AS3: var i:Number = 12;
…in PB is: float i = 12.0;
The decimal in 12.0 tells PB it’s a floating point number. If it was just 12 PB would think it’s an int.

When dealing with “vectors” (which are arrays, as in Flash 10′s odd use of the word “vector”) it’s float2 i = float2(12.0, 2.0). Notice there’s no brackets or anything suggesting any type of array present. It’s simply the type + how big the array is, eg float3. It goes up to 4, for the 4 channels in images: Red, Green, Blue, Alpha). Then, as you can see, intializing the array is a simple matter of putting in the numbers you said would be there. So float4(1.0, 24.2, 0.1, 3.4) is valid whereas float2(1.0, 24.2, 2) is not, because there’s an extra number in there and it’s an int (adding insult to injury).

An important thing to keep in mind is that Pixel Bender sees channels in the order described above (RGBA). This little detail cost me a bit of time because I’m used to AS3′s order of ARGB–the alpha channel is first in AS3 while it’s last in PB.

To use any of the built-in functions you simply call them as they appear in the reference doc: all(x); atan(x,y); etc., no Math calls like we have to do in Flash (this through me for a loop, lemme tell ya).

For those of you who use the shortcut operations like var i:int = foo < bar ? foo : bar;, then you'll be pleased to hear they're supported in PB too. Just about the only thing "Hydra" (formally the codename for Pixel Bender, now--I guess--the name of the PB Flash implementation) does not support is loops of any kind and their related break/continue statements. That last bit is bad because there are times when I want to stop the filter if a certain condition is met. You just have to design your logic to take this into account from the start.

That's the basics but take special note that shader.data is actually an array, so you can do some naughty stuff like iterate through some kinky data and set the input as shader.data['whatever'+i].input = kinky[i]. Also note that in order to set the input for a shader in AS3 you must set it to shader.data.vdipb.INPUT = inputImage where vdipb is the variable name you declared in the PB shader itself.

More performance tips

Turns out that after I converted my kernel from using boolean methods (like boolean4() etc.) to if statements, it consistently executed faster. I also got some fractional FPS increases by using the age-old optimization of putting real values (eg 1.2) in the evaluation statement instead of references (eg pixel.r). See the last blog I linked above for some other obvious and not-so-obvious performance tips.

PB math is much faster than straight AS3 math but it's slightly brighter (I wouldn't say it shines per se...) when it runs in asynchronous mode, which is enabled by using ShaderJob. You use addEventListener(Event:ShaderEvent...) and then run start(false) to put it in asynchronous mode (the param is waitForCompletion and it's already false by default). See Ryan's post for a great example of how the ShaderJob has to be setup (Squize's post, linked above, is an even clearer example).

Realtime use of Pixel Bender

Asynchronous mode

Reading the above linked performance tips for PB you, like me, might be thinking "OH MAN I can rule the universe with ShaderJob doing bitchwork like heavy collision solving" and you'd be totally wrong. You only have to set the input for a shader once, but you do have to create a new ShaderJob per computation of the filter every frame/tick. This is the depressing because ShaderJob takes a LONG time to start up and it, unlike the job itself, does use CPU from Flash's main thread--you do not get the asynchronous hotness until the actual job is started. And it is sloooooowwwww. Unless you're doing some serious number crunching or temporary special effect, you will not see a huge benefit from using PB in your game.

To be clear, ShaderJob works well enough for realtime usage but my experiments have shown that it's not fast enough to be executed every frame (unless you're SWF is running at 20 FPS or so). I tried to get it to fulfill my game's collision detection system by processing the entire map, but PB just couldn't handle the job. Still, I do recommend you try it (using Squize's recursive implementation) and see if it works for you. Just keep your hopes down Image may be NSFW.
Clik here to view.
;)

Synchronous mode

You can set ShaderJob.start(true) but if you're going the synchronous route, I suggest applying your Pixel Bender kernel by using the filter method. It starts up much faster than ShaderJob and doesn't have to be restarted every time you want to update the input. You do have to wait for it to finish processing before it will move to the next line in your code though, but as I mentioned above, PB math is a lot faster than AS3's Math library. So if you're doing something intense(r) like severe image distortion then PB is definitely worth a shot, but if it's just conditionals then you're probably better off in pure AS3 land.

Conclusion

Besides doing complex calculations, another place where PB would really help though is processing large (like 600 or 10000 pixels wide or bigger) images. It loops through each pixel faster than AS3 does. But remember that in AS3 you can do loops, so easily skipping pixels (using the continue statement) can result in some significant performance gains if you're not processing all the pixels in the input data (eg skipping transparent pixels). There's a lot of pro/cons so experimenting is, as always, the way to go (if you can afford it).

So there it is, all the info I wish was out there when I started learning PB (I can't stop thinking of Peanut Butter!). Hope some of it was helpful and of course I could be wrong about something (except about declaring input once, I've heard otherwise but in practice it worked fine) so please don't hesitate to correct me if so. Good luck and have fun Image may be NSFW.
Clik here to view.

Image may be NSFW.
Clik here to view.
flattr this!


Viewing all articles
Browse latest Browse all 8

Trending Articles