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(); } } }
