Das deutsche QBasic- und FreeBASIC-Forum Foren-Übersicht Das deutsche QBasic- und FreeBASIC-Forum
Für euch erreichbar unter qb-forum.de, fb-forum.de und freebasic-forum.de!
 
FAQFAQ   SuchenSuchen   MitgliederlisteMitgliederliste   BenutzergruppenBenutzergruppen  RegistrierenRegistrieren
ProfilProfil   Einloggen, um private Nachrichten zu lesenEinloggen, um private Nachrichten zu lesen   LoginLogin
Zur Begleitseite des Forums / Chat / Impressum
Aktueller Forenpartner:

mit "PerlinNoise"-Function ein 2D-Array füllen

 
Neues Thema eröffnen   Neue Antwort erstellen    Das deutsche QBasic- und FreeBASIC-Forum Foren-Übersicht -> Allgemeine Fragen zu FreeBASIC.
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen  
Autor Nachricht
Ice



Anmeldungsdatum: 15.02.2014
Beiträge: 4

BeitragVerfasst am: 25.03.2014, 22:03    Titel: mit "PerlinNoise"-Function ein 2D-Array füllen Antworten mit Zitat

Hallo zusammen,
ich versuche im Moment eine sogenannte Tilemap mithilfe der PerlinNoise Funktion zu erstellen.

Fürs besser Verständnis gehe ich jetzt einfach mal der Reihe nach durch:

Ohne PerlinNoise, mit "normalen" Zufallszahlen klappt es ganz gut, eine Tilemap zu erstellen.
Der Folgende Code füllt mir ein 2-dimensionales Array mit Zufallszahlen und lädt anhand der zufälligen Zahlen entweder die gras.bmp oder erde.bmp nebeneinander und untereinander auf der Bildschirm, sodass eine zufällige "Karte" ensteht.

Code:

DIM array(60, 60) AS DOUBLE
DIM erde AS any ptr
DIM gras AS any ptr

Screen 18,24,2,0

RANDOMIZE

FOR y AS INTEGER = 0 TO 31

FOR x AS INTEGER = 0 TO 42
    array(x, y) = RND*2
    IF array(x, y) <= 0.4 THEN
       
    erde = IMAGECREATE (16,16)
    BLOAD "erde.bmp", 0
    GET (0,0)-(15,15), erde
    PUT (x*15, y*15), erde, PSET         
 
    ELSE
   
    grass = Imagecreate (16,16)
    BLOAD "gras.bmp", 0
    GET (0,0)-(15,15), gras
    PUT (x*15, y*15), gras, PSET
   
    END IF
   
NEXT

NEXT



Das Problem, mit dieser "Zufallskarte" ist allerdings zunächst, dass sie keine "logisch" zusammenhängenden Flächen aufweist, da die Punkte wirklich komplett zusammenhangslos verteilt werden Kopf schütteln

An dieser Stelle kommt "PerlinNoise" ins Spiel.

Deswegen habe ich ein paar Tage recherchiert und unter anderem folgenden FreeBasic-Code für eben jenes PerlinNoise gefunden (bei Rückfragen dazzu am besten googeln, da ich selber das Prinzip erst so halbwegs verstanden habe):


Code:
dim as integer screen_width = 800, screen_height = 600
screenres screen_width, screen_height, 32, 0, 0

function Interpolate(i as single, j as single, k as single) as single
   return (1-k)*i + k*j
end function

function Noise(x as integer, y as integer) as single
   dim as integer n
   n = x + y * 57
   n = (n shl 13) xor n
   return (1.0 - ( (n * (n * n * 15731 + 789221) + 1376312589) and &H7fffffff) / 1073741824.0)
end function

function SmoothNoise(x as integer, y as integer) as single
   dim as single corners, sides, center
   corners = (Noise(x-1, y-1) + Noise(x+1, y-1) + Noise(x-1, y+1) + Noise(x+1, y+1) ) / 16
   sides   = (Noise(x-1, y) + Noise(x+1, y) + Noise(x, y-1) + Noise(x, y+1) ) /  8
   center  =  Noise(x, y) / 4
   return corners + sides + center
end function

function InterpolatedNoise(x as single, y as single) as single
   dim as integer integer_X, integer_Y
   dim as single v1, v2, v3, v4, i1, i2, fractional_X, fractional_Y
   integer_X    = int(x)
   fractional_X = x - integer_X
   integer_Y    = int(y)
   fractional_Y = y - integer_Y
   v1 = SmoothNoise(integer_X,     integer_Y)
   v2 = SmoothNoise(integer_X + 1, integer_Y)
   v3 = SmoothNoise(integer_X,     integer_Y + 1)
   v4 = SmoothNoise(integer_X + 1, integer_Y + 1)
   i1 = Interpolate(v1 , v2 , fractional_X)
   i2 = Interpolate(v3 , v4 , fractional_X)
   return Interpolate(i1 , i2 , fractional_Y)
end function

function PerlinNoise(x as single,y as single) as single
   dim as single frequency, amplitude
   dim as single total = 0
   dim as single p = 1 'persistence
   dim as integer n = 10 ' Number_Of_Octaves
   for i as integer = 1 to n
      frequency = 2*i
      amplitude = p/i
      total = total + InterpolatedNoise(x * frequency, y * frequency) * amplitude
   next i
   return total
end function

for i as integer = 0 to screen_width-1
   for j as integer = 0 to screen_height-1
      dim as Single PN = (PerlinNoise(i/16,j/16) + 1)/2
      pset (i,j), RGB(PN * 255, PN * 255, PN * 255)
   next j
next i


Dieser Code funktioniert an sich und zeichnet mit der letzten "for i/for j"-Schleife folgendes auf den Bildschirm:
Also ganz in dem Sinne, wie PerlinNoise aussehen soll!

So, lange Rede und kaum kein Sinn mit den Augen rollen

Hat jemand eine Idee, wie ich die Werte, die mir "function PerlinNoise" berechnet, anstatt als Zeichnung in ein zweidimensionales Array einbinden kann? Damit ich anschließend wieder, wie gehabt, durch IF...THEN bestimmten Wertebereichen eine *.bmp zuweisen und anschließend laden kann?

Wenn ich das richtig verstehe, müsste "function PerlinNoise" ja bloß immer einen zufälligen Endwert "total" berechnen, oder?
Wie rufe ich den Wert in meinem anfänglichen Code auf?


Oder bin ich mit meinem zweidimensionalen Array hierbei völlig auf dem Holzweg?? Ich bin sehr gespannt auf eure Rückmeldungen!

Beste Grüße
Ice
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
ThePuppetMaster



Anmeldungsdatum: 18.02.2007
Beiträge: 1839
Wohnort: [JN58JR]

BeitragVerfasst am: 25.03.2014, 22:53    Titel: Antworten mit Zitat

vielleicht gibt das den richtigen denk-anstoss zwinkern

Code:

'...
for i as integer = 0 to screen_width-1
   for j as integer = 0 to screen_height-1
      dim as Single PN = (PerlinNoise(i/16,j/16) + 1)/2
      Print i; "x"; j; "="; PN * 255
   next j
next i



MfG
TPM
_________________
[ WebFBC ][ OPS ][ ToOFlo ][ Wiemann.TV ]
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
Ice



Anmeldungsdatum: 15.02.2014
Beiträge: 4

BeitragVerfasst am: 25.03.2014, 23:28    Titel: Antworten mit Zitat

Allerdings!! 1 to screenwidth war zwar ein bisl heftig, aber bis 50 reichte mir auch schon zwinkern

Besten Dank, nun läufts schonmal! lächeln

(Jetzt tun sich gleich andere Probleme auf mit Feintuning und jedesmal zufälliger Erstellung vom Noise, aber das ist eine andere Geschichte und ein anderer Programmierabend happy )
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
ThePuppetMaster



Anmeldungsdatum: 18.02.2007
Beiträge: 1839
Wohnort: [JN58JR]

BeitragVerfasst am: 25.03.2014, 23:48    Titel: Antworten mit Zitat

Aber, um ne relativ "smoothe" karte zu erzeugen kannst du eigentlich auch recht einfach vorgehen. Dafür erzeugst du einfach eine rauschende Karte (rnd * 255), und legst darüber dann einen weichzeichner.

Die "körnigkeit" beeinflust du durch die Art des rauschens. z.B. Pixel rnd's, circle rnd's, rect Rnd's, ...

Code:

pset, map, ((int(rnd() * breite), int(rnd() * höhe)), int(rnd() * 255)
circle, map, ((int(rnd() * breite), int(rnd() * höhe)), int((rnd() * maxkreisbreite) + 1), int(rnd() * 255)
'...


je gröser die monofarbenen flächen, desto smoother wirds. je kleiner, desto gröber.
zum schluss den weichzeichner grüber, und fertig isses.



MfG
TPM
_________________
[ WebFBC ][ OPS ][ ToOFlo ][ Wiemann.TV ]
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
Haubitze



Anmeldungsdatum: 14.10.2009
Beiträge: 132

BeitragVerfasst am: 26.03.2014, 00:59    Titel: Antworten mit Zitat

Hi Ice,

du koenntest ja deine function

Code:

function Noise(x as integer, y as integer) as single
   dim as integer n
   n = x + y * 57
   n = (n shl 13) xor n
   return (1.0 - ( (n * (n * n * 15731 + 789221) + 1376312589) and &H7fffffff) / 1073741824.0)
end function


um einen parameter erweitern der den seed angiebt somit kannst du immer genau die selbe karte erstellen

Code:

function Noise(x as integer, y as integer,seed as uinteger) as single
   dim as integer n
   n = x + y * 57+seed
   n = (n shl 13) xor n
   return (1.0 - ( (n * (n * n * 15731 + 789221) + 1376312589) and &H7fffffff) / 1073741824.0)
end function


auswerten wuerd ich das wie ThePuppetMaster in seiner ersten antwort schrieb

Code:

...
dim as Single PN = ((PerlinNoise(i/16,j/16) + 1)/2)*255

...
select case PN
    case 1 to 10
             DrawTile(ERDE)
    case 11 to 200
             DrawTile(WASSER)
...
...



Salute
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
Ice



Anmeldungsdatum: 15.02.2014
Beiträge: 4

BeitragVerfasst am: 26.03.2014, 09:25    Titel: Antworten mit Zitat

Puppet Master, meinst du mit Weichzeichner einen im Grafikprogramm?
Das würde dann allerdings nicht weiterhelfen, weil es mir ja darum geht, Zahlenwerte mit Noise zu versehen und nicht einfach ein rauschendes Bild zu erstellen... lächeln

Haubitze, klingt gut mit dem seed!
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
ThePuppetMaster



Anmeldungsdatum: 18.02.2007
Beiträge: 1839
Wohnort: [JN58JR]

BeitragVerfasst am: 26.03.2014, 12:25    Titel: Antworten mit Zitat

Nun ... so wie ich das verstanden habe, willst du ne map erstellen. eine "random" map, die du erneut erzeugen kannst. Das kann man durchaus so machen. Mit randomize(<wert>) kann man einen startwert festlegen, mit dessen hilfe sich diese "zufallskarte" immer wieder erzeugen lässt.

Weichzeichner: Jain .. also .. das prinzip is wie bei nem grafik-prog, nur das du es halt in deinem programm automatisiert machst, um den "smoothness" zu erzeugen.


MfG
TPM
_________________
[ WebFBC ][ OPS ][ ToOFlo ][ Wiemann.TV ]
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
RockTheSchock



Anmeldungsdatum: 04.04.2007
Beiträge: 138

BeitragVerfasst am: 26.03.2014, 17:51    Titel: Map Generator Antworten mit Zitat

Schau dir mal diesen MapGenerator an bzw. die Weiterentwicklung davon. Die Maps sehen sehr realistsisch aus. Könnte das was für dich sein? Wir könnten versuchen das zusammen zu portieren, wenn du so etwas in der Art haben möchtest

http://forums.civfanatics.com/showthread.php?t=310891
http://samiam.org/civ4/Totestra/Totestra.py

Wir müssten aber wahrscheinlich erst fragen, ob wir das dürfen.
http://forums.civfanatics.com/showthread.php?t=310891&page=38
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
Ice



Anmeldungsdatum: 15.02.2014
Beiträge: 4

BeitragVerfasst am: 27.03.2014, 11:29    Titel: Antworten mit Zitat

Puuh, ganz schön viel Code für die Civ-Maps ... zwinkern

Das kreiert natürlich super Weltkarten! Für meine Zwecke und fürn Anfang will ich eher Karten von "Gebieten" (im Stile von zB. AoE/AoE2) als von ganzen Kontinenten erzeugen. Also ein paar zusammenhängende Wälder, Seen und Berge reichen schon lächeln

Edit: Echt hammer wie die PerfectWorld Generatoren sogar berücksichtigen, dass hohe Berge den Niederschlag abfangen und auf der anderen Seite dadurch Trockengebiete entstehen!
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
Muttonhead



Anmeldungsdatum: 26.08.2008
Beiträge: 565
Wohnort: Jüterbog

BeitragVerfasst am: 27.03.2014, 12:39    Titel: Antworten mit Zitat

http://www.freebasic-portal.de/porticula/bumpmap-rekursiv-564.html
ich kann mich noch an dieses rekursivmonster von mir erinnern
grinsen

Mutton
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
Beiträge der letzten Zeit anzeigen:   
Neues Thema eröffnen   Neue Antwort erstellen    Das deutsche QBasic- und FreeBASIC-Forum Foren-Übersicht -> Allgemeine Fragen zu FreeBASIC. Alle Zeiten sind GMT + 1 Stunde
Seite 1 von 1

 
Gehe zu:  
Du kannst keine Beiträge in dieses Forum schreiben.
Du kannst auf Beiträge in diesem Forum nicht antworten.
Du kannst deine Beiträge in diesem Forum nicht bearbeiten.
Du kannst deine Beiträge in diesem Forum nicht löschen.
Du kannst an Umfragen in diesem Forum nicht mitmachen.

 Impressum :: Datenschutz