Fő tartalom
Perlin zaj
Egy jó véletlenszám-generátor egymástól független, semmilyen mintázatot nem mutató számokat generál. Ahogy kezdünk belelátni, egy kis véletlenszerűség jól jön akkor, amikor organikus, életszerű viselkedést modellezünk. Ugyanakkor pusztán a véletlenszerűség nem mindig természetes.
Létezik egy algoritmus, a „Perlin zaj”, ami természetesebb eredményt ad. Ken Perlin kifejlesztett egy zaj funkciót, amikor az eredeti Tron filmen dolgozott az 1980-as évek elején; arra használta, hogy a számítógéppel generált effektekhez procedurális textúrát készítsen. 1997-ben munkájáért Perlin elnyerte az Oscar Műszaki díjat. A Perlin zaj felhasználásával természetesnek tűnő effektek generálhatók, például felhők, tájképek, vagy olyan felület-minták, mint például a márvány.
A Perlin zaj természetesebbnek tűnik, mert pszeudo-random számok rendezett (kis mértékben változó) szekvenciája. A lenti grafikon Perlin zajt ábrázol az idő függvényében (az időt az x-tengely fejezi ki). Figyeld meg a görbe egyenletességét!
Ezzel szemben viszont a következő ábra tiszta véletlenszámokat ábrázol az idő függvényében.
A ProcessingJS-ben van egy beépített függvény a Perlin zaj algoritmusának implementációjára: a
noise()
. A noise()
függvénynek egy, két vagy három bemeneti paramétere van, mivel a zajt egy, két vagy három dimenzióban tudja számolni. Kezdjük az egydimenziós zajjal!Noise - részletek
A noise leírásából megtudjuk, hogy a zaj több „oktávban” számolható. A
noiseDetail()
függvény meghívásával megváltoztatható mind az oktávok száma, mind az oktávok egymáshoz viszonyított fontossága. Ezzel módosítani lehet a noise függvény működését.Tegyük fel, hogy kört rajzolunk a ProcessingJS ablakba egy véletlen x pozícióba.
var x = random(0, width);
ellipse(x, 180, 16, 16);
Most a véletlen x pozíció helyett Perlin zaj szerinti „enyhébb” x helyzetet szeretnénk. Azt gondolnánk, hogy elég a
random()
függvényt a noise()
függvénnyel helyettesíteni, azazvar x = noise(0, width);
ellipse(x, 180, 16, 16);
Bár elvileg pont ezt akarjuk csinálni - kiszámítani egy 0 és1 közé eső x értéket a Perlin zaj alapján - de nem ez a jó megoldás. A
random()
függvény bemeneti paraméterei egy minimum és egy maximum közötti tartományt határoznak meg, de a noise()
függvény nem így működik. A noise()
egy olyan bemeneti paramétert vár, ami „egy időpillanatot” határoz meg, és mindig 0 és 1 közötti számot ad vissza. Az egydimenziós Perlin zajt úgy képzelhetjük el, mint zajértékek lineáris sorozatát az időben. Például itt látható a bemeneti és a hozzátartozó kimeneti értékek listája:Idő | Zajérték |
---|---|
0 | 0,469 |
0,01 | 0,480 |
0,02 | 0,492 |
0,03 | 0,505 |
0,04 | 0,517 |
Ahhoz, hogy egy zajértéket kapjunk a ProcessingJS-ben, át kell adnunk egy adott időpontot a
noise()
függvénynek. Például:var n = noise(0.03);
A fenti táblázat alapján a
noise()
a 0,505-öt fogja visszaadni a 0,03 időponthoz. Írhatunk egy programot, ami tárol egy idő változót, és folyamatosan kér egy zaj értéket a draw()
függvényhez.A fenti kód mindig ugyanazt a számot írja ki. Ez azért történik, mert a
noise()
függvényt mindig ugyanazzal az idő paraméterrel hívjuk meg.Ha növeljük a
t
időváltozót, akkor más eredményt kapunk. (A programban található megjegyzések: 1. sor: Dan Shiffman, natureofcode.com példája alapján; 8. sor: Előrehaladunk az időben.)A
t
növekedésének nagysága is befolyásolja a zajértékek változását. Ha nagyokat ugrunk az időben, akkor sokat hagyunk ki, és az értékek véletlenszerűbbek lesznek.Próbáld meg többször lefuttatni a kódot úgy, hogy a t változót 0,01-el, 0,02-vel, 0,05-tel, 0,1-el, 0,0001-el növeled: minden esetben más eredményt fogsz kapni.
A zaj leképezése
Most már készen vagyunk arra, hogy válaszoljunk arra a kérdésre: mit kezdjünk a zajértékkel? Ha megkapunk egy 0 és 1 közötti értéket, a mi dolgunk az, hogy hozzárendeljük egy megfelelő tartományhoz.
Megtehetnénk, hogy megszorozzuk az értéktartomány felső határértékével, de ez most jó alkalom arra, hogy bemutassuk a ProcessingJS
map()
függvényét, ami majd a későbbiekben több esetben is kapóra fog jönni. A map()
függvénynek öt paramétere van. Az első az az érték, amit le akarunk képezni, ebben az esetben ez n
. Azután meg kell adni a konvertálandó értékhez tartozó értéktartományt (minimumot és maximumot), majd az új értékhez tartozó értéktartományt. Ebben az esetben tudjuk, hogy a zaj értéke 0 és 1 közé esik, de most egy olyan négyszöget szeretnénk rajzolni, melynek szélessége 0 és a jelenlegi szélesség között van. (A programban található megjegyzések: 1. Dan Shiffman, natureofcode.com példája alapján, 8. Használjuk a map() függvényt a Perlin zaj értéktartományának módosítására)
Ugyanezt a logikát alkalmazhatjuk a véletlen bolyongónkra is oly módon, hogy mind az x, mind pedig az y koordinátát a Perlin zaj alapján határozzuk meg. (A programban található megjegyzések: 1. Dan Shiffman, natureofcode.com példája alapján; 15. véletlenszerűen mozgunk fel, le, jobbra, balra, vagy maradunk egy helyben; 20. megyünk előre az „időben”.)
Figyeld meg, hogy a fenti példához két új változóra van szükség:
tx
és ty
. Ennek az az oka, hogy meg kell őrizni a két időváltozót a Walker
(bolyongó) objektum x és y helyzetének tárolására.De valami furcsát figyelhetünk meg a két változóval kapcsolatban. Miért indul
tx
0-nál és ty
10 000-nél? Ez a két szám tetszőleges, de az időváltozóinkat tudatosan nagyon eltérő értékekkel inicializáltuk. Ez azért történt így, mert a noise függvény determinisztikus: egy adott t
értékre mindig ugyanazt az eredményt adja vissza. Ha az x
-re is és az y
-ra is ugyanazt a t
időpontot adtuk volna meg, akkor x
és y
mindig ugyanazt az értéket kapja, ami azt jelentette volna, hogy a Walker
objektum (a bolyongó) mindig átlósan ment volna. Ehelyett az időskála két szakaszát használtuk, x
esetében 0-tól indultunk, y
-nál 10 000-től, így x
és y
egymástól függetlennek látszanak.Igazság szerint itt nem igazán az időről van szó. Ez csupán egy hasznos metafora, segít megérteni, hogyan működik a noise függvény, de igazából itt inkább térről, mint időről van szó. A fenti ábra zajértékek lineáris sorozatát mutatja az egy dimenziós térben, és bármikor tetszés szerint lekérdezhetünk egy adott x értékhez tartozó zajértéket. Példákban gyakran látni
xoff
nevű változót, ami arra utal, hogy ez a változó a zaj függvény egy adott kiindulópontja (offset), nem egy adott t
időpont (mint ahogy az ábrán jelöltük).A következő feladatban egy kicsit másképpen fogod a zajt használni a
Walker
(bolyongó) megvalósításához. Jó szórakozást!Ez a „Természetes szimulációk" tananyag a Daniel Shiffman által készített „The Nature of Code” alapján készült, a Creative Commons Attribution-NonCommercial 3.0 Unported License szerint.
Szeretnél részt venni a beszélgetésben?
Még nincs hozzászólás.