Apple-like reflection using Pixel Bender

pixelbender.jpg
Update: Fixed a minor bug when dealing with transparent sources.

Everyone loves pixel bender and everyone loves those apple-like reflections. So why not combine them? That's why we've gone ahead and created a very simple pixel bender filter for creating just this effect, even on video (and it looks especially good on video).

Source code and download after the jump.

Here is the pbk source code for the filter:

  1. kernel ReflectionFilter
  2. <  namespace : "com.squidder";
  3.    vendor : "Jon Reiling / Squidder.com";
  4.    version : 1;
  5.    description : "Filter for creating an apple-like reflection.";
  6. >
  7. {
  8.    input image4 src;
  9.    output pixel4 dst;
  10.    
  11.    parameter float imageheight
  12.    <
  13.       minValue: 0.0;
  14.       maxValue : 1000.0;
  15.       defaultValue : 300.0;
  16.    
  17.    >;
  18.       
  19.    parameter float fadeheight
  20.    <
  21.       minValue : 0.0;
  22.       maxValue: 1000.0;
  23.       defaultValue: 100.0;
  24.    >;
  25.    
  26.    parameter float fadealpha
  27.    <
  28.       minValue : 0.0;
  29.       maxValue : 1.0;
  30.       defaultValue : 0.5;
  31.    >;
  32.    void
  33.    evaluatePixel()
  34.    {
  35.       float2 coord = outCoord();
  36.       
  37.       if ( coord[ 1 ] < imageheight ) {
  38.          dst = sampleNearest(src, coord );
  39.       } else {
  40.          
  41.          float alpha = 1.0 - ( coord[ 1 ] - imageheight ) / fadeheight;
  42.          coord[ 1 ] = imageheight - ( coord[ 1 ] - imageheight );
  43.          
  44.          dst = sampleNearest( src, coord );
  45.          
  46.          alpha *= fadealpha;
  47.          dst.a *= alpha;
  48.          dst.r *= alpha;
  49.          dst.b *= alpha;
  50.          dst.g *= alpha;
  51.       }
  52.       
  53.       
  54.    }
  55. }

As you may be able to tell, there are two unfortunate aspects to this filter. The first is that you have to manually pass in the height of the image. I have yet to figure out how to get the overall height of the image being passed in -- if anyone knows, please hit us up in the comments!

Secondly, if you try this out, you'll see that the reflection actually overwrites the bottom part of the source image. This is because, as far as I can tell, you can't add height to your output. So to counter this, you'll need to artificially add height to your target clip. You can do this easily by adding a transparent shape the height of your reflection. Again, if you have any notions on this, please drop a comment.

Finally, here is the flash code to read in and apply the filter:

  1. var reflectionHeight : int = 50;
  2. var urlLoader : URLLoader = new URLLoader();
  3. urlLoader.dataFormat = URLLoaderDataFormat.BINARY;
  4. urlLoader.addEventListener( Event.COMPLETE , _applyFilter );
  5. urlLoader.load( new URLRequest( "ReflectionFilter.pbj" ) );
  6. function _applyFilter( event : Event ) : void {
  7.    var shader:Shader = new Shader( URLLoader( event.target ).data );
  8.    
  9.    shader.data.imageheight.value = [ target.height - reflectionHeight ];
  10.    shader.data.fadeheight.value = [ reflectionHeight ];
  11.    shader.data.fadealpha.value = [ 0.4 ];
  12.       
  13.    var filter : ShaderFilter = new ShaderFilter( shader );
  14.    target.filters = [ filter ];
  15. }

Leave a comment

AS3 and Flash you'll lose your ink over.