Im Beispiel „Animated Spinning Moon“ werden anhand eines animierten, sich drehenden Monds Techniken für die Verwendung von Bitmap-Objekten und Bitmap-Bilddaten (BitmapData-Objekten) demonstriert. Mithilfe eines zweidimensionalen Bilds der Mondoberfläche als Ausgangsmaterial wird die Animation eines sich drehenden, kugelförmigen Monds erzeugt. Es werden folgende Techniken veranschaulicht:
-
Laden externer Bilder und Zugreifen auf die Bildrohdaten
-
Erstellen eines Animationseffekts durch wiederholtes Kopieren von Pixeln aus unterschiedlichen Teilen eines Quellbilds
-
Erstellen eines Bitmapbilds durch Festlegen von Pixelwerten
Die Anwendungsdateien für dieses Beispiel finden Sie unter
www.adobe.com/go/learn_programmingAS3samples_flash_de
. Die Dateien der Anwendung „Animated Spinning Moon“ befinden sich im Ordner „Samples/SpinningMoon“. Die Anwendung umfasst die folgenden Dateien:
Datei
|
Beschreibung
|
SpinningMoon.mxml
oder
SpinningMoon.fla
|
Die Hauptanwendungsdatei in Flex (MXML) oder Flash (FLA).
|
com/example/programmingas3/moon/MoonSphere.as
|
Die Klasse mit den Funktionen zum Laden, Anzeigen und Animieren des Monds.
|
moonMap.png
|
Bilddatei mit einem Foto der Mondoberfläche, die geladen und zum Erstellen des animierten, sich drehenden Monds verwendet wird.
|
Laden externer Bilder als Bitmap-Daten
Die erste Teilaufgabe in diesem Beispiel ist das Laden einer externen Bilddatei, die in diesem Fall ein Foto der Mondoberfläche ist. Der Ladevorgang wird mit zwei Methoden der MoonSphere-Klasse durchgeführt: dem
MoonSphere()
-Konstruktor, mit dem der Ladevorgang eingeleitet wird, und der
imageLoadComplete()
-Methode, die aufgerufen wird, wenn das externe Bild vollständig geladen wurde.
Das Laden externer Bilder entspricht dem Laden externer SWF-Dateien. In beiden Fällen wird zum Durchführen des Ladevorgangs eine Instanz der flash.display.Loader-Klasse verwendet. Der Code in der
MoonSphere()
-Methode, mit dem das Laden des Bilds gestartet wird, lautet wie folgt:
var imageLoader:Loader = new Loader();
imageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageLoadComplete);
imageLoader.load(new URLRequest("moonMap.png"));
In der ersten Zeile wird die Loader-Instanz mit dem Namen
imageLoader
deklariert. In der dritten Zeile wird dann der Ladevorgang tatsächlich gestartet, indem die
load()
-Methode des Loader-Objekts aufgerufen und eine URLRequest-Instanz übergeben wird, die die URL des zu ladenden Bilds enthält. In der zweiten Zeile wird der Ereignis-Listener festgelegt, der ausgelöst wird, wenn das Bild vollständig geladen wurde. Beachten Sie, dass die
addEventListener()
-Methode nicht für die Loader-Instanz selbst aufgerufen wird, sondern für die
contentLoaderInfo
-Eigenschaft des Loader-Objekts. Die Loader-Instanz selbst löst keine Ereignisse aus, die sich auf die zu ladenden Inhalte beziehen. Die
contentLoaderInfo
-Eigenschaft der Instanz enthält jedoch einen Verweis auf das LoaderInfo-Objekt, das den in das Loader-Objekt zu ladenden Inhalten zugeordnet ist (in diesem Fall das externe Bild). Dieses LoaderInfo-Objekt enthält mehrere Ereignisse mit Bezug auf den Fortschritt und den Abschluss des Ladevorgangs externer Inhalte, u. a. das
complete
-Ereignis (
Event.COMPLETE
), das einen Aufruf der
imageLoadComplete()
-Methode auslöst, wenn das Bild vollständig geladen wurde.
Während das Starten des Ladens externer Bilder einen wichtigen Teil des Gesamtvorgangs darstellt, ist es genau so wichtig, sich über die folgenden Schritte im Klaren zu sein, nachdem das Laden abgeschlossen ist. Wie im zuvor abgebildeten Code dargestellt, wird die
imageLoadComplete()
-Funktion aufgerufen, wenn das Bild vollständig geladen ist. In dieser Funktion erfolgen verschiedene Manipulationen der geladenen Bilddaten, die in den folgenden Abschnitten beschrieben werden. Zum Verwenden der Bilddaten muss jedoch zunächst auf sie zugegriffen werden. Beim Verwenden eines Loader-Objekts zum Laden eines externen Bilds wird das geladene Bild zu einer Bitmap-Instanz, die dem Loader-Objekt als untergeordnetes Anzeigeobjekt zugeordnet wird. In diesem Fall steht die Loader-Instanz in der Ereignis-Listener-Methode als Teil des Ereignisobjekts zur Verfügung, das der Methode als Parameter übergeben wird. Es folgen die ersten Zeilen der
imageLoadComplete()
-Methode:
private function imageLoadComplete(event:Event):void
{
textureMap = event.target.content.bitmapData;
...
}
Beachten Sie, dass der Ereignisobjektparameter die Bezeichnung
event
trägt und eine Instanz der Event-Klasse ist. Jede Instanz der Event-Klasse hat eine
target
-Eigenschaft, die auf das Objekt verweist, das das Ereignis ausgelöst hat (in diesem Fall die LoaderInfo-Instanz, für die wie zuvor beschrieben die
addEventListener()
-Methode aufgerufen wurde). Das LoaderInfo-Objekt hat wiederum eine
content
-Eigenschaft, die (nach Abschluss des Ladevorgangs) die Bitmap-Instanz mit dem geladenen Bitmapbild enthält. Wenn Sie das Bild direkt auf dem Bildschirm anzeigen möchten, können Sie diese Bitmap-Instanz (
event.target.content
) einem Anzeigeobjektcontainer zuweisen. (Sie können auch das Loader-Objekt einem Anzeigeobjektcontainer zuweisen). In diesem Beispiel werden die geladenen Inhalte jedoch als Quelle für Bildrohdaten verwendet und nicht direkt auf dem Bildschirm angezeigt. Daher wird in der ersten Zeile der
imageLoadComplete()
-Methode die
bitmapData
-Eigenschaft der geladenen Bitmap-Instanz (
event.target.content.bitmapData
) gelesen und in der Instanzvariablen
textureMap
gespeichert. Diese wird als Bilddatenquelle verwendet, um die Animation des sich drehenden Monds zu erzeugen. Dies wird als Nächstes beschrieben.
Erstellen eines Animationseffekts durch Kopieren von Pixeln
Eine einfache Definition von Animation ist die Illusion von Bewegung oder Abwechslung durch das Ändern eines Bilds über einen bestimmten Zeitraum. In diesem Beispiel besteht das Ziel darin, die Illusion eines kugelförmigen Monds zu erzeugen, der sich um seine vertikale Achse dreht. Für den Zweck dieser Animation kann jedoch der Aspekt einer sphärischen Verzerrung vernachlässigt werden. Betrachten Sie das Bild, das geladen und als Quelle der Mondbilddaten verwendet wird:
Wie Sie sehen, sind in dem Bild keine kugelförmigen Körper abgebildet. Vielmehr handelt es sich um ein rechteckiges Foto der Mondoberfläche. Da das Foto eine Aufnahme vom Mondäquator darstellt, sind die Bildbereiche am oberen und unteren Rand lang gezogen und verzerrt. Um die Bildverzerrung zu entfernen und das Bild kugelförmig erscheinen zu lassen, wird ein Verschiebungsmatrixfilter eingesetzt. Dies wird an späterer Stelle beschrieben. Da dieses Quellbild ein Rechteck ist, genügt es zum Erzeugen der Illusion einer sich drehenden Kugel, das Foto der Mondoberfläche horizontal zu verschieben.
Beachten Sie, dass das Bild eigentlich aus zwei nebeneinandergelegten Kopien des Mondoberflächenfotos besteht. Dieses Bild ist das Quellbild, aus dem wiederholt Bilddaten kopiert werden, um den Anschein von Bewegung zu erwecken. Durch das Aneinanderfügen zweier Kopien des Bilds ist es einfacher, einen ununterbrochenen Bildlaufeffekt zu erzielen. Zum besseren Verständnis wird der Animationsvorgang nun schrittweise abgehandelt.
Der Animationsvorgang wird mit zwei verschiedenen ActionScript-Objekten durchgeführt. Zunächst wird das geladene Quellbild verwendet, das im Code durch die BitmapData-Instanz mit dem Namen
textureMap
dargestellt wird. Wie zuvor beschrieben, wird
textureMap
mithilfe des folgenden Codes mit Bilddaten gefüllt, wenn der Ladevorgang des externen Bilds abgeschlossen ist:
textureMap = event.target.content.bitmapData;
Der Inhalt von
textureMap
ist das rechteckige Mondbild. Zusätzlich wird im Code zum Erzeugen des animierten Rotationseffekts eine Bitmap-Instanz mit dem Namen
sphere
verwendet, bei der es sich um das eigentliche Anzeigeobjekt handelt, mit dem das Mondbild auf dem Bildschirm angezeigt wird. Wie
textureMap
wird auch das
sphere
-Objekt mithilfe der ursprünglichen Bilddaten in der
imageLoadComplete()
-Methode erzeugt und gefüllt. Dies erfolgt mit dem folgenden Code:
sphere = new Bitmap();
sphere.bitmapData = new BitmapData(textureMap.width / 2, textureMap.height);
sphere.bitmapData.copyPixels(textureMap,
new Rectangle(0, 0, sphere.width, sphere.height),
new Point(0, 0));
Wie aus dem Code ersichtlich, wird
sphere
instanziiert. Die
bitmapData
-Eigenschaft der Instanz (die Bildrohdaten, die von
sphere
angezeigt werden) wird mit derselben Höhe und der halben Breite von
textureMap
angelegt. Anders ausgedrückt, hat der Inhalt von
sphere
die Größe eines Mondfotos (da das Bild in
textureMap
aus zwei nebeneinandergelegten Mondfotos besteht). Als Nächstes wird die
bitmapData
-Eigenschaft mithilfe der
copyPixels()
-Methode mit Bilddaten gefüllt. Mit den Parametern im Aufruf der
copyPixels()
-Methode werden mehrere Informationen übergeben:
-
Der erste Parameter gibt an, dass die Bilddaten aus
textureMap
kopiert werden.
-
Der zweite Parameter, eine neue Rectangle-Instanz, legt fest, aus welchem Teil von
textureMap
der Bildausschnitt kopiert werden soll. In diesem Fall handelt es sich um ein Rechteck, das an der linken oberen Ecke von
textureMap
beginnt (angegeben durch die ersten beiden
Rectangle()
-Parameter
0, 0
). Die Breite und Höhe des rechteckigen Bildausschnitts stimmen mit den Eigenschaften
width
und
height
von
sphere
überein.
-
Der dritte Parameter, eine neue Point-Instanz mit dem x-Wert und dem y-Wert
0
, definiert das Ziel der Pixeldaten, in diesem Fall die linke obere Ecke (0, 0) von
sphere.bitmapData
.
Mit dem Code werden die in der folgenden Abbildung umrandeten Pixel aus
textureMap
kopiert und in
sphere
eingefügt. Anders ausgedrückt, ist der BitmapData-Inhalt von
sphere
der im Folgenden markierte Teil von
textureMap
:
Dabei darf jedoch nicht vergessen werden, dass es sich hierbei nur um den Anfangszustand von
sphere
handelt, d. h. um das erste Bild, das in
sphere
eingefügt wird.
Nachdem nun das Quellbild geladen und
sphere
erstellt wurde, besteht die letzte Aufgabe der
imageLoadComplete()
-Methode darin, die Animation einzurichten. Die Animation wird von einer Timer-Instanz mit dem Namen
rotationTimer
gesteuert, die mit dem folgenden Code erstellt und gestartet wird:
var rotationTimer:Timer = new Timer(15);
rotationTimer.addEventListener(TimerEvent.TIMER, rotateMoon);
rotationTimer.start();
Im Code wird zunächst die Timer-Instanz mit dem Namen
rotationTimer
erstellt. Mit dem an den
Timer()
-Konstruktor übergebenen Parameter wird angegeben, dass
rotationTimer
das zugehörige
timer
-Ereignis alle 15 illisekunden auslösen soll. Anschließend wird die
addEventListener()
-Methode aufgerufen und festgelegt, dass beim Auftreten des
timer
-Ereignisses (
TimerEvent.TIMER
) die Methode
rotateMoon()
aufgerufen wird. Schließlich wird der Timer dann durch Aufrufen der zugehörigen
start()
-Methode gestartet.
Aufgrund der Parameter für
rotationTimer
ruft Flash Player im Abstand von etwa 15 Millisekunden die
rotateMoon()
-Methode der MoonSphere-Klasse auf. Auf diese Weise wird die Animation des Monds realisiert. Der Quellcode der
rotateMoon()
-Methode lautet wie folgt:
private function rotateMoon(event:TimerEvent):void
{
sourceX += 1;
if (sourceX > textureMap.width / 2)
{
sourceX = 0;
}
sphere.Data.copyPixels(textureMap,
new Rectangle(sourceX, 0, sphere.width, sphere.height),
new Point(0, 0));
event.updateAfterEvent();
}
Mit diesem Code werden drei Aufgaben ausgeführt:
-
Der Wert der Variablen
sourceX
(anfangs auf 0 gesetzt) wird um 1 erhöht.
sourceX += 1;
Die Variable
sourceX
wird verwendet, um die Position in
textureMap
festzulegen, ab der die Pixel kopiert und in
sphere
eingefügt werden. Der Code hat daher den Effekt, dass das auf
textureMap
angewendete Rechteck um ein Pixel nach rechts verschoben wird. In der grafischen Darstellung bedeutet dies, dass das Quellrechteck nach mehreren Animationszyklen um mehrere Pixel nach rechts verschoben ist:
Nach einigen weiteren Zyklen hat sich das Rechteck noch weiter bewegt:
Diese schrittweise, kontinuierliche Verschiebung der Position, ab der die Pixel kopiert werden, ist der Schlüssel zur Animation. Durch das langsame und stetige Verschieben der Quellposition nach rechts scheint sich das auf dem Bildschirm in
sphere
angezeigte Bild kontinuierlich nach links zu bewegen. Aus diesem Grund muss das Quellbild (
textureMap
) aus zwei Kopien des Mondoberflächenfotos bestehen. Da sich das Rechteck kontinuierlich nach rechts bewegt, befindet es sich die meiste Zeit nicht über nur einem Mondfoto, sondern überlappt die beiden Fotos.
-
Es gibt jedoch ein Problem mit dem sich langsam nach rechts verschiebenden Rechteck. Über kurz oder lang erreicht das Rechteck den rechten Rand von
textureMap
. Gleichzeitig können keine weiteren Pixel des Mondfotos kopiert und in
sphere
eingefügt werden.
Dieses Problem wird mit den nächsten Codezeilen gelöst:
if (sourceX >= textureMap.width / 2)
{
sourceX = 0;
}
Im Code wird überprüft, ob
sourceX
(der linke Rand des Rechtecks) die Mitte von
textureMap
erreicht hat. Wenn dies der Fall ist, wird
sourceX
wieder auf 0 gesetzt und so zurück zum linken Rand von
textureMap
bewegt. Damit beginnt der Zyklus von vorn:
-
Nachdem der passende Wert für
sourceX
berechnet ist, besteht der letzte Schritt zum Erzeugen der Animation darin, die Pixel des neuen Quellrechtecks auch tatsächlich zu kopieren und in
sphere
einzufügen. Der dazu verwendete Code ähnelt sehr dem Code, mit dem
sphere
zu Beginn gefüllt wurde (weiter oben beschrieben). Der einzige Unterschied besteht darin, dass nun beim Aufrufen des Konstruktors
new Rectangle()
der linke Rand des Rechtecks auf
sourceX
gesetzt wird:
sphere.bitmapData.copyPixels(textureMap,
new Rectangle(sourceX, 0, sphere.width, sphere.height),
new Point(0, 0));
Rufen Sie sich in Erinnerung, dass dieser Code alle 15 illisekunden aufgerufen wird. Während sich die Position des Quellrechtecks kontinuierlich ändert und die kopierten Pixel in
sphere
eingefügt werden, wird auf dem Bildschirm der Eindruck erzeugt, dass sich das in
sphere
dargestellte Mondfoto ständig bewegt. Anders ausgedrückt, es entsteht der Eindruck, dass der Mond sich dreht.
Erzeugen des kugelförmigen Erscheinungsbilds
Natürlich ist der Mond kein Rechteck, sondern eine Kugel. Daher muss im Beispiel das rechteckige und fortlaufend animierte Foto der Mondoberfläche in eine Kugel umgewandelt werden. Hierzu müssen zwei Schritte ausgeführt werden: Mit einer Maske werden alle Bildinhalte außerhalb eines kreisförmigen Bereichs des Mondoberflächenfotos ausgeblendet. Mit einem Verschiebungsmatrixfilter wird dann die Darstellung des Mondfotos verzerrt, um es dreidimensional erscheinen zu lassen.
Zunächst wird eine kreisförmige Maske verwendet, um alle Inhalte des MoonSphere-Objekts außer der durch den Filter erzeugten Kugel auszublenden. Mit dem folgenden Code wird die Maske als Shape-Instanz erstellt und auf die MoonSphere-Instanz angewendet:
moonMask = new Shape();
moonMask.graphics.beginFill(0);
moonMask.graphics.drawCircle(0, 0, radius);
this.addChild(moonMask);
this.mask = moonMask;
Beachten Sie, dass die Maske über die geerbte
mask
-Eigenschaft direkt auf die MoonSphere-Instanz angewendet werden kann, da es sich bei dieser Instanz um ein Anzeigeobjekt handelt.
Um einen realistisch wirkenden Effekt einer sich drehenden Kugel zu erzeugen, ist es nicht damit getan, Teile des Fotos durch eine kreisförmige Maske auszublenden. Aufgrund der Art und Weise, wie das Foto der Mondoberfläche aufgenommen wurde, sind die Abmessungen nicht proportional. Die Bildteile am oberen und unteren Bildrand sind stärker verzerrt und gestreckt als die Bereiche am Äquator. Um das Mondfoto dreidimensional wirken zu lassen, wird ein Verschiebungsmatrixfilter verwendet.
Bei einem Verschiebungsmatrixfilter handelt es sich um einen Filtertyp, der zum Verzerren von Bildern eingesetzt wird. In diesem Fall wird das Mondfoto „verzerrt“, damit es realistischer wirkt. Dazu werden der obere und untere Bildteil horizontal gestaucht, der Mittelteil bleibt jedoch unverändert. Unter der Voraussetzung, dass der Filter auf einen quadratförmigen Teil des Fotos angewendet wird, entsteht durch Stauchen des oberen und unteren Bildteils ohne Einbeziehung der Bildmitte aus dem Quadrat ein Kreis. Ein Nebeneffekt der Animation dieses verzerrten Bilds besteht darin, dass sich die Bildmitte jeweils um einen größeren Pixelabstand zu bewegen scheint als die Bereiche am oberen und unteren Bildrand. Dies erzeugt die Illusion, dass es sich bei dem Kreis in Wirklichkeit um ein dreidimensionales Objekt (eine Kugel) handelt.
Der folgende Code wird verwendet, um den Verschiebungsmatrixfilter mit dem Namen
displaceFilter
zu erstellen:
var displaceFilter:DisplacementMapFilter;
displaceFilter = new DisplacementMapFilter(fisheyeLens,
new Point(radius, 0),
BitmapDataChannel.RED,
BitmapDataChannel.GREEN,
radius, 0);
Der erste Parameter
fisheyeLens
wird als Matrixbild bezeichnet. In diesem Fall handelt es sich um ein im Programmcode erstelltes BitmapData-Objekt. Die Erstellung dieses Bilds wird unter
Erstellen eines Bitmapbilds durch Festlegen von Pixelwerten
erläutert. Die anderen Parameter beschreiben die Position im gefilterten Bild, ab der der Filter angewendet werden soll, sowie die zum Steuern des Verschiebungseffekts verwendeten Farbkanäle und in welchem Ausmaß sie sich auf die Verschiebung auswirken. Nachdem der Verschiebungsmatrixfilter erstellt wurde, wird er noch in der
imageLoadComplete()
-Methode auf
sphere
angewendet:
sphere.filters = [displaceFilter];
Das endgültige Bild (Maske und Verschiebungsmatrixfilter angewendet) sieht wie folgt aus:
Mit jedem neuen Zyklus der Animation des sich drehenden Monds wird der Inhalt der BitmapData-Eigenschaft von „sphere“ mit einem neuen Ausschnitt der Quellbilddaten überschrieben. Der Filter muss jedoch nicht jedes Mal erneut angewendet werden. Der Grund hierfür ist, dass der Filter nicht auf die Bitmap-Daten (die Pixelrohdaten), sondern auf die Bitmap-Instanz (das Anzeigeobjekt) angewendet wird. Beachten Sie, dass die Bitmap-Instanz nicht die tatsächlichen Bitmap-Daten enthält. Sie ist das Anzeigeobjekt, mit dem die Bitmap-Daten auf dem Bildschirm dargestellt werden. Zur Veranschaulichung: Eine Bitmap-Instanz ist wie ein Diaprojektor, mit dem Fotos auf einer Leinwand dargestellt werden, und ein BitmapData-Objekt ist das eigentliche Dia, das mit dem Diaprojektor projiziert werden kann. Filter können direkt auf ein BitmapData-Objekt angewendet werden. Dies kann damit verglichen werden, dass direkt auf das Dia gezeichnet wird, um das Bild zu verändern. Filter können jedoch auch auf beliebige Anzeigeobjekte (einschließlich Bitmap-Instanzen) angewendet werden. Dies ist vergleichbar mit dem Anbringen eines Filters vor dem Projektorobjektiv, um das auf der Leinwand dargestellte Bild zu verzerren (ohne überhaupt das Original-Dia zu verändern). Da auf die Bitmap-Rohdaten mithilfe der bitmapData-Eigenschaft einer Bitmap-Instanz zugegriffen werden kann, können Filter direkt auf die Bitmap-Rohdaten angewendet werden. In diesem Fall ist es jedoch sinnvoll, den Filter nicht auf die Bitmap-Daten, sondern auf das Bitmap-Anzeigeobjekt anzuwenden.
Weitere Informationen zum Verwenden von Verschiebungsmatrixfiltern in ActionScript finden Sie unter
Anwenden von Filtern auf Anzeigeobjekte
.
Erstellen eines Bitmapbilds durch Festlegen von Pixelwerten
Ein wichtiger Aspekt beim Anwenden von Verschiebungsmatrixfiltern ist, dass eigentlich zwei Bilder verwendet werden. Das eine Bild (das Quellbild) wird tatsächlich durch den Filter verändert. In diesem Beispiel ist das Quellbild die Bitmap-Instanz mit dem Namen
sphere
. Das andere vom Filter verwendete Bild wird als Matrixbild bezeichnet. Das Matrixbild wird nicht auf dem Bildschirm angezeigt. Stattdessen werden die Farben der einzelnen Pixel als Eingabe der Verschiebungsfunktion verwendet. Die Farbe des Pixels an einer bestimmten (x, y)-Koordinate im Matrixbild legt fest, welche Verschiebung (der physischen Position) auf das entsprechende Pixel an dieser (x, y)-Koordinate im Quellbild angewendet wird.
Daher wird für dieses Beispiel ein geeignetes Matrixbild benötigt, um mit dem Verschiebungsmatrixfilter einen Kugeleffekt zu erzeugen. Dieses Matrixbild hat einen grauen Hintergrund und stellt einen Kreis dar, der mit dem horizontalen Farbverlauf einer einzigen Farbe (Rot, von dunkel zu hell) gefüllt ist, wie im Folgenden abgebildet:
Da in diesem Beispiel nur ein Matrixbild und ein Filter eingesetzt werden, wird das Matrixbild nur einmal (in der
imageLoadComplete()
-Methode, d. h. nach Abschluss des Ladevorgangs des externen Bilds) erzeugt. Das Matrixbild mit dem Namen
fisheyeLens
wird durch Aufrufen der
createFisheyeMap()
-Methode der MoonSphere-Klasse erstellt:
var fisheyeLens:BitmapData = createFisheyeMap(radius);
Innerhalb der
createFisheyeMap()
-Methode wird das Matrixbild Pixel für Pixel mithilfe der
setPixel()
-Methode der BitmapData-Klasse gezeichnet. Der vollständige Code der
createFisheyeMap()
-Methode ist im Folgenden aufgeführt. Im Anschluss daran finden Sie eine schrittweise Erläuterung der Funktionsweise.
private function createFisheyeMap(radius:int):BitmapData
{
var diameter:int = 2 * radius;
var result:BitmapData = new BitmapData(diameter,
diameter,
false,
0x808080);
// Loop through the pixels in the image one by one
for (var i:int = 0; i < diameter; i++)
{
for (var j:int = 0; j < diameter; j++)
{
// Calculate the x and y distances of this pixel from
// the center of the circle (as a percentage of the radius).
var pctX:Number = (i - radius) / radius;
var pctY:Number = (j - radius) / radius;
// Calculate the linear distance of this pixel from
// the center of the circle (as a percentage of the radius).
var pctDistance:Number = Math.sqrt(pctX * pctX + pctY * pctY);
// If the current pixel is inside the circle,
// set its color.
if (pctDistance < 1)
{
// Calculate the appropriate color depending on the
// distance of this pixel from the center of the circle.
var red:int;
var green:int;
var blue:int;
var rgb:uint;
red = 128 * (1 + 0.75 * pctX * pctX * pctX / (1 - pctY * pctY));
green = 0;
blue = 0;
rgb = (red << 16 | green << 8 | blue);
// Set the pixel to the calculated color.
result.setPixel(i, j, rgb);
}
}
}
return result;
}
Beim Aufrufen der Methode wird dieser zunächst ein Parameter (
radius
) übergeben, der den Radius des zu erstellenden kreisförmigen Bilds angibt. Anschließend wird im Code das BitmapData-Objekt erstellt, in dem der Kreis gezeichnet werden soll. Dieses Objekt mit dem Namen
result
wird schließlich als Rückgabewert der Methode zurückgegeben. Wie im folgenden Codeausschnitt dargestellt, wird die BitmapData-Instanz
result
mit den folgenden Werten erstellt: Breite und Höhe entsprechen dem Kreisdurchmesser, keine Transparenz (
false
im dritten Parameter) und Vorfüllung mit der Farbe
0x808080
(mittelgrau):
var result:BitmapData = new BitmapData(diameter,
diameter,
false,
0x808080);
Anschließend werden im Code zwei Schleifen verwendet, damit alle Pixel des Bilds einzeln durchlaufen werden. In der äußeren Schleife werden alle Bildspalten von links nach rechts durchlaufen (die Variable
i
enthält die horizontale Position des jeweils zu bearbeitenden Pixels). In der inneren Schleife werden alle Pixel der aktiven Spalte von oben nach unten durchlaufen (die Variable
j
enthält die vertikale Position des jeweils zu bearbeitenden Pixels). Der Code für die Schleifen ist im Folgenden dargestellt (der Inhalt der inneren Schleife wurde weggelassen):
for (var i:int = 0; i < diameter; i++)
{
for (var j:int = 0; j < diameter; j++)
{
...
}
}
Während in den Schleifen alle Pixel einzeln durchlaufen werden, wird für jedes Pixel ein Wert (der Farbwert dieses Pixels im Matrixbild) berechnet. Dieser Vorgang umfasst vier Schritte:
-
Im Code wird für das aktuelle Pixel der Abstand vom Kreismittelpunkt auf der x-Achse berechnet (
i - radius
). Dieser Wert wird durch den Radius dividiert, um den Prozentwert (im Verhältnis zum Radius) und nicht den absoluten Abstand (
(i - radius) / radius
) zu erhalten. Dieser Prozentwert wird in einer Variablen mit dem Namen
pctX
gespeichert. Der entsprechende Wert für die y-Achse wird ebenfalls berechnet und in der Variablen
pctY
gespeichert, wie im folgenden Code dargestellt:
var pctX:Number = (i - radius) / radius;
var pctY:Number = (j - radius) / radius;
-
Mithilfe einer trigonometrischen Standardformel, dem Satz des Pythagoras, wird aus
pctX
und
pctY
der lineare Abstand zwischen dem Kreismittelpunkt und dem aktuellen Punkt berechnet. Dieser Wert wird in einer Variablen mit dem Namen
pctDistance
gespeichert, wie im Folgenden dargestellt:
var pctDistance:Number = Math.sqrt(pctX * pctX + pctY * pctY);
-
Anschließend wird überprüft, ob der prozentuale Abstand kleiner als 1 ist (100 % des Radius, d. h. das Pixel befindet sich innerhalb des Kreisradius). Wenn sich das Pixel innerhalb des Kreises befindet, wird ihm ein berechneter Wert (an dieser Stelle weggelassen, jedoch in Schritt 4 beschrieben) zugewiesen. Andernfalls wird der Standardfarbwert des Pixels für Mittelgrau nicht geändert:
if (pctDistance < 1)
{
...
}
-
Für die Pixel innerhalb des Kreises wird ein Farbwert berechnet. Am Ende weist der Kreis einen roten Farbverlauf auf, der sich von Schwarz (0 % Rot) am linken Kreisrand bis zu Hellrot (100 %) am rechten Kreisrand erstreckt. Der Farbwert wird ursprünglich in drei Teilkomponenten (Rot, Grün und Blau) berechnet, wie im Folgenden dargestellt:
red = 128 * (1 + 0.75 * pctX * pctX * pctX / (1 - pctY * pctY));
green = 0;
blue = 0;
Beachten Sie, dass nur der Rotanteil der Farbe (die Variable
red
) tatsächlich einen Wert enthält. Die Werte für Grün und Blau (die Variablen
green
und
blue
) sind hier zum besseren Verständnis ebenfalls aufgeführt, können jedoch weggelassen werden. Da der Zweck dieser Methode darin besteht, einen Kreis mit einem roten Farbverlauf zu erzeugen, werden keine Werte für Grün und Blau benötigt.
Nachdem die drei Farbwertkomponenten festgelegt sind, werden sie mithilfe eines Bitverschiebungs-Standardalgorithmus in einem einzigen ganzzahligen Farbwert kombiniert, wie im folgenden Code dargestellt:
rgb = (red << 16 | green << 8 | blue);
Schließlich wird der berechnete Farbwert dann mit der
setPixel()
-Methode des BitmapData-Objekts
result
dem aktuellen Pixel zugewiesen:
result.setPixel(i, j, rgb);
|
|
|