Kirjautuminen

Haku

Tehtävät

Oppaat: Grafiikka: Noise-algoritmit

Kirjoittaja: peki. Vuosi: 2004.

Noise-algoritmeilla luodaan nimensä mukaan erilaista kohinaa. Erilaisilla algoritmeilla luodaan erilaista kohinaa. Ehkä tunnetuin näistä algoritmeista on Perlin noise -algoritmi. Kerron sen toiminnasta ensiksi.

Algoritmeja voidaan käyttää luonnollisina tekstuureina, kun yhdistetään peruskohina erilaisiin matemaattisiin kaavoihin. Toisin kuin perinteiset tekstuurit, nämä tekstuurit eivät tarvitse mitään valmiiksi piirrettyä kuvaa. Ne luodaan tyhjästä ennen itse ohjelman tai demon pääsilmukan käynnistymistä. Tekstuurit voidaan myöskin kartoittaa suoraan kolmiulotteisen objektin pinnalle. Tämä siksi, että kaavaa jolla "melu" luodaan voidaan muokata tarpeen mukaan transformoimaan pikselit valmiiksi kolmiulotteiseen avaruuteen sopiviksi.

Perlin noise

Kuvaus

Tämä funktio (selitän myöhemmin, miksi se ei ole algoritmi) on todennäköisesti tutuin kohina-algoritmi. Se tuottaa kuvan, joka muistuttaa pilviä. Se perustuu interpolatioon. Tässä esimerkissä sovellamme kosini-interpolointia. Se on mielestäni soveltuvin tähän funktioon. On olemassa myös uskomattoman monimutkainen cubic interpolation -kaava. Se antaa hieman paremman tuloksen, mutta tässä eroa ei edes huomaa. Cubic interpolation on myös hidas.

Kosini-interpolointi

Perusinterpolointifunktio ottaa kolme parametriä: a:n ja b:n arvot, sekä x:n arvon, joka on väliltä 0 ja 1. Interpolointifunktio palauttaa arvon valiltä a ja b painotettuna arvolla x.

Perusinterpolointi

Kun interpolointia terästetään kosinilla saadaan rumien pisteiden välille vedettyjen viivojen sijaan kauniita luonnollisia käyriä.

KosiniInterpolointi(a, b, x)
{
    ft = x * pi
    f = (1 - cos(ft)) * .5

    return  a * (1 - f) + b *f
 }

Pehmennetty melu

Vaikka käytämme interpolointia, on hyvä silti hieman pehmentää melua. Silloin se ei näytä niin "arvotulta". Silloin se ei myöskään näytä niin neliömäiseltä 2D- ja 3D-versioissa. Jos olet koskaan kirjoittanut pehmennysfiltterin, tämä on sinulle lastenleikkiä.

Otamme siis viereisten pikselien värien keskiarvon ja asetamme sen tutkittavan pikselin väriksi.

Pehmenna(x, y)
{
    nurkat = (Noise(x - 1, y - 1) + Noise(x + 1, y - 1) + Noise(x - 1, y + 1) + Noise(x + 1, y + 1)) / 16
    sivut  = (Noise(x - 1, y) + Noise(x + 1, y) + Noise(x, y - 1) + Noise(x, y + 1)) / 8
    keskus = Noise(x, y) / 4

    return nurkat + sivut + keskus
}

Laittakaamme kaikki yhteen

Nyt tiedämme kaiken oleellisen, joten voimme alkaa miettiä itse Perlin's noisen toteutusta. Perlin's noise ei ole algoritmi, sillä se on vain useiden interpoloitujen melujen yhdistymä. Sille annetaan yksi tai useampi parametri, ja se palauttaa arvon. Se on siis funktio.

Oletetaan, että Noise taulukko sisältää arvottuja arvoja väliltä -1 ja 1.

PehmennaMelu(x as double, y as double)
{
    nurkat = (Noise(x - 1, y - 1) + Noise(x + 1, y - 1) + Noise(x - 1, y + 1) +
       Noise(x + 1, y + 1 )) / 16
    sivut  = (Noise(x - 1, y) + Noise(x + 1, y) + Noise(x, y - 1) + Noise(x, y + 1)) / 8
    keskus = Noise(x, y) / 4

    return nurkat+sivut+keskus
}
KosiniInterpolointi(a, b, x)
{
    // kerrotaan piillä x eli parametri, joka kertoo kumpaa (a, b) lähellä pitää palautusarvon olla
    ft = x * pi
    // otetaan kosini mukaan
    f = (1 - cos(ft)) * .5

    // palautetaan interpolointi
    return  a * (1 - f) + b * f
 }

InterpoloituMelu(x as double, y as double)
 {
      // uämä sisältää double muuttujan x muutettuna integer muotoon
      integer_X = int(x)
      // tämä on sopiva arvo, joka syötetään interpolointifunktiolle
      // (koska x = double ja integer_x = integer, niin desimaaliosa jää jäljelle)
      fractional_X = x - integer_X

      // sama kuin äskeinen, mutta y -koordinaatille
      integer_Y    = int(y)
      fractional_Y = y - integer_Y

      // haetaan ja pehmennetään melu "lähipikseleissä"
      v1 = PehmennaMelu(integer_X,     integer_Y)
      v2 = PehmennaMelu(integer_X + 1, integer_Y)
      v3 = PehmennaMelu(integer_X,     integer_Y + 1)
      v4 = PehmennaMelu(integer_X + 1, integer_Y + 1)

      // interpoloidaan, jotta saadaan aikaan tasainen väriliuku(x-akseli)
      i1 = KosiniInterpolointi(v1, v2, fractional_X)
      i2 = KosiniInterpolointi(v3, v4, fractional_X)

      // interpoloidaan vielä kerran(y-akseli)
      return KosiniInterpolointi(i1, i2, fractional_Y)
}

PerlinNoise_2D(x as double, y as double)
{
      kaikki= 0
      // seuraavalle en löytänyt kunnon sanaa (kokeile muuttaa tätä ja katso tulosta)
      p = pysyvyys
      n = Oktaavien määrä - 1

      for i 0:sta n:ään
          // taajuudeksi kahden i. potenssi
          taajuus = 2 ^ i
          // amplitudiksi p:n i. potenssi
          amplitudi = p ^ i
          // lisätään tulos pikselin maksimiarvoon, sinun tehtäväksesi jää varmistaa,
          // että kaikki on sallittujen väriarvojen sisäpuolella
          kaikki += InterpoloituMelu(x * taajuus, y * taajuus) * amplitudi
      next
      return total
}

Nyt meillä pitäisi olla kaunis pilvimaisema.

Valmis VB.NET-esimerkki (ilman pehmennystä ja hieman eri tavalla toteutettuna) löytyy Putkasta täältä. Lähdemateriaalina on käytetty tätä sivua.

Fault noise

Kuvaus

Tämä algoritmi on erittäin raskas, vaikka onkin yksinkertainen. Se perustuu siihen, että tason läpi vedetään viiva. Tämän jälkeen viivan toisella puolella olevia pisteitä vaalennetaan ja toisella puolella olevia tummennetaan. Kun tämä toistetaan riittävän monta kertaa, saadaan aikaan kaunis kuva.

Matematiikka

Matemaattiselta kannalta meidän täytyy tuntea ainoastaan suoran yhtälö, ja osata leikkiä sillä.

y = kx + b muuntuu muotoon ax + by + c = 0.

Arvomme suoralle kulmakertoimen ja vakion.
// kulmakertoimen kulma v = rnd * 2 * pi
d = sqrt(ruudunleveys * ruudunleveys + ruudunkorkeus * ruudunkorkeus)
// kulmakerroin x:lle
a = sin(v)
// kulmakerroin y:lle
b = cos(v)
// c:stä saadaan arvottu numero väliltä -d / 2 ja d / 2 (d = halkaisija)
c = rnd * d - d / 2

Toteutus

Meidän on kelattava kaikki ruudulla näkyvät pikselit ja tutkittava, kummalla puolella suoraa pikseli on. Tehdään tämä 500 kertaa.

d = sqrt(ruudunleveys * ruudunleveys + ruudunkorkeus * ruudunkorkeus)
for i = 1 to 500
    // arvotaan uusi suora
    v = rnd * 2 * pii
    a = sin(v)
    b = cos(v)
    c = rnd * d - d / 2
    for x = 0 to ruudunleveys
        for y = 0 to ruudunkorkeus
            // meidän on muutettava suoran yhtälöä saadaksemme aikaan kauniin kuvan,
            // muutetaan ax + by + c -> ax + by - c
            if (a*x + b*y - c > 0)
                // vaalealla puolella
                clr = getPixel(x,y)
                clr += korotus
                setPixel(x,y) värillä crl
            else
                // tummalla puolella
                lr = getPixel(x,y)
                clr -= korotus
                setPixel(x,y) värillä crl
        next
    next
next

Nyt meillä pitäisi olla kaunis melukartta.

Valmis VB.NET esimerkki löytyy Putkasta täältä.

Pekka Järvinen, 30.4.2004

Kirjoita kommentti

Huomio! Kommentoi tässä ainoastaan tämän oppaan hyviä ja huonoja puolia. Älä kirjoita muita kysymyksiä tähän. Jos koodisi ei toimi tai tarvitset muuten vain apua ohjelmoinnissa, lähetä viesti keskusteluun.

Muista lukea keskustelun ohjeet.
Tietoa sivustosta