Create Custom Filters Using the Pixel Bender Toolkit

Create Custom Filters Using the Pixel Bender Toolkit

Tutorial Details
  • Program: Flash CS4
  • Platform: Flash (Flash Player 10)
  • Libraries used: Pixel Bender

Twice a month, we revisit some of our readers’ favorite posts from throughout the history of Activetuts+. This tutorial was first published in September, 2009.

Hi, once again, my name is André and in this tutorial I’ll demonstrate how to create custom filters with the Pixel Bender Toolkit, then use them with Flash CS4 to output .pbj files.

* This feature works only in Flash Player 10.


Step 1: The Pixel Bender Toolkit

The Pixel Bender Toolkit comes with the Adobe Master Collection CS4 pack, or you can download it at http://labs.adobe.com/downloads/pixelbender.html.


Step 2: The Basics

Before creating any filter, we must understand the basic functions and types of the language. It’s different to Flash, and much simpler.

The input keyword: This is the input image, the image that will be read and worked on. We can have up to 2 input images in the code, working with one image will create a filter, and working with 2 images will create a blend mode. The input is always type of “image4″, which is an image in RGBA mode (Red, Green, Blue and Alpha).

The output keyword: This is the output pixel, as opposed to the input. This will not output the image, this will just output the pixel read in RGBA. This is type “pixel4″ (and not image4 like the input).

The parameter keyword: Parameter keyword will work like a setter function. With the parameter the values of the filter can be changed when in use. The parameter must be followed by the type and name, and can also have minimum value, maximum value and default value. Example: parameter int dimension <minValue:1; maxValue:10; defaultValue:1;>; or parameter float myfloat <minValue:1.0; maxValue: 2.0; defaultValue: 1.0>. Also the parameter can be typed float2, float3, float3, int1, int2… example: parameter float2 test <minValue:float2(1.0,2.0);maxValue:float2(5);defaultValue:float2(1.0,2.0);>;

Also we have the types float, float2, float3, float4, int, int2, int3, int4 and many others which we will not use here. Also, some types don’t work with Flash Player 10, so I won’t get into them right now. I will, however, discuss a little bit about the types I’ve mentioned here and how they work.

Type float, float2, float3 and float4: when you create a float4 type for example, you are creating an array of 4 float values. In Pixelbender the float values are define by dot, but float() also works like a function to convert other number values in float. For example "float4 test=float4(1,2,3,4);". Here we have an object with 4 values (type float) in “test” variable. You can also create a float4 object from one value, for example: "float4 test=float4(3);". Here we have an object with 4 values (RGBA) and all values are the same (3.0 float). When you create a float value, you can also create it using a dot like "float test=1.0;". If you try to define it like "float test=1;" it will throw an error, because numbers without a dot in pixelbender work like int values.

So float are always defined by dot. Even using “float()” to create the float value will return a number with a dot. Lastly, to access float values with more than one value you can use syntax like an array access ” variable[0] or variable[1] or variable[2] … “.

Type int, int2, int3 and in4 are the same thing as float types, but don’t have dots. You can also convert number values using “int” like functions.

evaluatePixel(): this function runs over all the image, pixel by pixel, and then returns the output type pixel4. In custom filters for Flash we always use this function.

outCoord(): this function returns the current coordinate of the pixel being read by the evaluatePixel function. It returns a value type float2, x and y values, and can be accessed by [] like array or .x and .y like object. For example: var out=outCoord(); //out.x is the same of out[0] and out.y is the same of out[1].

sampleNearest(source,pixelCoordinate): this function returns the float4 value of the pixel from the source image (image4) at the coordinations “pixelCoordinate”. Normally we use the “outCoord” function here.

An observation must be made; when using float values and you want to add/subtract/multiply or divide the values with other float value of the same length, you can use them like this example:

  float4 test1=float4(3.0,2.0,2.0,3.0);
  float4 test2=float4(1.0,2.0,2.0,1.0);
  float4 result=test1-test2;

The result will be a variable type float4 with values 2.0, 0.0, 0.0 and 2.0. Also, you could use:

  float4 test1=float4(3.0,2.0,2.0,3.0);
  float4 test2=float4(1.0,2.0,2.0,1.0);
  float4 result=test1;
  result[0]=test1[0]-test2[0];
  result[2]-=0.5;

I think this is enough to understand the structure of Pixel Bender code, let’s move onto the next step, after I’ve mentioned just one more thing:

Before testing any filter, it’s important to load at least one image (file > load image 1″). To test the filter you can go to build > run, if the filter has any parameters, on the right side of the application you’ll see sliders to change the values. They change at runtime and have a live preview, since each time you press run again.


Step 3: Create a New Pixel Bender Filter

This filter comes with Pixel Bender Toolkit, but is one of the simpler filters to explain. For more about the Pixel Bender language reference just hit F1 button in the program, and the help in .pdf will open.

Once the program is open, create a new Kernel Filter (file > new kernel filter) the program will create a default structure for the filter:

<languageVersion : 1.0;>
kernel NewFilter
<   namespace : "Your Namespace";
    vendor : "Your Vendor";
    version : 1;
    description : "your description";
>
{
    input image4 src;
    output pixel4 dst;

    void
    evaluatePixel()
    {
        dst = sampleNearest(src,outCoord());
    }
}

In kernel NewFilter, you change the name NewFilter for the name of your filter. Namespace, vendor, version and description I don’t need to explain, just your strings like author, version (int) and the description.

The input image will be the image loaded by the filter and the output will be the pixel generated by the evaluatePixel function. The output will be a pixel4 value generated by the evaluatePixel function, which runs pixel by pixel of the input image as I’ve explained.

At the line “dst = sampleNearest(src,outCoord());” we are getting the value of the current pixel, and the coordinate outCoord() from image src (the input image), so we can modify the values of the rgba value of the dst. For example, if we want to invert the colours of the input image, we could do the following:

    dst = sampleNearest(src,outCoord());
    dst.rgb=float3(1)-dst.rgb;

What are we doing here?

We are stating that the rgb value of this pixel is the array of float3 value less the original value of rgb, so the color will be inverted. You can use the dst.rgb instead of using dst[0], dst[1]… and the order after the dot can be any order, it will read each letter as the value of the color. For example, you can use dst.gbr=float3(1)-dst.gbr. Another thing you can try is to change the colours of the image. For example by using the code below (inside the evaluatePixel function):

    dst = sampleNearest(src,outCoord());
    dst.rgb=dst.brg;

This code will output an oddly coloured image.


Step 4: Testing a Prepared Code From Adobe

Let’s test a filter from Adobe. The pixelate filter is great for testing, so go to file > open; in the folder where Pixel Bender is installed there are some filters. Let’s choose the pixelate filter. Once it’s open you can hit the “run” button to test the filter. If you want to export, go to file > Export kernel filter for flash player. This will export the filter to use with Flash, you can load the filter with the URLLoader or embed with the Embed tag from Flex SDK. In this tutorial I will show how to work with the embedded file, since the filter weighs only about 4kb to 15kb (it’s very lightweight).

The output extension is a .pbj file.


Step 5: Create the Folder Structure

If you have a classpath for Flash, use your classpath, if you dont have one and want to create one, open my previous tutorial and follow Step 1. If you don’t want a classpath, use the same folder of your .fla document. Let’s assume the classpath for the tutorial.

In your classpath create the folder “pixelbender”. Then inside the “pixelbender” folder, inside your classpath create the folder “pbj”. Copy the .pbj file (example: pixelate.pbj) to this pbj folder you’ve created.


Step 6: Creating the Class for the Pixelate Filter

Open Flash CS4, or Flex with updated SDK for FP10. If you’re using Flash, it’s important to setup the Flex SDK for Flash. If you don’t know how to do this, hit “ctrl+u” to open the preferences of Flash, then select the “actionscripts” at category, then “Actionsctipt 3.0 settings”. In the window “Actionscript 3.0 advanced settings” click the “+” button of the library path and add the following: $(FlexSDK)/frameworks/libs/flex.swc. Click the OK button.

Now create a new .as file, and start coding the following:

First we set the package and import the necessary classes.

package pixelbender{
	import flash.display.Shader;
	import flash.filters.ShaderFilter;
	import flash.utils.ByteArray;

Create the public class PixelateFilter extending the ShaderFilter. The ShaderFilter can be applied as a normal filter in the filter array of any DisplayObject.

public class PixelateFilter extends ShaderFilter{

Embed the pixelate.pbj file in the folder pbj (we’re assuming that we’ll save the .as in the pixelate folder of our classpath). The embed tag is a Flex tag which embeds files in a swf instead of loading them. There are lots of types that you can embed, like .flv, .jpg and others, and as mimeType application/octet-stream the file will be embedded as ByteArray. The embed tag creates a class for the embedded file, here I’m using a class named “Filter”.

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

In the constructor, let’s create an instance of our embedded file as ByteArray. The ByteArray is the Shader constructor’s parameter, so we’ll also create the shader instance, setting the filter to “ByteArray” as the parameter of the constructor. Since we’re extending the ShaderFilter, we don’t need to create an instance of the ShaderFilter. This class is already ShaderFilter extended, so all we need to do is set the shader parameter of our ShaderFilter class as the shader instance.

public function PixelateFilter():void
{
	var filter:ByteArray=new Filter() as ByteArray; //The embedded file as ByteArray
	var shader:Shader=new Shader(filter); //The instance of Shader
	this.shader=shader; //setting the parameter shader of our class
}

Now we create a new parameter for our class, the parameter “dimension”. This parameter will affect the “parameter int dimension” created in the pixelbender. The setter function will alter the value, and the getter function will just get the current value. The shader data values can be accessed by “instance.data.value”, the values are arrays. If we had a parameter “parameter int2 position;” in the filter for example, we would access it by “instance.data.position[0]” and “instance.data.position[1]” respectively.

public function set dimension(value:Number):void
{
	shader.data.dimension.value[0]=value;
}

public function get dimension():Number
{
	return shader.data.dimension.value[0];
}

After all that, just close the package and the class.

}
}

Now the class for this filter is created, save the .as file with the name “PixelateFilter.as” (the same name as the class) in the pixelbender folder inside your classpath (same name as your package, and where you’ve also created the pbj folder).


Step 7: Test the New Filter

First step, create a new .fla AS3 document, save it anywhere you want, for example c:/mycustomfilter.

Define a class for this .fla document. Open the properties panel of the .fla document from the window > properties, in the box “Class” type “Main”, and create a new actionscript file.

Copy any image to the same folder of the .fla document, for example I’ve used one of the sample images from the Pixel Bender examples; YellowFlowers.png, which can be found with the source files.

If you don’t have the TweenLite class yet, please download it at http://blog.greensock.com/tweenliteas3/, and unpack the contents of gs folder inside the gs folder in your classpath.

Create a new .as document.

Include the necessary classes to our classpath:

package{
	import flash.display.Sprite;
	import flash.display.Bitmap;
	import pixelbender.PixelateFilter; //Our custom filter
	import gs.TweenLite; //the best Tweening class

Create the Main class extending the Sprite class:

public class Main extends Sprite{

Embed the image for testing, the mimeType is “image/png”, so we’re embedding as image not ByteArray. Name its class “Img”. Additionally, we type a variable named “filter” of the type PixelateFilter, so we can use it in any function later on.

[Embed(source="YellowFlowers.png",mimeType="image/png")] private var Img:Class;
private var filter:PixelateFilter;

In the constructor, we start creating our image, which will be affected by the filter, then add the image child to the stage. Then create instance of PixelateFilter. We’ve created the variable before, so we don’t need to type again. Set the filter dimension to 100, so we can see the effect better, also add the filter to the filterlist of our Main class.

Then using the TweenLite class we animate the filter parameter. The dimension parameter will be animated from 100 to 1. While the animation is being updated, the function “tweenLiteUpdate” is executed, and when it’s finished animating the “newTween” function will be executed.

public function Main():void{
	var image:Bitmap=new Img() as Bitmap;
	addChild(image);
	filter=new PixelateFilter();
	filter.dimension=100;
	this.filters=[filter];
	TweenLite.to(filter,3,{dimension:1,onUpdate:tweenLiteUpdate,onComplete:newTween});
}

While TweenLite is being updated, the tweenLiteUpdate is executed and updates the filter of our Main class. Without this method we wouldn’t see the TweenLite updating the filter.

private function tweenLiteUpdate():void{
	this.filters=[filter];
}

When the first Tweening animation completes, it will run the newTween function. The first line of this function will check if the filter dimension value is 1. If so, it will set the dim variable to 100, else it’ll set the variable to 1. This is the same with if and else, or switch. The second line will start the Tweening animation of the filter again.

private function newTween():void{
	var dim:Number=(filter.dimension==1)?100:1;
	TweenLite.to(filter,3,{dimension:dim,onUpdate:tweenLiteUpdate,onComplete:newTween});
}

Now just close the package and the class with double “}”.

}
}

Save your file as “Main.as” in the same folder of your .fla file, and if all files and folder are OK, you can test your file. The animation will start pixelated, changing to the normal image, and will loop continuously.


Conclusion

I hope you liked this, and I hope it will be very useful. In Adobe Exchange there are a lot of other filters you can download, some of them are free or open source. I’ve also put some other .pbj and classes with the source for studying. For example, SpherizeFilter.as: http://cavallari.freehostia.com/spherize/, animates by the position of the mouse.

Add Comment

Discussion 21 Comments

  1. Easy my friend, awesome pixel effect and thanks for the tut.

  2. Dudefox says:

    Just what i was waiting for, thanks a lot André, i tryed some pb tutorials here, but this was the best i found, also i learned how to use a Tween engine with the parameters of the pb filter.

    Just a question, this kind of solution you created to use a Tween engine with the parameters works with another kind of filter? i mean, with have arrays as parameters?

    • André says:
      Author

      Yes, you can create parameters (functions getter and setter) to work with Tween engines in other filters, any kind of class works too if the parameters are public.

  3. jink says:

    Dario Gutierrez your kind words of wisdom are a great asset to this site
    thank you for your visit, and thank you for the tutorial.

  4. TwoFace says:

    Hello Andre!
    Thanks for this good article, clear and simple :)

  5. Diego SA says:

    Oh my god, this is a well-wanted effect I’ve always wanted to do! Something like Super Nintendo’s Final Fantasy effect when entering in the battle screen.
    Awesome! Thanks a lot!

  6. André says:
    Author

    http://www.adobe.com/cfusion/exchange/index.cfm?event=productHome&exc=26&loc=en_us

    More and more filters from adobe exchange that can be downloaded and used the same way. (just read if it´s compatible to flash player)

  7. Erick says:

    Good Effect, but you can do it with Jumpeye Components.

  8. JNaves says:

    AMAZING!!!

    just what i was waiting for, i already used jumpeye components, but cant be done half of what it does with pixelbender, and here we have a free solution against the payd solution of jumpeye

  9. Giallo says:

    very cool effect

  10. Dimitree says:

    Kind of, the same effect without Pixel Bender in AS2
    http://www.senocular.com/flash/source.php?id=0.189

    • André says:
      Author

      Yes, all the pixelbender filters can be done with BitmapData class, but it´s more difficult and havyer. But the porpouse of this tutorial is to teach how to create and use a pixelbender filter for flash, not just how to use the pixelate filter…

      And thanks for the solution for AS2, i think it will be usefull for some people here

  11. André says:
    Author

    Some more effects i´ve tryed…

    http://cavallari.freehostia.com/testswf/?swf=spherefilter.swf

    http://cavallari.freehostia.com/testswf/?swf=smudgefilter.swf (click image to see)

    AND, this link is where you can test online .pbj files wich you download… it also creates the class automatically, to load a class just right click and click “Carregar filtro”, when a filter is loaded you can right click again and select “salvar classe” to create a custom.as file for this .pbj, the menuitem “Carregar imagem” you can load another image if you want

  12. josé carlos Neves says:

    Thank you for this info and files. This open new doors to a sensor project I’m working on.

  13. grayger says:

    Thanks for nice tutorial.

Add a Comment

To add a code snippet to your comment, please wrap your code like so: <pre name="code" class="html">YOUR CODE</pre>. You can replace the class name with "js," "css," "sql," or "php." If there are any "<" or ">" within your code, please search and replace them with: &lt; and &gt; respectively.