follow me on twitter

Note to self: remember to use the test database when testing this site ;D


final test - hope

Working with Shaders/Filters in Flash 10

Disclaimer: Beta API, APIs may change. Article based on investigatory work via code introspection.

Update: "Hydra" is now known as "Pixel Bender"

Loading Hydra Filters

The Flash API encapsulates Hydra Filters as a flash.display::Shader instances. To create a Shader instance we need to inject the byte code from a compiled Hydra filter file into it. We can do this in two familiar ways.

1) Using ActionScript 3 meta tags to inject the byte code directly into our compiled SWF.


[Embed(source="HydraFilter.hbc", mimeType="application/octet-stream")]
var Filter:Class;

var shader:Shader = new Shader(new Filter());

2) With the use of the URLLoader class which brings all the benefits of runtime loading.

function loadFilter() {
loader = new URLLoader();
loader.dataFormat = URLLoaderDataFormat.BINARY;
loader.addEventListener(Event.COMPLETE, loadCompleteHandler);
loader.load(new URLRequest("HydraFilter.hbc"));
}

function loadCompleteHandler(event:Event):void {
var shader:Shader = new Shader(loader.data);
}

Accessing Filter Properties and Defining Input

Hydra filters usually take different parameters in order to control their output. For example, the existing BlurFilter in Flash has blurX and blurY to control the strength of its "blurring". Flash 10 encapsulates a single filter parameter into a dynamic flash.display::ShaderParameter class instance. This class is dynamic in order for it to be able to inspect custom parameter meta-data . For example you might have minValue / maxValue set on the filter parameter (see below).

parameter float strength
<
description: "The strength of the blur";
minValue: 0.0;
maxValue: 50.0;
>;

To set the value of a ShaderParameter, you can access the 'value' property of ShaderParameter and get/set Arrays on it. The size and type of data in the array all depends on the type of data the filter parameter is expecting. You can ask the ShaderParameter which flavor of Array it's expecting by calling the 'type' property of ShaderParameter. In our Hydra code above you can see that the parameter is a float. A float requires a single Array element with the data type of that element being a Number. So for example, we could set ... value = [10] .. and now the value of the strength is 10.

All of these ShaderParameter's are wrapped up in another shader centric class called flash.display::ShaderData. This class is completely dynamic and gives access to ShaderParameter's by their name. You should also be able to enumerate over them using a "for each" or "for in" loop. ShaderData also gives you assess to meta-data from the header of the Hydra filter such as its name, version, etc. So extending on the previous example, we can now say .. shaderData.strength.value = [10]

ShaderData also exposes the image input properties of a Hydra filter. For example our Hydra filter may be expecting a bitmap with an alpha channel ...

input image4 src;

We represent this bitmap data input with yet another shader centric dynamic class called flash.display::ShaderInput. This class exposes some key meta-data type information about the input image property such as how many channels the bitmap should process (shaderInput.channels:int) and the index order of the property within the filter (shaderInput.index:int). The main property of this class is the 'input' property. Here we can set either a BitmapData, ByteArray or a Vector.<Number> instance that contains our input image. If the input is not a BitmapData type, then 'width' and 'height' properties must also be assigned to the ShaderInput instance.

Below is an example of assigning BitmapData to a ShaderInput (input image4 src) through our ShaderData:

shaderData.src.input = new BitmapData(123, 321, true, 0xFFCC00CC);

ActionScript developers should not typically need to create ShaderParameter and ShaderInput instances. All instances are created automatically to map to the requirements of the custom Hydra filter. All of these data instances should be accessible via the flash.display::Shader instance that we created before from our Hydra filter byte code. The property of Shader that gives us access to all of these parameters, inputs and meta-data is the 'data' property.

Example:

var shader:Shader = new Shader(hydraShaderByteCode);

trace(shader.data.name) // "DemoFilter"
trace(shader.data.version) // "1"
trace(shader.data.strength.maxValue) // 50.0
trace(shader.data.strength.description) // "The strength of the blur"
trace(shader.data.src.channels) // 4

shader.data.strength.value = [10]
shader.data.src.input = new BitmapData(123, 321, true, 0xFFCC00CC);

Filter Rendering - BitmapFilter

Once you have encapsulated your hydra filter as a Shader, everything else starts to become very familiar. We just have one more element to add. The missing element is the flash.filters::ShaderFilter class. This class extends flash.filters::BitmapFilter, which is the base class for all existing DisplayObject filters. And so, we can now utilize our Shaders in exact same way that we would traditionally work with existing built in filters such as BlurFilter.

NOTE: BitmapFilter will automatically set the first ShaderInput for you. The DisplayObject that the BitmapFilter is assigned to becomes the first image input. Additional image inputs shall need to be defined in the usual way.

In this example below, we can how we wrap the Shader up into a ShaderFilter and apply it to a Sprite.

[Embed(source="HydraFilter.hbc", mimeType="application/octet-stream")]
var MyFilter:Class;

var shader:Shader = new Shader(hydraShaderByteCode);
var filter:ShaderFilter = new new ShaderFilter(shader);
filter.data.strength.value = [10];

var sprite:Sprite = new Sprite();
sprite.graphics.beginFill(0xcc00cc);
sprite.graphics.drawRect(0,0,123,321);
sprite.filters = [filter];

addChild(sprite);

Filter Rendering - Threaded Background Jobs

Sometimes a Hydra filter might take longer than desired to render. And because Flash currently runs on a single threaded rendering loop, a taxing filter could leave an applications UI unresponsive for an undesired amount of time. To avoid this scenario, Adobe have added the ability to perform background GPU filter rendering outside of the main thread, in the form of "jobs".

The Flash API defines the flash.display::ShaderJob class for developers to manage this background rendering process. Here is an example using a BitmapData object as our output "bucket".

function startJob(shader:Shader, target:BitmapData) {
var job:ShaderJob = ShaderJob(shader, target);
job.addEventListener(ShaderEvent.COMPLETE, shaderJobCompleteHandler)
job.start()
}

function shaderJobCompleteHandler(e:ShaderEvent):void {
var result:BitmapData = e.bitmapData;
}




senocular via the old blog says ... You may notice that source code for Pixel Bender (hydra) files now use the extension .pbk and bytecode uses the extension .pbj

Laurent Kappler via the old blog says ... Hi Alex,

Very interesting post!

I'm trying your method but I get an error from flash player 10

ArgumentError: Error #2004: L'un des paramètres n'est pas valide.
at flash.display::ShaderData/_setByteCode()
at flash.display::ShaderData()
at flash.display::Shader/set byteCode()
at flash.display::Shader()
at Main/init()[D:\job\logiquefloue\prog\as3\_Astro\AstroShader\src\Main.as:23]
at Main()[D:\job\logiquefloue\prog\as3\_Astro\AstroShader\src\Main.as:17]

it's like the new Filter() is not a byteArray.
Do you have an idea what's going on. My code here:

package
{
import flash.display.*;
import flash.filters.*;


public class Main extends Sprite
{

[Embed(source="../asset/firstSteps.pbk", mimeType="application/octet-stream")]
public var Filter:Class;
public var shader:Shader;

public function Main():void
{
init();
}

public function init():void
{

shader = new Shader( new Filter() );

}
}

}

ty
L

admin via the old blog says ... You need to use the compiled version of the filter (the .pbj). You can use the Pixel Bender Toolkit to do this. http://labs.adobe.com/wiki/index.php/Pixel_Bender_Toolkit

[FlashPlayer10]Minimal template for using Pixel Bender Filters via the old blog says ... [...] The Back Button » Working with Shaders/Filters in Flash 10 The Flash Blog » Loading Pixel Bender Filters in Flash 10 AstronShaderFilter AIF [...]

JoJo Jonboy via the old blog says ... Hi there.
I i saw ya msg on thebackbutton.com
Very well constructed
In fact I have been looking for something similar for yonks
thebackbutton.com is a site i'll keep bookmarked
Great effort keep up the good work !
John
selling used cars online

de via the old blog says ... Note, that you can embed Shader's bytecode in Flash CS4 IDE too. Not that good way, but why bother with a loader? Bytecode is actually ByteArray, so you just need to form it somehow. For example you can convert the actual .pbj file to hex codes, store the hexcodes string as string, convert the hexcodes string to ByteArray and set bytecode to that array.

MorganLucile via this site says ... Some time before, I needed to buy a house for my business but I did not have enough money and couldn't buy something. Thank heaven my friend proposed to try to get the <a href="http://lowest-rate-loans.com/topics/home-loans">home loans</a> at reliable creditors. So, I acted so and was satisfied with my secured loan.







Coming Soon