If you're seeing this message, it means we're having trouble loading external resources on our website.

Ha webszűrőt használsz, győződj meg róla, hogy a *.kastatic.org és a *.kasandbox.org nincsenek blokkolva.

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!
Kép a Nature of Code-ból
1.5. ábra: Zaj
Ezzel szemben viszont a következő ábra tiszta véletlenszámokat ábrázol az idő függvényében.
Kép a Nature of Code-ból
1.6. ábra: Véletlenszámok
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, azaz
var 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
00,469
0,010,480
0,020,492
0,030,505
0,040,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.
Zaj az idő függvényében
1,7. ábra
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.
Kép a Nature of Code-ból
I.8. ábra
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.
Kép a Nature of Code-ból
I.9. ábra
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.
Tudsz angolul? Kattints ide, ha meg szeretnéd nézni, milyen beszélgetések folynak a Khan Academy angol nyelvű oldalán.