Zurück   Flashforum > Flash > ActionScript > ActionScript 1

Antwort
 
LinkBack Themen-Optionen Ansicht
Alt 18-09-2006, 08:55   #1 (permalink)
Freizeitflasher
 
Benutzerbild von Alphanimal
 
Registriert seit: Jun 2004
Ort: Niederösterreich
Beiträge: 615
Hilfe bei realistischem Wasser Effekt

Hallo!
Ihr kennt doch diese Wasser-Effekt Applets wie dieses hier von Anfy:
http://www.anfyteam.com/anj/water/anwater2.html

Ich bin grade dabei sowas in Flash zu machen. Ich habe die Theorie dahinter von folgendem Artikel:
http://freespace.virgin.net/hugo.eli...cs/x_water.htm

Zusammengefasst geht es dabei um folgendes:
Wir haben 2 Buffer (Bitmaps). Diese Buffer enthalten als Farbwerte die Höhe der Wasseroberfläche (Amplitude).

Buffer 1 enthält den aktuellen Status.
Buffer 2 den Status im Frame davor.

Durch die Differenz der beiden Buffer lässt sich berechnen, wie schnell sich die Wasseroberflächen an einem bestimmten Pixel hebt/senkt.
Diese Geschwindigkeit überträgt man jeweils auf die benachbarten Pixel.
Mehr dazu in dem Artikel!

Also im Endeffekt ergibt sich ein einfacher Algorithmus:
Code:
damping = 0.95;
jeden frame{
	Wellen erzeugen (z.B. Farbe an Mauspos. ändern)
	für jeden Pixel{
		Neuer Buffer = Smooth(Alter Buffer)*2 - Neuer Buffer;
		Neuer Buffer = Neuer Buffer * damping
	}
	Neuen Buffer anzeigen
	Die beiden Buffer Vertauschen (neuer Buffer ist alt)
}
function Smooth{ 
	Durchschnittlichen Wert der angrenzenden Pixel zurückgeben
}
Ich habe es geschafft, diese Verhaltensweise ohne BitmapData Objekte zu implementieren. Für jeden Pixel hab ich einen MC erstellt usw...

Der Code kommt einfach in den ersten Frame. Damit es funktioniert, braucht man noch einen MC in der Bibliothek mit einem Rechteck darin und mit der Link-ID "pixel". Die Frabe des Rechteckes sollte sich natürlich von der Hintergrundfarbe abheben

PHP-Code:
cx 30cy 30//Breite/Höhe
damp 0.95;      //Dämpfung
dx 5dy 5;   //Breite/Höhe der Pixel
= []; //Array mit Pixel-MCs

for(x=0;x<cx;x++){ //Pixel erstellen
    
p[x] = [];
    for(
y=0;y<cy;y++){
        
mc this.attachMovie("part"nullthis.getNextHighestDepth());
        
mc._x x*dx//Positionieren
        
mc._y y*dy;
        
mc._width dx;
        
mc._height dy;
        
mc.0// Alter Buffer
        
mc.0// Neuer Buffer
        
p[x][y] = mc;
    }
}

this.onMouseMove = function(){
    
//Pixel setzen
    
px Math.floor((_xmouse)/dx);
    
py Math.floor((_ymouse)/dy);
    if(
px>&& px<cx-&& py>&& py<cy-1p[px][py].= -50;
}

this.onEnterFrame= function(){
    
//Für jeden Pixel, den nicht am Rand ist
    
for(y=1;y<cy-1;y++)for(x=1;x<cx-1;x++){
        
//Die magische Formel anwenden
        
p[x][y].= (p[x-1][y].z
                   
p[x+1][y].z
                   
p[x][y-1].z
                   
p[x][y+1].z)/p[x][y].v;
        
p[x][y].*= damp;
    }
    
//Ergebnis anzeigen
    
for(y=0;y<cy;y++)for(x=0;x<cx;x++){
        
p[x][y]._alpha p[x][y].50;
    }
    
//Buffer vertauschen
    
for(y=1;y<cy-1;y++)for(x=1;x<cx-1;x++){
        
p[x][y].v;
        
p[x][y].p[x][y].z;
        
p[x][y].t;
    }

Das funktioniert... aber natürlich extrem langsam! jeden Pixel einzeln berechnen braucht seine Zeit in Flash.
Die SWF ist im Anhang water2.zip

Ich hab mir jetzt gedacht, das muss in Flash 8 mit BitmapData usw. auch funktionieren! Das hat es auch ansatzweise! (Ein paar Probleme habe ich bei denen ich Hilfe brauche.)

Also meine Überlegungen:
Die magische Formel für jeden Pixel ist "c = s(p) - c".
c ist der aktuelle Buffer (current)
p ist der alte Buffer (previous)
s(p) halbiert die Farbwerte der angrenzenden Pixel in p und addiert sie. Smooth(p)*2.

Wie macht man das jetzt mit BitmapData? Naja... man braucht zunächst die 2 Bitmaps für die beiden Buffer, und dann noch einen dritten für die Zwischenspeicherung.
folgender Algorithmus:
Code:
2 BitmapData Objekte ("prev" und "curr") mit einem definieren Farbwert initialisieren (z.B. 0x7f7f7f)
BitmapData "buff" für Zwischenspeicherung erstellen und auf mit attachBitmap anzeigen.
jeden Frame{
	"buff" komplett auf 0x000000 setzen
	Farbwert in "prev" halbieren und 4x versetzt additiv auf "buff" zeichnen
	"curr" subtraktiv auf "buff" zeichenen
	//buff wird angezeigt, da er jetzt nicht mehr verändert wird
	"buff" auf "prev" zeichnen
	"curr" und "prev" vertauschen
}
Dies ist die Berechnung von curr = s(prev)*2 - curr
1. doppelter Durchschnitt von "prev" wird in wird in "buff" gespeichert ("s(prev)*2")
2. "curr" wird von buff abgezogen ("... - curr")
3. buff wird in curr gezeichnet (curr = ...)

Hier ist mein Code für Flash Player 8 - Einfach in den ersten Frame einer blanken .fla Datei!
PHP-Code:
import flash.display.BitmapData
import flash
.geom.Rectangle
import flash
.geom.Matrix
import flash
.geom.ColorTransform

200//Dimensionen der Bitmaps
200;

init_color 0x7f7f7f//Ausgangsfarbe (50% grau)

//Bitmaps erstellen
curr = new BitmapData(whfalseinit_color);
prev = new BitmapData(whfalseinit_color);
buff = new BitmapData(whfalseinit_color);

this.attachBitmap(buff1);

//Rereich zum Zeichenen = Alles außer Rand-Pixel
active = new Rectangle(11w-2h-2);

shift = [ //Matrizen zum verschieben auf die 4 benachbarten Pixel
    
new Matrix(1,0,0,1,  1,  0),
    new 
Matrix(1,0,0,1, -1,  0),
    new 
Matrix(1,0,0,1,  0,  1),
    new 
Matrix(1,0,0,1,  0, -1)
];

// Einheitsmatrix für Subtraktion (nichts verändern!)
subMatrix = new Matrix();
//CT für Subtraktion ( sollte eigentlich nichts verändern,
//                     aber funktioniert nur mit "-2" Verschiebung???)
subTrans = new ColorTransform(1,1,1,1, -2,-2,-2,0);

//CT für Addition (halber Farbwert wird 4x addiert... s(prev)*2 )
darken = new ColorTransform(0.50.50.51,,,0);

this.onMouseMove = function(){
    if(
active.contains(_xmouse_ymouse)){ //Wenn maus im Bereich ist, Welle erstellen
        
curr.setPixel(_xmouse_ymouse0xffffff);
    }
    
}

this.onEnterFrame = function(){
    
// c = s(p)*2 - c

    //"buff" löschen
    
buff.fillRect(active0x000000);
    for(
i in shift){ //Doppelten Durchschnitt der angrenzenden Pixel von "prev" in "buff" zeichnen
        
buff.draw(prevshift[i], darken"add"active);
    }
    
//"curr" von "buff" abziehen
    
buff.draw(currsubMatrixsubTrans"subtract"active);
    
//"buff" nach "curr" kopieren
    
curr.draw(buff);
    
    
//Buffer vertauschen
    
tmp prev;
    
prev curr;
    
curr tmp;

Wie man sieht funktionierts einigermaßen (ohne Dämpfung)
Die SWF ist im Anhang water4.zip

Da Problem ist, dass es sich nicht genau so verhält wie das Beispiel ohne Bitmaps.
1. Ich ziehe nachdem der doppelte Durchschnitt berechnet wird 2 von jedem Pixel ab... wenn ich das nicht mache wird nach kurzer zeit alles schwarz - warum???
2. Wenn man eine Welle mit 0xffffff zeichnet ist kurz ein Weißer Pixel zu sehen der aber im nächsten Frame schwarz wird. (Wellenfront ist immer Schwarz???) Im aneren Beispiel breitet sich eine Weiße Welle aus.
3. kann ich keine andere Ausgangsfarbe als 0x7f7f7f verwenden. Mir ist klar, dass eine höhere (hellere) Farbe bei der Zwischenberechnung über 0xff kommen würde, aber niedrigere Werte funktionieren auch nicht wirklich.

Vl. interessiert sich der eine oder andere für die Umsetzung eines solchen Wasser-Effekts? Ich habe sowas noch nie in Flash gesehen! Hatte noch keiner die Idee?
Falls mir jemand einen Tipp geben könnte, warum es nicht so funktioniert wie es sollte, währe ich sehr dankbar!

Grüße! Daniel
Angehängte Dateien
Dateityp: zip water2.zip (788 Bytes, 106x aufgerufen)
Dateityp: zip water4.zip (702 Bytes, 142x aufgerufen)
__________________
Some Flash Worx

Geändert von Alphanimal (18-09-2006 um 08:58 Uhr)
Alphanimal ist offline   Mit Zitat antworten
Alt 19-10-2006, 20:56   #2 (permalink)
Neuer User
 
Registriert seit: Oct 2004
Beiträge: 34
Lightbulb wellenfunktion

Erst mal herzlichen Glückwunsch für Deine Fortschritte.
Ich habe mir den Code noch nicht angeschaut, aber der optische Effekt spricht für sich. Spontan würde ich aber zunächst erst mal empfehlen, die kreisförmigen Wellen nicht ewig laufen zu lassen. Und ich frage mich, warum man immer mit einer "Nadel" im Wasser rumrührt und somit immer nur ein einziges pixel anstößt. Zumindest so breit wie ein Finger (4-5 Pixel) oder sogar eine "Hand" sollten es schon sein. Bei Gelegenheit werde ich mich mal mit der Mathematik Deiner Wellen beschäftigen - aber ich denke, Du hast das Prinzip schon verstanden und brauchst wohl keine technische Unterstützung mehr.
Wie ist denn der Stand (bin nämlich sehr interessiert!)
heyeli ist offline   Mit Zitat antworten
Alt 20-10-2006, 16:11   #3 (permalink)
Freizeitflasher
 
Benutzerbild von Alphanimal
 
Registriert seit: Jun 2004
Ort: Niederösterreich
Beiträge: 615
Hallo!

Mit der Dämpfung der Wellen hab ich mich noch nicht beschäftigt, da ich ja noch grundlegende Probleme hab. Auch dass immer nur 1 px gezeichnet wird ist noch nicht relevant.

Ich habe es bis jetzt noch ein paar mal versucht von null anzufangen, aber ich habe immer das gleiche Problem. Habs mittlerweile aufgegeben.

Was ich erst nach diesem Post erfahren hab ist, dass André Michelle das ganze schon implementiert hat.
Ich hab ihm ein Email und eine PM gesendet mit der Bitte um Hilfe. Hab aber nix bekommen

mfg Daniel
__________________
Some Flash Worx
Alphanimal ist offline   Mit Zitat antworten
Antwort

Lesezeichen

Themen-Optionen
Ansicht

Forumregeln
Es ist Ihnen nicht erlaubt, neue Themen zu verfassen.
Es ist Ihnen nicht erlaubt, auf Beiträge zu antworten.
Es ist Ihnen nicht erlaubt, Anhänge hochzuladen.
Es ist Ihnen nicht erlaubt, Ihre Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks sind an
Pingbacks sind an
Refbacks sind an



Alle Zeitangaben in WEZ +1. Es ist jetzt 15:22 Uhr.

Domains, Webhosting & Vserver von Host Europe
Unterstützt das Flashforum!
Adobe User Group


Copyright ©1999 – 2012 Marc Thiele