Static Distortion Effect

Static Distortion EffectI am sure you have seen some games or movies that display an image that has static distortions applied to it. It kind of gives a visual representation of the static that you would get on a radio which has not been properly tuned. Some effects use this to illustrate teleporting, only they distort more in the y-direction than in the x. Once again this is from a tutorial over at tutsplus.com. Written by the same guy (Cadin Batrack) that did the CRT effect using RGB shifting. This particular demo has quick buttons to show the distortion effect in 3 stages, as well as sliders for custom configuration. There is also a hover and click effect on the yoda. The yoda will grow on rolling in with a large distortion and shrink when rolling out with a medium distortion. There are also sounds attached to both those events, created with bfxr. However they are muted by default. Nobody likes sharp noises coming through their speakers unexpectedly. Enable them by toggling the setting.

The algorithm

  • Generate / use a distortion map (The tutorial used an image created in photoshop. I wrote a generator, included below)
    • Make sure it is grayscale
    • Make sure it is horizontal lines of varying shades
  • Use the distortion map as the base for the displacement map filter
  • Shift the displacement map on the y-axis to achieve the animation
  • Change the scaleX parameter to increase or decrease the horizontal scaling, e.g. the severity of the displacement on the x-axis

For the rollover effects…

  • On rollover
    • enlarge the image
    • play a sound
    • have high distortion for the length of the sound
    • reset back to the idle state (low distortion)
  • On rollout
    • reset the image scaling
    • have medium distortion for some time
    • reset back to idle state after the time has elapsed

The code

package net.avdw.fx
{
	import flash.display.Bitmap;
	import flash.display.BitmapDataChannel;
	import flash.display.DisplayObject;
	import flash.events.Event;
	import flash.geom.Point;
	import flash.filters.DisplacementMapFilter;
	import flash.filters.DisplacementMapFilterMode;
	import net.avdw.generate.makeStaticDisplacementMap;
	import net.avdw.number.SeededRNG;

	public class StaticDistortionFx
	{
		public var minScaleX:int = 0;
		public var maxScaleX:int = 2;

		private var displayObj:DisplayObject;
		private var displacementFilter:DisplacementMapFilter;

		public function StaticDistortionFx(displayObj:DisplayObject)
		{
			this.displayObj = displayObj;
			displacementFilter = new DisplacementMapFilter(makeStaticDisplacementMap(displayObj.width, displayObj.height * 2), new Point(), BitmapDataChannel.RED, BitmapDataChannel.RED, 0, 1, DisplacementMapFilterMode.COLOR, 0, 0);
			displayObj.addEventListener(Event.ENTER_FRAME, animate);
		}

		public function low():void {
			minScaleX = 0;
			maxScaleX = 2;
		}

		public function medium():void {
			minScaleX = 2;
			maxScaleX = 6;
		}

		public function high():void {
			minScaleX = 12;
			maxScaleX = 25;
		}

		private function animate(e:Event):void
		{
			displacementFilter.mapPoint = new Point(0, -Math.random() * displacementFilter.mapBitmap.height / 2);
			displacementFilter.scaleX = SeededRNG.float(minScaleX, maxScaleX);

			displayObj.filters = [displacementFilter];
		}
	}

}

package net.avdw.generate
{
	import flash.display.BitmapData;
	import flash.display.BitmapDataChannel;
	import flash.display.BlendMode;
	import net.avdw.color.combineARGB;
	import net.avdw.graphics.drawFastLine;

	public function makeStaticDisplacementMap(width:int, height:int):BitmapData
	{
		var bmpData:BitmapData = new BitmapData(width, height, false, 0x888888);
		var noise:BitmapData = bmpData.clone();
		noise.noise(Math.random() * int.MAX_VALUE, 0, 255, BitmapDataChannel.RED, true);

		var numLines:int = width * 10;
		for (var i:int = 0; i < numLines; i++)
		{
			var x:int = Math.random() * width;
			var y:int = Math.random() * height;
			var length:int = Math.random() * width * .2;
			drawFastLine(bmpData, x, y, x + length, y, combineARGB(1, Math.random()));
		}
		bmpData.draw(noise, null, null, BlendMode.OVERLAY);
		return bmpData;
	}

}