Displacementmapfilter – Dynamischen Nebel erzeugen

Mai 20th, 2010 by admin

In diesem Displacementmapfilter Tutorial geht es um die Erzeugung von dynamischen Nebeleffekten. Hierzu erzeuge ich erst eine Nebelwand mittels einer Perlinschen Störung, in der ich zunächst die Dunklen bereiche transparent mache (je dunkler desto durchsichtiger) und anschließend deren Farbwerte durch Weiß ersetze. Das Ergebniss ist ein durchgehend weißes Bild, mit durchsichtigen Verläufen, wo sich zuvor dunkle Bereiche befanden.

FlashPlayer starten

Hier das Script:

 var fogData : BitmapData;
 var fog : Bitmap;
 var _w : int = 550;
 var _h : int = 400;
 
 var _perlinData : BitmapData ;
 var _dispFilter : DisplacementMapFilter ;
 
 var _perlinOff : Array = new Array;
 var _numOctaves : int = 3 ;
 
 var _baseX : int = 100 ;
 var _baseY : int = 100 ;
 var _strength : int = 50 ;
 
 
 createFogData() ;
 createFog() ;
 createDisplacement() ;
 addChild(fog);
 
 
 function createFogData() : void {
 
	fogData = new BitmapData( _w, _h ) ;
 	fogData.perlinNoise( _baseX, _baseY, _numOctaves, 10, true, true, 7, true, [new Point(0, 0) ] ) ;	
 }
 
 function createFog() : void {
 
	var rect : Rectangle = new Rectangle( 0, 0, _w, _h ) ;
	var old_bytes : ByteArray = fogData.getPixels( rect ) ;
	var new_bytes : ByteArray = new ByteArray();
 
	old_bytes.position = 0 ;
 
	for (var i:int = 0; i < old_bytes.length; i+=4) 
	{				
		new_bytes[i + 0] = 255 - old_bytes[i + 1] ; // alpha is negated R (R == G == B)
 
		new_bytes[i + 1] = 255 ; 
		new_bytes[i + 2] = 255 ;
		new_bytes[i + 3] = 255 ; // RGB = 0xffffff
	}
 
	fogData.setPixels( rect, new_bytes ) ;
	fog = new Bitmap( fogData ) ;
	fog.alpha = .5;
}
 
 function createDisplacement() : void {
 
		_perlinOff = new Array ;
		_perlinOff.push( new Point ) ;
		_perlinData = new BitmapData( _w , _h, false ) ;
		_dispFilter = new DisplacementMapFilter( _perlinData, new Point( ), BitmapDataChannel.RED, BitmapDataChannel.GREEN, _strength, _strength, "color" ) ;
 
		this.addEventListener( Event.ENTER_FRAME, perlinize );
}
 
 function perlinize( e:Event ) : void {
			_perlinOff[0].x++;
			_perlinOff[0].y++;
			_perlinData.perlinNoise( _baseX, _baseY, 1, 50, true, true, 7, false, _perlinOff ) ;
			fog.filters = [ _dispFilter ] ;
		}

Das Ganze funktioniert folgdender Maßen: Man lädt die Pixelwerte des Perlin-Bildes in ein Bytearray. Hier stehen immer vier bytes (8 Bits, also werte zwischen 0 und 255) für einen Kanal, ALPHA – RED – GREEN – BLUE, in dieser Reihenfolge. Da in der perlin() funktion der parameter Grayscale aktiviert ist, entsprechen die bytes 2-4 einander (R = G = B), somit ist jeder Pixel grau, weil kein Farbkanal den anderen überwiegt.
Ersetzt man nun das erste Byte ALPHA mit 255 (nicht transparent) durch 255 – R (je dunkler desto durchsichtiger), muss man nur noch die Übrigen bytes R G und B auf 255 (ergibt weiß) setzen und schon hat man die besagte Nebelwand.

Anschließend wird eine weitere, diesmal in einer ENTER_FRAME Schleife fortlaufend gemachte Perlinsche Störung in Kombination mit einem Displacementmapfilter dazu benutzt, der Nebelwand eine realistische, dynamische Bewegung zu geben.

Das Ergebniss ist schaurig schön, nicht wahr?

DisplacementMapFilter Tutorial Wellenbewegung

Dezember 13th, 2009 by admin

DisplacementMapFilter Tutorial Nummer eins: Der Effekt ist beinahe klassisch, man nehme eine fortlaufende perlinsche Störung und verwende sie als DisplacementMap für für einen DisplacementMapFilter. Diesen wendet man dann in einer EnterFrame Schleife auf ein Bild an, beispielsweise ein Foto:

FlashPlayer starten

Ein geradezu halluzinogener Effekt, doch schon eilt die Ernüchterung:

import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.BitmapDataChannel;
import flash.filters.DisplacementMapFilter;
import flash.display.DisplayObject;
 
import flash.events.MouseEvent;
import flash.events.Event;
 
var pic:DisplayObject = new luke_pic;
var bitdata :BitmapData = new BitmapData(pic.width + 30, pic.height + 30);
var displacement :DisplacementMapFilter;
var perlinCounter :uint = 0;
var displacementIntensity :uint = 50;
 
addChild(pic);
addEventListener(Event.ENTER_FRAME, wave);
 
function wave(e:Event) {
	perlinCounter += 6;
	bitdata.perlinNoise(200, 200, 1, 5, true, true, 3, false, [new Point(perlinCounter, perlinCounter)]);
	displacement = new DisplacementMapFilter(bitdata, new Point( -15, -15), BitmapDataChannel.GREEN, BitmapDataChannel.RED, displacementIntensity, displacementIntensity, "color");
	pic.filters = [displacement];
}

Hier werden sowohl das Perlinbild, wie auch der DisplacementmapFilter in jedem Frame aktualisiert. Das Perlinbild dient dem DisplacementMapFilter als DisplacementMap. Der DisplacementMapFilter nutzt die Farben aus der DisplacementMap als Grundlage, für die Verzerrungen im Bild. Diese Verzerrungen entstehen wiederum dadurch, dass anhand der Farbwerte aus der neue Dimensionen für die einzelnen Pixel errechnet werden, dass heißt sie vergrößern oder verkleinern sich und schieben die umliegenden Pixel einfach zur Seite.

Dazu muss man dem DisplacementMapFilter zunächst mitteilen, welche Farbe für verzerrungen auf der x-Achse und welche für solche auf der y-Achse genutzt werden sollen. In diesem Fall soll grün auf der x-achse und rot auf der y-achse verzerren, das sind die Parameter 3 und 4.

new DisplacementMapFilter(bitdata, new Point( -15, -15), BitmapDataChannel.GREEN, BitmapDataChannel.RED, displacementIntensity, displacementIntensity, "color")

Parameter 1 ist die DisplacementMap, aus der die Farbinformationen genommen werden, wie gesagt handelt es sich hier um ein bild, das mit der BitmapData.perlinNoise funktion generiert wurde. Hierzu gibt es Näheres in diesem Tutorial. Der darauffolgende Punkt mit den x und y = -15 besagt, wo die DisplacementMap auf dem pic liegt: Im grunde bedeutet das, dass das Perlinbild, 15 pixel über und 15 pixel links von dem Registrierungspunkt des Objekts angesetzt wird, dass gefiltert wird, also das pic.

new DisplacementMapFilter(bitdata, new Point( -15, -15), ...

Dann noch die Intensität, mit der verzerrt werden soll, auch jeweils auf den x und y achsen. Je höher dieser Wert, desto stärker die Verzerrung. Am Schluss des Funktionsaufrufes kann noch ein Modus übergeben werden, Color ist in der Regel der Beste, bei weiterem Interesse an den Modi, möchte ich auf die Adobe Docs verweisen.

Jetzt nochmal zum besseren Verständnis am Stück:
Der DisplacementMapFilter wird auf (-15|-15) relativ zum RegistrierungsPunkt des Bildes (0|0) gelegt. Jetzt liegt die DisplacementMap über dem Pic, es liegen also auch immer ein Farbiger Pixel aus dem PerlinBild (= die DisplacementMap) über jedem Pixel des Pics. Also beginnt der Filter damit, jeden Pixel im Bild, mit der Farbe des Pixels aus dem Perlinbild zu vergleichen. Ist die Farbe im PerlinBild knallrot, wird der Pixel auf der y-Achse gestreckt, alle Pixel über und unter ihm werden einfach zur Seite geschoben. Ist die Farbe dagegen braun und enthält folglich sowohl rot, als auch grün, wird der Pixel in dem zu filterenden Bild auf x und y gestreckt, in dem entsprechenden Verhältnis von rot und Grün in dem Braunton.

Neutral verhält sich der Filter zu der zu folgendem Grauton: 0×808080, also das grau, das exakt zwischen schwarz und weiß liegt. Und übrigens: der DisplacementMapFilter ist ein echter PerformanceKiller, wenn man es damit übertreibt.

Bleibt noch zu sagen, dass dieser Filter von allen der komplizierteste ist und man erst damit experimentiert, ehe man das Gefühl dafür bekommt. Einfach ein bisschen mit den Parametern zu spielen, ist auch ein guter Anfang. Anschließend lohnt es sich bestimmt, dieses Tutorial nochmals zu lesen. Und keine Sorge, es sind bereits weitere Tuts zu dem Thema in der Schmiede.