Interactive Pixel Bender wave

I finally got around to play with Pixel Bender.

I was particularly interested in how to hook up the shader parameters to be interactive.
I ended up with this fairly basic attenuated wave-disturbance thing, and now I shudder to think how much more involved it would be to do a similar effect by other means (DisplacementMapFilter, ConvolutionFilter, or what have you), not to mention the performance-difference. Talk about getting spoiled, FAST.

Play around with the SWF for a bit, and then it’s time to see the other goods below. (By the way, the scenic shot was taken at a recent family trip to Mammoth Lakes… ;) )

This is the .pbk shader file that goes into the Pixel Bender Toolkit, and is eventually exported as a .pbj file usable within Flash:

<languageversion : 1.0;>
 
kernel Disturbance
< namespace : "com.etoth";
    vendor : "edvardtoth.com";
    version : 1;
    description : "Attenuated wave disturbance";
>
{
    parameter float ticker
    < minValue:0.0;
        maxValue:1.0;
        defaultValue:0.0;
    >;
 
    parameter float amplitude
    < minValue:0.0;
        maxValue:100.0;
        defaultValue:40.0;
    >;
 
    parameter float frequency
    < minValue:0.0;
        maxValue:100.00;
        defaultValue:19.0;
    >;
 
    parameter float radius
    < minValue:0.0;
        maxValue:300.0;
        defaultValue:200.00;
    >;
 
    parameter float xPos
    < minValue:0.0;
        maxValue:600.0;
        defaultValue:300.00;
    >;
 
    parameter float yPos
    < minValue:0.0;
        maxValue:600.0;
        defaultValue:300.00;
    >;
 
    input image4 src;
    output pixel4 dst;
 
    void evaluatePixel()
    {
       float2 coords = outCoord();
 
        // interestingly this is noticeably faster than (pow((xPos-coords.x),2.0)
        float dist = sqrt ((xPos-coords.x) * (xPos-coords.x) + (yPos-coords.y) * (yPos-coords.y));
 
        float ampSlice = amplitude / radius;
        float ampModifier = radius - dist;
 
        if (ampModifier < 0.0)
        {ampModifier = 0.0;}
        if (ampModifier > radius)
        {ampModifier = radius;}
 
        coords.y += sin( (coords.y-ticker ) * frequency ) * (ampModifier * ampSlice); 
 
        dst = sampleNearest(src, coords);
       }
}
</languageversion>

…and this is the ActionScript file to bring it all together. (Of course the example’s FLA contains a few additional elements as well (e.g. the standard Flash component sliders), but they are so trivial that they aren’t worth getting distracted about.)

// Interactive Pixel Bender wave example (c) edvardtoth.com
 
package 
{
	import flash.display.*;
	import flash.events.*;
	import Stats;
 
	[SWF(width='570', height='570', framerate='60')]
 
	public class Disturbance extends MovieClip
	{
		// ===== embed shader here
		[Embed (source = "disturbance.pbj", mimeType = "application/octet-stream")]
		private var shaderObj:Class;
		// =====
 
		private var shader:Shader;
		private var shaderImage:ShaderImage;
 
		private var displayWidth:Number;
		private var displayHeight:Number;
 
		private var ticker:Number = 0;
 
		public function Disturbance()
		{
			if ( stage != null )
			{
				stage.scaleMode = StageScaleMode.NO_SCALE;
				stage.align = StageAlign.TOP_LEFT;
 
				displayWidth = stage.stageWidth;
				displayHeight = stage.stageHeight;
			}	
 
			// the performance-meter
			var stats:Stats = new Stats();
			addChild (stats);
 
			// this is the image in the Library
			shaderImage = new ShaderImage(0,0);
 
			// instantiate the embedded shader
			shader = new Shader(new shaderObj());
 
			// specify the image as the input-image for the shader
			shader.data.src.input = shaderImage;
 
			addEventListener (Event.ENTER_FRAME, updateFrame, false, 0, true);
		}
 
		private function updateFrame (event:Event):void
		{
			// assign values to the shader parameters based on the state of the sliders, the position of the mouse-pointer, etc.
			ticker += (speedSlider.value * 0.005);
 
			shader.data.ticker.value = [ticker];
			shader.data.xPos.value = [mouseX];
			shader.data.yPos.value = [mouseY];
			shader.data.radius.value = [radiusSlider.value];
			shader.data.amplitude.value = [amplitudeSlider.value];
 
			// draw and fill with image + shader
			graphics.clear();
			graphics.beginShaderFill (shader);
			graphics.drawRect (0, 0, displayWidth, displayHeight);
			graphics.endFill();
		}
	}
}

There are no comments yet. Be the first and leave a response!

Leave a Reply

Headway Themes — The Drag & Drop WordPress Theme