So, recently I discovered Pixel Bender, and I realized that it might be nice to share what I've learned with other people. So now, I present:
How to make cool filters and stuff for FlashRequirements:-FlashDevelop + Flex SDK (or Flex, but I'll be using FlashDevelop)
-Flash 10 debugger
-Some AS3 programming knowledge and FlashDevelop experience
-Elbows
IntroductionThis tutorial is an attempt to show people how to use Adobe Pixel Bender to make visual filters that can be integrated into FlashDevelop projects. It's also my first tutorial, so I hope it's not too terrible.
Why do Pixel Blender filters matter, you ask? Basically, when used right they're a great way to give your game cool visual polish without having to make any of that pesky and time-consuming "art". So they're quite handy for rapid game development (or just being lazy
).
This tutorial is going to be broken up into three parts. The first part will explain how to get a Pixel Bender filter working in a FlashDevelop project, the second part will explain how to create your own filter, and the third part will explain some filters that I've already made.
Also, if you happen to make any of your own .pbk files and feel like you're in a sharing mood, it'd be totally awesome if you could post the source of them in this thread.
Part 1First things first, make sure you actually have Pixel Bender. While you might be able to make the files with Notepad or something, the Pixel Bender toolkit lets you test and debug your filters while you make them.
Download Pixel Bender here:
http://labs.adobe.com/downloads/pixelbender.htmlAfter you download and install it, run the program and you should be greeted with a screen that looks like this (minus the green dots):
This interface is extremely simple, but I added big circles with numbers on things because that's the type of thing that a tutorial is supposed to do. Here's what those circles represent!
1) The image view - Images are loaded onto this. After you do your filter-making magic, the result is then displayed here.
2) The "Filter Parameter UI" - This part of the screen has two purposes. First, it's a debugger, although not the most helpful one. Once you actually get your code running, it's the area that lets you tweak parameters that you define.
3) The source editor - This is where you write your filters. Unfortunately, it's a pretty terrible editor in comparison to FlashDevelop. Also unfortunately, I'm too lazy to edit my files elsewhere and import them into Pixel Bender.
Since our goal right now is to learn the system and not the code, just go to File>Open Filter and select "pixelate.pbk". For testing, we're also going to need to open an image to see its effects, so choose File>Load Image 1 and choose "YellowFlowers.png". Test the filter out by pressing the Run button at the bottom of the screen. The Filter Parameter UI should have magically transformed into a slider thingy. Slide it around, and become amazed at an effect you've already seen in the background of Messhof's game Punishment!
Gee golly jeepers! :ONow let's get this fantastic thing working in FlashDevelop. First, I'll do it with a "blank" example, and then I'll show you how to incorporate these things into Flixel (since I will never get around to finishing my engine
).
First, create a new blank AS3 project in FlashDevelop.
[IMPORTANT]Make sure that you target Flash Player 10, otherwise the filter will not work and everything you know and love will die forever![/IMPORTANT]Add a new class, name it Main.as, and set the file to Always Compile. Now, copy+paste the following code (don't worry, I'll explain what it all means in a bit):
package
{
import flash.display.Shader;
import flash.display.Sprite;
import flash.events.Event;
import flash.filters.ShaderFilter;
public class Main extends Sprite
{
[Embed(source = "pixelate.pbj", mimeType = "application/octet-stream")]
private var Pixelate:Class;
private var myShaderFilter:ShaderFilter;
private var pixelAmount:int = 1;
private var increase:Boolean = true;
public function Main()
{
myShaderFilter = new ShaderFilter(new Shader(new Pixelate()));
this.filters = [myShaderFilter];
addEventListener(Event.ENTER_FRAME, step);
}
private function step(event:Event):void
{
graphics.clear()
graphics.beginFill(0x000000);
graphics.drawCircle(200, 200, 200);
if (increase)
{
pixelAmount++;
if (pixelAmount >= 100)
{
pixelAmount = 100;
increase = false;
}
}
else
{
pixelAmount--;
if (pixelAmount <= 1)
{
pixelAmount = 1;
increase = true;
}
}
myShaderFilter.shader.data.dimension.value = [pixelAmount];
this.filters = [myShaderFilter];
}
}
}
Before you compile and run it, go back to Pixel Bender, choose File>Export Filter for Flash Player, and save the file as "pixelate.pbj" in the same directory as your Main.as file. Okay, now you can test it. If all goes well, you should see a black circle that goes from being normal to very pixelated, and then back to normal, and so on. If not, make sure that all your compiler settings are correct, you have the right files in the right places, and you copied and pasted the code exactly as is. If it still doesn't work, then maybe your computer hates you or something. I dunno.
Here's my project if yours is giving you trouble.
Yay! Now it's time to decipher what my code actually means! Huzzah!
Here's an important part:
[Embed(source = "pixelate.pbj", mimeType = "application/octet-stream")]
private var Pixelate:Class;
This embeds the object into the .swf as a class so that it can actually be used. The main difference here between this and a regular ol' embed thingy is the mimeType segment, which is essential for getting the .pbj file to work.
private var myShaderFilter:ShaderFilter;
private var pixelAmount:int = 1;
private var increase:Boolean = true;
myShaderFilter is a ShaderFilter object (surprise, surprise) that we will eventually add to the main sprite. pixelAmount and increase are variables that will help in changing the amount of pixelation.
myShaderFilter = new ShaderFilter(new Shader(new Pixelate()));
this.filters = [myShaderFilter];
addEventListener(Event.ENTER_FRAME, step);
In the first line, the ShaderFilter is created. The second line adds the filter to the main sprite. If you can't understand the third line, I suggest that you learn Actionscript 3.
graphics.clear()
graphics.beginFill(0x000000);
graphics.drawCircle(200, 200, 200);
This draws a black circle 400 pixels in diameter! Yay!
if (increase)
{
pixelAmount++;
if (pixelAmount >= 100)
{
pixelAmount = 100;
increase = false;
}
}
else
{
pixelAmount--;
if (pixelAmount <= 1)
{
pixelAmount = 1;
increase = true;
}
}
This part isn't important to understanding Pixel Bender, but I'll explain it anyways. Basically, it makes the pixelation amount go up by one pixel per frame until it reaches 100, at which point it starts decreasing by one pixel per frame back to one.
myShaderFilter.shader.data.dimension.value = [pixelAmount];
this.filters = [myShaderFilter];
Okay, this part is important. The first line sets the dimension parameter to the value pixelAmount. The second line updates the main sprite's filters array. Important things to note:
-To change the value of a parameter in a Pixel Bender file, you need to access it through myParameter.value, and not myParameter.
-The value has to be an array. You'll see why in part 2.
-Whenever the ShaderFilter is changed, you have to update the display objects affected by it.
So, yeah! You just got a Pixel Bender filter working! That's pretty cool!
Putting Pixel Bender filters in FlixelHey, let's apply one of these filters to the Flixel game Mode! First, make sure that you can get Flixel to work in FlashDevelop. I'm not gonna help you with that part. Next, open up FlxG.as. In the import statments, add:
import flash.display.Sprite;
import flash.display.Shader;
import flash.filters.ShaderFilter;
You'll also need to add these lines in somewhere:
static private var _shader:Shader;
static private var _screen:flash.display.Sprite;
static public function set screen(value:Sprite):void {
_screen = value;
}
static public function get shader():Shader {
return _shader;
}
static public function set shader(value:Shader):void {
_shader = value;
if (_shader != null && _screen != null) _screen.filters = [new ShaderFilter(_shader)];
else if (_screen != null)_screen.filters = [];
}
static public function updateShader():void {
shader = shader;
}
Now open up FlxGame.as. Scroll down to line 511. There should be several lines talking about _buffer. After the line "addChild(_buffer);", add these two lines:
FlxG.screen = _buffer;
FlxG.updateShader();
Yippie! Now you have a shader filter that you can use in Flixel. Access/change the shader through the variable FlxG.shader. Whenever you change a variable within the shader, you will have to call FlxG.updateShader().
Let me know if this works for you or not. Also, I can explain what's going on in this later, but I need to be paying attention to my teacher right now. :/