Fractal Flames

Übersicht BlitzBasic Codearchiv

Neue Antwort erstellen

Noobody

Betreff: Fractal Flames

BeitragDi, Mai 05, 2009 22:20
Antworten mit Zitat
Benutzer-Profile anzeigen
Kürzlich stiess ich bei einem Ausflug auf die englische Wikipedia auf einen kleinen Artikel über sogenannte Fractal Flames.

Dabei geht es nicht etwa - wie man vom Namen her schliessen könnte - um fraktale Flammen, sondern um eine Gruppe von Iterated Function Systems (kurz IFS). Was ist denn das schon wieder?
In einem IFS wird anfangs ein zufälliger Punkt ausgewählt. Danach werden nacheinander verschiedene Funktionen darauf angewandt; durch jede Funktionsanwendung werden die Koordinaten des Punktes verändert und an der neuen Position wird ein Farbabdruck hinterlassen, der später beim Rendern verwendet wird.
Die anzuwendenden Funktionen werden ebenfalls zufällig ausgewählt, jedoch wird nach einem bestimmten Schema vorgegangen: Jede Funktion erhält eine Gewichtung, die bestimmt, wie oft die Funktion aufgerufen wird. Je höher die Gewichtung im Vergleich zu den anderen Funktionen, desto öfter wird sie aufgerufen.

Die fraktalen Flammen erweitern dieses IF - System um sogenannte Variationsfunktionen, die zusätzlich noch das Koordinatensystem verändern können - hier ins Detail zu gehen, würde jedoch den Rahmen dieses Posts sprengen.
Kurz gefasst können mit fraktalen Flammen faszinierende Bilder generiert werden. Sie eignen sich perfekt als Bildschirmhintergrund oder zum Ausdrucken und Aufhängen Razz

Ich kann dabei nur empfehlen, selber ein wenig mit dem Code herumzuspielen und die schönsten Eigenkreationen hier zu posten.
Die komplette Funktionsweise der einzelnen Parameter zu erklären, wäre hier wohl zuviel; allerdings bekommt man auch sehr schöne Resultate, wenn man einfach verschiedene Zahlen ausprobiert (allerdings sollten die Zahlen im Bereich von -1 bis 1 bleiben).
Der Bereich im Code, wo man zu Werke gehen kann, ist durch Kommentare gekennzeichnet; was man alles beachten sollte, steht ebenfalls in den Kommentaren.

Der Code: [AUSKLAPPEN]
Const GWIDTH = 800
Const GHEIGHT = 600

Graphics GWIDTH, GHEIGHT, 0, 2
SetBuffer BackBuffer()

Const RED            = 0
Const GREEN            = 1
Const BLUE            = 2
Const FACTOR_A         = 3
Const FACTOR_B         = 4
Const FACTOR_C         = 5
Const FACTOR_D         = 6
Const FACTOR_E         = 7
Const FACTOR_F         = 8
Const WEIGHT         = 9
Const BLEND_REFLECTION   = 10
Const BLEND_SINUSODIAL   = 11
Const BLEND_SPHERICAL   = 12
Const BLEND_SWIRL      = 13
Const BLEND_HORSESHOE   = 14
Const BLEND_POLAR      = 15
Const BLEND_HANDKERCHIEF= 16

Const VAR_REFLECTION   = 0
Const VAR_SINUSODIAL   = 1
Const VAR_SPHERICAL      = 2
Const VAR_SWIRL         = 3
Const VAR_HORSESHOE      = 4
Const VAR_POLAR         = 5
Const VAR_HANDKERCHIEF   = 6

Dim F#( 31, 16 )
Dim Density#( GWIDTH - 1, GHEIGHT - 1 )
Dim RGB#( GWIDTH - 1, GHEIGHT - 1, 3 )
Dim MappedRGB#( GWIDTH - 1, GHEIGHT - 1, 3 )

Global FunctionCount, AccWeight#, RMin#, GMin#, BMin#, RMax#, GMax#, BMax#


;--------------------------------------------------------------- Ab hier eigene Funktionen kreieren

;Hinweise zur Funktionserstellung:
;   AddFunction erstellt eine neue Funktion mit den Parametern A, B, C, D, E, F und mit einer bestimmten Gewichtung.
;   SetFunctionColor legt für eine Funktion eine bestimmte Farbe fest. Der erste Parameter ist der Index der Funktion, beginnend mit 0
;   SetFunctionBlending bestimmt den Einfluss einer Variationsfunktion auf die Funktion. Der erste Parameter ist der Funktionsindex, der zweite Parameter
;                  die Variationsfunktion (man kann hier alle Konstanten angeben, die mit VAR_ beginnen) und der letzte Parameter bestimmt,
;                  wie gross der Einfluss auf die Funktion ist.


;            A    B    C    D   E   F   Gewichtung
AddFunction( 1, -0.4, 0.7, 0.3, 1, 0.7, 0.5 ) ;Funktionserstellung
   SetFunctionColor( 0, 0, 0, 0 ) ;Farbinitialisierung
   SetFunctionBlending( 0, VAR_HANDKERCHIEF, 1.2 ) ;Den Einfluss der einzelnen Variationsfunktionen festlegen
   SetFunctionBlending( 0, VAR_SPHERICAL,    0.9 )
   SetFunctionBlending( 0, VAR_SWIRL,        0.4 )

;             A    B    C    D    E    F   Gewichtung
AddFunction( 0.4, 0.4, 0.7, 0.8, 0.3, 0.2, 0.5 )
   SetFunctionColor( 1, 255, 255, 255 )
   SetFunctionBlending( 1, VAR_SWIRL,     0.7 )
   SetFunctionBlending( 1, VAR_HORSESHOE, 0.5 )

;            A    B    C    D   E   F   Gewichtung
AddFunction( 1, -0.4, 0.7, 0.3, 1, 0.7, 0.5 )
   SetFunctionColor( 2, 0, 0, 255 )
   SetFunctionBlending( 2, VAR_SPHERICAL, 2.7 )


;------------------------------------------------------------------------------------------------------------



FractalFlame()
End

Function FractalFlame()
   Local X# = Rnd( -1, 1 )
   Local Y# = Rnd( -1, 1 )
   
   Local R# = Rnd( 0, 1 )
   Local G# = Rnd( 0, 1 )
   Local B# = Rnd( 0, 1 )
   
   Local Iteration = 0, RenderTimer = MilliSecs()
   
   While True
      FunctionWeight# = Rnd( 0, AccWeight# )
      
      For t = 0 To FunctionCount - 1
         If FunctionWeight# < F( t, WEIGHT ) Then
            NewX# = F( t, FACTOR_A )*X# + F( t, FACTOR_B )*Y# + F( t, FACTOR_C )
            NewY# = F( t, FACTOR_D )*X# + F( t, FACTOR_E )*Y# + F( t, FACTOR_F )
            
            R# = ( R# + F( t, RED   ) )/2.
            G# = ( G# + F( t, GREEN ) )/2.
            B# = ( B# + F( t, BLUE  ) )/2.
            
            X# = 0
            Y# = 0
            
            RadiusSq# = NewX#*NewX# + NewY#*NewY# ;Hier werden Werte vorrausberechnet, die von den Variationen oft gebraucht werden.
            Radius# = Sqr( RadiusSq# )
            
            For Variation = 0 To 6
               If F( t, Variation + 10 ) <> 0 Then
                  Select Variation
                     Case VAR_REFLECTION
                        X# = X# + NewX#*F( t, BLEND_REFLECTION )
                        Y# = Y# + NewY#*F( t, BLEND_REFLECTION )
                     Case VAR_SINUSODIAL
                        X# = X# + Sin( NewX#*360 )*F( t, BLEND_SINUSODIAL )
                        Y# = Y# + Sin( NewY#*360 )*F( t, BLEND_SINUSODIAL )
                     Case VAR_SPHERICAL
                        X# = X# + NewX#*F( t, BLEND_SPHERICAL )/RadiusSq#
                        Y# = Y# + NewY#*F( t, BLEND_SPHERICAL )/RadiusSq#
                     Case VAR_SWIRL
                        X# = X# + ( NewX#*Sin( RadiusSq# ) - NewY#*Cos( RadiusSq# ) )*F( t, BLEND_SWIRL )
                        Y# = Y# + ( NewX#*Cos( RadiusSq# ) + NewY#*Sin( RadiusSq# ) )*F( t, BLEND_SWIRL )
                     Case VAR_HORSESHOE
                        X# = X# + ( NewX# - NewY# )*( NewX# + NewY# )*F( t, BLEND_HORSESHOE )/RadiusSq#
                        Y# = Y# + 2*NewX#*NewY#*F( t, BLEND_HORSESHOE )/RadiusSq#
                     Case VAR_POLAR
                        X# = X# + ATan( NewX#/NewY# )/180*F( t, BLEND_POLAR )
                        Y# = Y# + ( Radius# - 1 )*F( t, BLEND_POLAR )
                     Case VAR_HANDKERCHIEF
                        X# = X# + Radius#*Sin( ATan( NewX#/NewY# ) + Radius#*360 )*F( t, BLEND_HANDKERCHIEF )
                        Y# = Y# + Radius#*Cos( ATan( NewX#/NewY# ) - Radius#*360 )*F( t, BLEND_HANDKERCHIEF )
                  End Select
               EndIf
            Next
            
            Exit
         EndIf
         
         FunctionWeight# = FunctionWeight# - F( t, WEIGHT )
      Next
      
      Iteration = Iteration + 1
      If Iteration > 20 Then FinalTransform( X#, Y#, Iteration/10000000., R#, G#, B# )
      
      If MilliSecs() - RenderTimer > 3000 Then
         Cls
         
         ToneMap( 1.01 )
         Render()
         
         Flip 0
         
         RenderTimer = MilliSecs()
      EndIf
      
      If KeyHit( 1 ) Then End
   Wend
End Function

Function FinalTransform( FX#, FY#, FDensity#, R#, G#, B# )
   X = FX#*GWIDTH/10 + GWIDTH/2
   Y = FY#*GHEIGHT/10 + GHEIGHT/2
   
   If X >= 0 And X < GWIDTH And Y >= 0 And Y < GHEIGHT Then
      RGB( X, Y, RED   ) = ( RGB( X, Y, RED   )*Density( X, Y ) + R#*FDensity# )/( Density( X, Y ) + FDensity# )
      RGB( X, Y, GREEN ) = ( RGB( X, Y, GREEN )*Density( X, Y ) + G#*FDensity# )/( Density( X, Y ) + FDensity# )
      RGB( X, Y, BLUE  ) = ( RGB( X, Y, BLUE  )*Density( X, Y ) + B#*FDensity# )/( Density( X, Y ) + FDensity# )
      Density( X, Y ) = Density( X, Y ) + FDensity#
   EndIf
End Function

Function Render()
   LockBuffer
   
   For X = 0 To GWIDTH - 1
      For Y = 0 To GHEIGHT - 1
         R# = ( MappedRGB( X, Y, RED   ) - RMin# )/( RMax# - RMin# )
         G# = ( MappedRGB( X, Y, GREEN ) - GMin# )/( GMax# - GMin# )
         B# = ( MappedRGB( X, Y, BLUE  ) - BMin# )/( BMax# - BMin# )
         
         WritePixelFast X, Y, Floor( 255*R# ) Shl 16 + Floor( 255*G# ) Shl 8 + Floor( 255*B# )
      Next
   Next
   
   UnlockBuffer
End Function

Function ToneMap( B# )
   RMin# = 10000
   GMin# = 10000
   BMin# = 10000
   RMax# = -10000
   GMax# = -10000
   BMax# = -10000
   
   For X = 0 To GWIDTH - 1
      For Y = 0 To GHEIGHT - 1
         MappedRGB( X, Y, RED   ) = B#*RGB( X, Y, RED   )/( ( B# - 1 )*RGB( X, Y, RED   ) + 1 )
         MappedRGB( X, Y, GREEN ) = B#*RGB( X, Y, GREEN )/( ( B# - 1 )*RGB( X, Y, GREEN ) + 1 )
         MappedRGB( X, Y, BLUE  ) = B#*RGB( X, Y, BLUE  )/( ( B# - 1 )*RGB( X, Y, BLUE  ) + 1 )
         
         If MappedRGB( X, Y, RED   ) > RMax# Then RMax# = MappedRGB( X, Y, RED   ) ElseIf MappedRGB( X, Y, RED   ) < RMin# Then RMin# = MappedRGB( X, Y, RED   )
         If MappedRGB( X, Y, GREEN ) > GMax# Then GMax# = MappedRGB( X, Y, GREEN ) ElseIf MappedRGB( X, Y, GREEN ) < GMin# Then GMin# = MappedRGB( X, Y, GREEN )
         If MappedRGB( X, Y, BLUE  ) > BMax# Then BMax# = MappedRGB( X, Y, BLUE  ) ElseIf MappedRGB( X, Y, BLUE  ) < BMin# Then BMin# = MappedRGB( X, Y, BLUE  )
      Next
   Next
End Function

Function AddFunction( FA#, FB#, FC#, FD#, FE#, FF#, FWeight# )
   F( FunctionCount, RED   ) = Rnd( 0, 1 )
   F( FunctionCount, GREEN ) = Rnd( 0, 1 )
   F( FunctionCount, BLUE  ) = Rnd( 0, 1 )
   F( FunctionCount, FACTOR_A ) = FA#
   F( FunctionCount, FACTOR_B ) = FB#
   F( FunctionCount, FACTOR_C ) = FC#
   F( FunctionCount, FACTOR_D ) = FD#
   F( FunctionCount, FACTOR_E ) = FE#
   F( FunctionCount, FACTOR_F ) = FF#
   F( FunctionCount, WEIGHT ) = FWeight#
   
   FunctionCount = FunctionCount + 1
   AccWeight# = AccWeight# + FWeight#
End Function

Function SetFunctionColor( FunctionIndex, R, G, B )
   F( FunctionIndex, RED   ) = R/255.
   F( FunctionIndex, GREEN ) = G/255.
   F( FunctionIndex, BLUE  ) = B/255.
End Function

Function SetFunctionBlending( FunctionIndex, Variation, BlendFactor# )
   F( FunctionIndex, Variation + 10 ) = BlendFactor#
End Function


Da die Funktionen alle zufällig angewandt werden, hat man nicht plötzlich ein fertig gerendertes Bild, sondern nur einen Punktehaufen, der sich mit der Zeit immer weiter verfeinert. Je nach Funktionszusammenstellung ergeben sich verschiedene Berechnungszeiten, bis ein zufriedenstellendes Bild erstellt wurde.
Alle 3 Sekunden wird ein neues Bild gezeichnet, um den aktuellen Fortschritt anzuzeigen - für die folgenden Bilder habe ich je 1-3 Minuten gewartet, bis ich den Screenshot gemacht habe.

Hier einige Beispiele von erstellten Bildern:

user posted image

user posted image

user posted image
  • Zuletzt bearbeitet von Noobody am Mi, Mai 06, 2009 7:41, insgesamt einmal bearbeitet

Nova

BeitragDi, Mai 05, 2009 23:19
Antworten mit Zitat
Benutzer-Profile anzeigen
Faszinierend!

Hast du vielleicht einen deutschen Link der erklärt, wie das funktioniert? Oder könntest du das hier nochmal etwas näher erläutern? Ich würde das zu gerne nachcoden! Smile
AMD Athlon II 4x3,1GHz, 8GB Ram DDR3, ATI Radeon HD 6870, Win 7 64bit

MikeDee

BeitragDi, Mai 05, 2009 23:25
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich verstehe zwar kein Wort, ist ja auch schon spät, aber man, das sieht echt gut gemacht. Seltsamerweiße ist bei jedem Bild bei mir die Grundfarbe blau.
Nicht wenige benutzen die Anonymität des Internets um berühmt zu werden.

Valnar

BeitragMi, Mai 06, 2009 0:13
Antworten mit Zitat
Benutzer-Profile anzeigen
Kannst du evtl. den Trennstrich im Code kleiner machen? Der sprengt bei mir das ganze Design, da er nicht umgebrochen wird!
DANKE!

@Topic: währe ein Cooler Bildschirmschoner, eventuell Bastel ich mir selber mal einen, es gibt dazu ja ne Howto hier.
 

Ava

Gast

BeitragMi, Mai 06, 2009 1:05
Antworten mit Zitat
Besonders das dritte Bild find ich total schön! Das würd ich mir glatt in meinem Zimmer aufhängen Exclamation Rolling Eyes Very Happy

ozzi789

BeitragMi, Mai 06, 2009 7:34
Antworten mit Zitat
Benutzer-Profile anzeigen
Noobody du bist ein Genie Oo
Werd gleich ein wenig dran rumschrauben, obwohl ich nicht viel davon versteh <<


mfg ozzi
0x2B || ! 0x2B
C# | C++13 | Java 7 | PHP 5

Noobody

BeitragMi, Mai 06, 2009 7:59
Antworten mit Zitat
Benutzer-Profile anzeigen
Nova hat Folgendes geschrieben:
Hast du vielleicht einen deutschen Link der erklärt, wie das funktioniert? Oder könntest du das hier nochmal etwas näher erläutern? Ich würde das zu gerne nachcoden!

Auf deutsch leider überhaupt nicht, auf englisch gibt es hier (PDF) eine Dokumentation der Mathematik dahinter, geschrieben vom Erfinder der Fractal Flames. Mit der Doku hatte ich so meine Probleme, weil sie einige Dinge mehrdeutig erklärt, daher weiss ich auch nicht, ob meine Implementation 'richtig' ist Razz
Wenn das auch nicht hilft, werde ich mir heute Abend mal Zeit nehmen und versuchen, das zu erklären.


MikeDee hat Folgendes geschrieben:
Seltsamerweiße ist bei jedem Bild bei mir die Grundfarbe blau.

Die dritte Funktion im Beispiel hat auch eine blaue Farbe, im Code steht ja Code: [AUSKLAPPEN]
SetFunctionColor( 2, 0, 0, 255 )

Entweder, du färbst die Funktion anders ein oder löscht sie ganz, das sollte den Blaustich beheben Wink


Valnar hat Folgendes geschrieben:
Kannst du evtl. den Trennstrich im Code kleiner machen? Der sprengt bei mir das ganze Design, da er nicht umgebrochen wird!

Done.
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun

Chrise

BeitragMi, Mai 06, 2009 14:21
Antworten mit Zitat
Benutzer-Profile anzeigen
Ach wie geil ist das denn oO
Wofür mit Bildbearbeitungsprogrammen aufwendig irgendwelche Bilder herstellen, wenns auch einfach mit einem Code geht, den Noobody bestimmt mal wieder einfach so nebenbei geschrieben hat?^^
Programmier doch gleich ein Bildbearbeitungsprogramm, vielleicht findest du mal Sonntags Nachmittag - so ganz nebenbei Wink - Zeit.

Also dir kommt allmählich keiner mehr in Sachen Speed und Codeneuheiten mehr nach. Weiter so, deine Arbeiten sind Spitze und schön anzusehen!
Llama 1 Llama 2 Llama 3
Vielen Dank an Pummelie, der mir auf seinem Server einen Platz für LlamaNet bietet.

hectic

Sieger des IS Talentwettbewerb 2006

BeitragMi, Mai 06, 2009 15:01
Antworten mit Zitat
Benutzer-Profile anzeigen
Genau genommen ist es eine in die dritte Dimension verdrehte zweidimensionale Fläche. Oder sehe ich das falsch?
Wenn man nun die zweidimensionale Fläche in nur einer Dimension zeichnet und die zweite Dimension in die Zeit streckt, bekommt man eine schöne Animation raus. Allerdings sieht das Einzelbild natürlich nicht so gut aus.

Code: [AUSKLAPPEN]
Graphics 400,400,0,2
SetBuffer BackBuffer()

qq#=0
za#=0
x1#=0
y1#=0
x2#=0
y2#=0


While Not KeyHit(1)
   za=za+1
   
   LockBuffer BackBuffer()
   
   For qq=0 To 9999
      x1=Sin(qq/3)/8
      y1=Cos(qq/2)/8
      x2=Sin(qq*x1+za)*(qq+x1)/60
      y2=Cos(qq*y1)*(qq+y1)/60
      WritePixelFast 200+x2,200+y2,14737632
   Next
   
   UnlockBuffer BackBuffer()
   
   Flip
   Cls
Wend
End

Dieser Code stammt noch aus meiner Power-Basic 2.0 -Zeit.
Download der Draw3D2 V.1.1 für schnelle Echtzeiteffekte über Blitz3D

SpionAtom

BeitragMi, Mai 06, 2009 15:09
Antworten mit Zitat
Benutzer-Profile anzeigen
Schöne Sachen das!

Und Schöne Sache hectic. Bei diesen Bildern kann man nie sagen, ob sie links oder rechtsdrehend sind. (Ich kann es halbwegs steuern in welche Richtung ich es haben will, ist ne tolle Konzentrationsübung^^)
os: Windows 10 Home cpu: Intel Core i7 6700K 4.00Ghz gpu: NVIDIA GeForce GTX 1080

NightPhoenix

BeitragMi, Mai 06, 2009 15:41
Antworten mit Zitat
Benutzer-Profile anzeigen
*zustimm* fällt einem doch recht schwer, wenn sich das Hirn erstmal eine Richtung ausgesucht hat Smile tolle Sache Wink
 

aletes

BeitragMi, Mai 06, 2009 16:31
Antworten mit Zitat
Benutzer-Profile anzeigen
gut gemacht
hier mal mein ergebnis:
user posted image

Noobody

BeitragMi, Mai 06, 2009 17:18
Antworten mit Zitat
Benutzer-Profile anzeigen
hectic hat Folgendes geschrieben:
Genau genommen ist es eine in die dritte Dimension verdrehte zweidimensionale Fläche. Oder sehe ich das falsch?

Ganz so einfach ist es nicht Wink
Im Programm selbst wird keine dritte Dimension eingeführt, es wird einfach das zweidimensionale Koordinatensystem durch bestimmte Funktionen verzerrt. Der Grundstamm an Funktionen wird durch AddFunction gestellt. Diese Funktionen bestimmen die Koordinatenachsen des Koordinatensystems; auf den Punkt wird eine sogenannte affine Transformation durchgeführt.
Zusätzlich werden noch Variationsfunktionen auf das Koordinatensystem ausgeführt. Diese Variationen sind nicht-linear und verzerren daher das System so, dass es ähnlich wie 3D aussieht (die Variation VAR_HANDKERCHIEF beispielsweise 'zerknüllt' das Koordinatensystem ähnlich wie ein Taschentuch, wodurch die Bereiche in der Mitte aussehen, als wären sie nach vorne gewölbt).
Dieser 3D - Effekt wird zusätzlich noch dadurch verstärkt, dass gewisse Teile des Fraktals vor anderen gezeichnet werden, was durch die Dichteverteilung erreicht wird, die die Farbgebung eines bestimmten Pixels bestimmt. Das anschliessend angewandte Tonemapping tut auch noch seinen Teil (wobei ich hier auf den eher simpleren Schlick-Operator zurückgegriffen habe, wodurch leider die Farbqualität verringert wird; andere Verfahren wären wohl zu rechenintensiv).

Es ist also keine in 3D gewölbte Fläche, sondern ein verzerrtes Koordinatensystem - der 3D Effekt ist aber durchaus erwünscht, weswegen die Variationsfunktionen überhaupt ausgeführt werden.
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun

Neue Antwort erstellen


Übersicht BlitzBasic Codearchiv

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group