Still Dre

Вот такой незамысловатый эффект получился при использовании pixel bender'а.

На самом деле такой эффект я впервые увидел у Andre Michelle, но сорсов он не выложил. В те времена я написал его на восьмом плеере (AS2), но с выходом новых возможностей решил повторить эксперимент. Обошлось не без приключений, зато код получился без граблей, которые приходилось строить в восьмерке.

Смотреть тут. (5 мб)


Пишем фильтр


Переменные:
src — первая входная картинка
src2 — вторая входная картинка
white — белый цвет
black — черный цвет
min — значение по которому определяем ставить белый или черный цвет в выходящее изображение

Логика фильтра такова:
— (a1) берем цвет первого пикселя первой картинки
— (a2) берем цвет первого пикселя второй картинки
— (ss) вычитаем из a1 a2
— если разница каждого цвета ss больше min тогда в выходящей картинке на месте первого пикселя будет белый цвет иначе черный
  1. <languageVersion : 1.0;>
  2.  
  3. kernel NewFilter
  4. namespace : "Your Namespace";
  5.   vendor : "Your Vendor";
  6.   version : 1;
  7.   description : "your description";
  8. >
  9. {
  10.   input image4 src;
  11.   input image4 src2;
  12.   output pixel4 dst;
  13.   
  14.   const pixel4 white = float4(1.0, 1.0, 1.0, 1.0);
  15.   const pixel4 black = float4(0.0, 0.0, 0.0, 0.0);
  16.   const float min = 0.05;
  17.  
  18.   void
  19.   evaluatePixel()
  20.   {
  21.     pixel4 a1 = sampleNearest(src, outCoord());
  22.     pixel4 a2 = sampleNearest(src2, outCoord());
  23.     
  24.     pixel4 ss = a1 - a2;
  25.     
  26.     dst = (ss.r>min && ss.g>min && ss.b>min) ? white : black;
  27.   }
  28. }
* This source code was highlighted with Source Code Highlighter.


Пишем программу


Чтение кода не должен вызвать затруднений, только поясню некоторые вещи.

bmp1 — отпечаток картинки видео самого нового кадра
bmp2 — отпечаток bmp1, то есть предыдущий кадр от самого нового
bmp3 — результирующая картинка после применения фильтра PixelBender'а
cmf — фильтр который вычитает из всех пикселей картинки альфу по 10
out — картинка которую мы видим, на нее каждый кадр накладывается bmp3, а также фильтр cmf и blur
  1. package {
  2.   
  3.   import flash.display.Bitmap;
  4.   import flash.display.BitmapData;
  5.   import flash.display.Shader;
  6.   import flash.display.ShaderJob;
  7.   import flash.display.Sprite;
  8.   import flash.events.Event;
  9.   import flash.filters.BlurFilter;
  10.   import flash.filters.ColorMatrixFilter;
  11.   import flash.geom.Point;
  12.   import flash.media.Video;
  13.   import flash.net.NetConnection;
  14.   import flash.net.NetStream;
  15.   import flash.utils.ByteArray;
  16.   
  17.   [SWF(width=376, height=160, backgroundColor=0x0)]
  18.   
  19.   public class SubstractTv extends Sprite {
  20.     
  21.     [Embed(source="../assets/kutu.pbj", mimeType="application/octet-stream")]
  22.     private var pbj:Class;
  23.     
  24.     private var wid:uint = stage.stageWidth;
  25.     private var hei:uint = stage.stageHeight;
  26.     
  27.     private var video:Video;
  28.     private var nc:NetConnection;
  29.     private var ns:NetStream;
  30.     
  31.     private var bmp1:BitmapData;
  32.     private var bmp2:BitmapData;
  33.     private var bmp3:BitmapData;
  34.     private var out:BitmapData;
  35.     private var bmp:Bitmap;
  36.     
  37.     private var shader:Shader;
  38.     private var shaderJob:ShaderJob;
  39.     
  40.     private var blur:BlurFilter;
  41.     private var cmf:ColorMatrixFilter;
  42.     
  43.     public function SubstractTv() {
  44.       nc = new NetConnection();
  45.       nc.connect(null);
  46.       ns = new NetStream(nc);
  47.       ns.client = new Object();
  48.       ns.play("video.f4v");
  49.       
  50.       video = new Video(wid, hei);
  51.       video.attachNetStream(ns);
  52.       
  53.       bmp1 = new BitmapData(wid, hei, true);
  54.       bmp2 = bmp1.clone();
  55.       bmp3 = bmp1.clone();
  56.       out = bmp1.clone();
  57.       bmp = new Bitmap(out, "auto", true);
  58.       addChild(bmp);
  59.       
  60.       shader = new Shader(new pbj() as ByteArray);
  61.       shader.data.src.input = bmp1;
  62.       shader.data.src2.input = bmp2;
  63.       createShaderJob();
  64.       
  65.       addEventListener(Event.ENTER_FRAME, onEnterFrame);
  66.       
  67.       blur = new BlurFilter(3, 3, 3);
  68.       cmf = new ColorMatrixFilter([  1, 0, 0, 0, 0,
  69.                       0, 1, 0, 0, 0,
  70.                       0, 0, 1, 0, 0,
  71.                       0, 0, 0, 1, -10]);
  72.     }
  73.     
  74.     private function onEnterFrame(e:Event):void {
  75.       if (shaderJob.progress != 1) return;
  76.       
  77.       bmp2.draw(bmp1);
  78.       try {
  79.         bmp1.draw(video);
  80.       } catch(e:Error) {}
  81.       
  82.       createShaderJob();
  83.       
  84.       out.applyFilter(out, out.rect, new Point(), blur);
  85.       out.applyFilter(out, out.rect, new Point(), cmf);
  86.       out.draw(bmp3);
  87.     }
  88.     
  89.     private function createShaderJob():void {
  90.       shaderJob = new ShaderJob(shader, bmp3, wid, hei);
  91.       shaderJob.start();
  92.     }
  93.     
  94.   }
  95. }
* This source code was highlighted with Source Code Highlighter.