Recently I wrote about my distortion effect. Believe me, I experimented with it a lot. And it was damn slow on big bitmaps. But here’s a funny way to do it through native jpeg decoding. And it runs smooth on relatively big bitmaps. The guy messes up with jpeg data in ByteArray many times in a row loading it over and over again. Letting Flash native jpeg decoder do the work for him. This is is a great example of creative thinking!
Tag Archive for 'Effect'
You should have seen the effect of a TV signal glitch on text at my last va.lent.in site. People keep asking me how it was done over and over again. I won’t post complete source code here because it’s kind of messy. I’ll just give basic ideas, because this effect is rather simple.
Basically, you just displace red, green and blue channels of a bitmap separately and apply the same actions to resulting bitmap. Adding some kind of wave function looks cool too, but is damn slow. So, what I decided to do is to distort a small rectangle of target image over a couple of frames. First, I used only BitmapDatas but later tried to test PixelBender performance. Honestly, I don’t remember any miraculous speed gain, so there might be none at all. But anyway, here’s the code of this filter. Basically, it’s just 3 lines of code:
void evaluatePixel()
{
float2 outCoords = outCoord();
dst.r = sample( src, float2(outCoords.x + rOffset, outCoords.y) ).r;
dst.g = sample( src, float2(outCoords.x + gOffset, outCoords.y) ).g;
dst.b = sample( src, float2(outCoords.x + bOffset, outCoords.y) ).b;
}
Full source code you can download here: RGBDisplacement.pbk
This shader takes 3 displacement values as parameters. Now back to AS3. Once again, this code is result of numerous experiments, changes and fixes during development. Please don’t use it as is (actually it doesn’t work alone) but rather try to understand the basic idea.
[Embed(source="filters/RGBDisplacement.pbj", mimeType="application/octet-stream")]
private var ShaderDistort:Class;
public function Distortion( source: Sprite, minAmp: int = 10, maxAmp: int = 40, len: int = 30, minRand: Number = .05, ampRand: Number = .8, maxH: int = 20 )
{ ... }
Shader class and constructor params.
public function start( interval: int = -1 ): void
{
if ( bitmapData.width != Math.ceil(_source.width) || bitmapData.height != Math.ceil(_source.height) )
{
initBitmaps();
}
seed = 0;
_source.alpha = 0;
visible = true;
this.interval = interval;
// set random displacement
bmpY = Math.random()*(bitmapData.height-bitmapDataDistorted.height);
bitmapData.fillRect( bitmapData.rect, 0x000000 );
bitmapData.draw( _source );
business();
}
This method resets distortion params, sets bmpY to a random starting y position and invokes business() which does the job.
private function business( evt: Event = null ): void
{
// stop if played for certain number of frames
if (interval == 0)
{
stop();
return;
}
interval--;
// randomly move the effect up or down
bmpY += int((10 - Math.random()*20) * Math.sqrt(interval));
bmpY < 0 ? bmpY = 0 : true;
bmpY > bitmapData.height-bitmapDataDistorted.height ? bmpY = bitmapData.height-bitmapDataDistorted.height : true;
var bmpd: BitmapData = new BitmapData( bitmapDataDistorted.width, bitmapDataDistorted.height, false, 0x000000 );
bmpd.copyPixels( bitmapData, new Rectangle(0, bmpY, bitmapDataDistorted.width, bitmapDataDistorted.height ), new Point(0, 0) );
filter.data.src.input = bmpd;
seed++;
seed >= len ? seed = 0: true;
// wave function
var v: Number = 3.14159265 / len * seed;
// approximation of sin()
var sin: Number = 1.27323954 * v - 0.405284735 * v * v;
var amp: Number = minAmp + sin * difAmp;
var i: int = 0;
var disp: Array = [];
var pi2: Number = 6.28318531;
for (i; i<3; i++)
{
if ( seeds[i] >= 1 )
{
seeds[i]--;
dSeeds[i] = Math.random() * ampRand + minRand;
}
seeds[i] += dSeeds[i];
v = seeds[i] * pi2;
// approximation of sin()
if (v > 3.14159265) v -= 6.28318531;
if (v < 0)
sin = 1.27323954 * v + .405284735 * v * v;
else
sin = 1.27323954 * v - 0.405284735 * v * v;
disp[i] = sin * amp;
}
// set displacements for shader
filter.data.rOffset.value = [disp[0]];
filter.data.gOffset.value = [disp[1]];
filter.data.bOffset.value = [disp[2]];
// invoke shader
var job: ShaderJob = new ShaderJob(filter, bitmapDataDistorted);
job.addEventListener(ShaderEvent.COMPLETE, redraw);
job.start();
}
And finally redraw() method
private function redraw( evt: Event = null ): void
{
bitmapData.copyPixels( bitmapDataDistorted, bitmapDataDistorted.rect, new Point(0, bmpY) );
id = setTimeout(business, 40);
}
That’s it. You can refer to my post about using Maple for more math.
The source of this class is here: Distortion.as
Sometimes it’s good to test some math model before coding it into ActionScript or any other language, draw some cool graphs and play with parameters. Of course you could write a simple flash application to draw graphs for you but why waste time if there are a lot of math software around? In school we used Maple, so from time to time I use it to check stuff before actually coding it. I have to say that I’m not good at it but my knowledge is enough for my own tasks.
Well, right now I need to code a pseudo random movement. I need some kind of a periodic pattern with bursts and decaying.
So, I opened Maple and set several constants I had in mind.
minAmp — minimal value of global amplitude,
maxAmp — maximum value,
minLen — minimal wave length,
deltaLen — minLen + deltaLen = maxLen — maximum wave length,
speed — wave speed (rendered useless).
After that I wrote functions for amplitude.
In the example I used constant wave length, didn’t have time to play more with it. Here everything is simple. We have some x value from which wave length and amplitude is counted. Both are periodical.
Here’s the graph.
Now we can add one more sin which will be limited by this amplitude.
We are getting a periodical movement but it’s too boring. Here goes the magic.
This function generates all the randomness. Simply put, there’s some seed which grows from 0 to 1 (actually a bit more) by dseed and after it reaches 1 it goes back to almost zero and dseed (delta seed — seed change speed) changes to some other value controlled by minRand and ampRand. At the end we get new value in the last line.
That’s how we get such a jerky rhythm, and because of dseed the movement can be be fast and slow. And everything is limited by periodic amplitude.
Let’s check the result.
This is just what I wanted. If you play with parameters a bit ou can get very interesting results.
Here’s the example. You shouldn’t stare it for a long time q: It uses much CPU so I recommend you to close the tab after you finish reading.







Recent Comments