Perlin-ljud

Tvådimensionell skiva genom 3D Perlin-brus vid z=0

Perlin-brus är en typ av gradientbrus som utvecklades av Ken Perlin 1983. Det har många användningsområden, inklusive men inte begränsat till: procedurgenerering av terräng , applicering av pseudo-slumpmässiga förändringar på en variabel och hjälp med att skapa bildtexturer . Det är oftast implementerat i två, tre eller fyra dimensioner , men kan definieras för valfritt antal dimensioner.

Historia

Ken Perlin utvecklade Perlin-brus 1983 som ett resultat av sin frustration över det "maskinlika" utseendet av datorgenererade bilder (CGI) vid den tiden. Han beskrev formellt sina upptäckter i en SIGGRAPH -tidning 1985 kallad An Image Synthesizer . Han utvecklade den efter att ha arbetat på Disneys datoranimerade sci-fi- film Tron (1982) för animationsföretaget Mathematical Applications Group (MAGI) . År 1997 tilldelades Perlin en Oscar för teknisk prestation för att ha skapat algoritmen, vars citat löd:

Till Ken Perlin för utvecklingen av Perlin Noise, en teknik som används för att producera naturliga texturer på datorgenererade ytor för visuella effekter för rörliga bilder. Utvecklingen av Perlin Noise har gjort det möjligt för datorgrafiker att bättre representera komplexiteten hos naturfenomen i visuella effekter för filmindustrin.

Perlin ansökte inte om några patent på algoritmen, men 2001 beviljades han patent för användning av 3D+-implementeringar av simplexbrus för textursyntes . Simplex brus har samma syfte, men använder ett enklare utrymmesfyllande rutnät. Enkelt brus lindrar en del av problemen med Perlins "klassiska brus", bland annat beräkningskomplexitet och visuellt signifikanta riktningsartefakter.

Används

Ett virtuellt landskap genererat med Perlin-brus

Perlin-brus är en primitiv procedurtextur , en typ av gradientbrus som används av konstnärer med visuella effekter för att öka intrycket av realism i datorgrafik . Funktionen har ett pseudo-slumpmässigt utseende, men alla dess visuella detaljer har samma storlek. Denna egenskap gör att den är lätt att kontrollera; Flera skalade kopior av Perlin-brus kan infogas i matematiska uttryck för att skapa en stor variation av processuella texturer. Syntetiska texturer som använder Perlin-brus används ofta i CGI för att få datorgenererade visuella element – ​​såsom objektytor, eld, rök eller moln – att framstå mer naturliga genom att imitera det kontrollerade slumpmässiga utseendet av texturer i naturen.

En organisk yta genererad med Perlin-brus

Det används också ofta för att generera texturer när minnet är extremt begränsat, till exempel i demos . Dess efterföljare, såsom fraktalbrus och simplexbrus , har blivit nästan allestädes närvarande i grafikbehandlingsenheter både för realtidsgrafik och för procedurtexturer i icke-realtid i alla typer av datorgrafik.

Det används ofta i videospel för att skapa procedurgenererad terräng som ser naturlig ut.

Algoritm detalj

Perlin-brus skalas om och läggas till i sig självt för att skapa fraktalt brus.

Perlin-brus är oftast implementerat som en två-, tre- eller fyrdimensionell funktion , men kan definieras för valfritt antal dimensioner. En implementering innefattar vanligtvis tre steg: definiera ett rutnät av slumpmässiga gradientvektorer, beräkna punktprodukten mellan gradientvektorerna och deras förskjutningar, och interpolation mellan dessa värden.

Grid definition

Ett tvådimensionellt rutnät av gradientvektorer

Definiera ett n -dimensionellt rutnät där varje rutkorsning har associerat med sig en fast slumpmässig n -dimensionell gradientvektor av enhetslängd, förutom i det endimensionella fallet där gradienterna är slumpmässiga skalärer mellan -1 och 1.

Punkt produkt

Punktprodukten för varje punkt med dess närmaste rutnätsnodgradientvärde. Prickprodukten med de andra tre noderna i cellen visas inte.

För att räkna ut värdet av en kandidatpoäng, hitta först den unika rutnätscellen där punkten ligger. Identifiera sedan de hörnen av den cellen och deras associerade gradientvektorer. Beräkna sedan en offsetvektor för varje hörn. En offsetvektor är en förskjutningsvektor från det hörnet till kandidatpunkten.

För varje hörn tar vi punktprodukten mellan dess gradientvektor och offsetvektorn till kandidatpunkten. Denna punktprodukt kommer att vara noll om kandidatpunkten är exakt i rutnätshörnet.

Observera att en gradientvektors inflytande växer med avståndet, vilket kan undvikas genom att normalisera offsetvektorn till en längd av först. Detta skulle införa märkbara skarpa förändringar, förutom att avståndet beaktas i följande interpolationssteg. Normalisering av offsetvektorn är dock inte en vanlig praxis.

För en punkt i ett tvådimensionellt rutnät kommer detta att kräva beräkning av 4 offsetvektorer och punktprodukter, medan det i tre dimensioner kommer att kräva 8 offsetvektorer och 8 punktprodukter. Generellt sett har algoritmen komplexitet , där är antalet dimensioner.

Interpolation

Det slutliga interpolerade resultatet

Det sista steget är interpolation mellan de punktprodukterna. Interpolation utförs med en funktion som har noll förstaderivata ( och möjligen även andraderivata) vid de rutnoderna. Därför, vid punkter nära rutnätsnoderna, kommer utsignalen att approximera punktprodukten av gradientvektorn för noden och offsetvektorn till noden. Detta innebär att brusfunktionen kommer att passera noll vid varje nod, vilket ger Perlin-bruset dess karakteristiska utseende.

Om , ett exempel på en funktion som interpolerar mellan värdet vid rutnätsnod 0 och värdet vid rutnätsnod 1 är

där smoothstep -funktionen användes.

Brusfunktioner för användning i datorgrafik producerar vanligtvis värden i området [-1,0,1,0] och kan skalas därefter.

Genomförande

Följande är en tvådimensionell implementering av Classical Perlin Noise, skriven i C.

Den ursprungliga referensimplementeringen av Perlin hade stora skillnader [ citat behövs ] :

  • det använder en tredimensionell metod genom att interpolera mellan 8 hörn av en kub istället för de 4 hörnen i en kvadrat nedan.
  • den slumpmässiga gradientriktningen blandar bitar av heltalskoordinaterna för hörn, vilket är mycket snabbare än att blanda med interferensen vid hög frekvens av rotationer av heltalskoordinaterna för hörn, slås samman och roteras igen med hög frekvens av en produkt: rotationerna är inte enhetliga distribuerad.
  • Perlins metod delar upp heltalsrymden i 256x256x256 kuber och använder sedan en slumpmässig permutation av dessa kuber för att blanda dem, och sedan tilldelas varje kubpositionshörn en av tolv riktningar till de angränsande icke-permuterade kuberna i ett 4x4x4 beläggningsutrymme: detta kräver enbart beläggningsutrymme. heltalsoperationer men upprätthåller en enhetlig fördelning av riktningar.
  • interpolationsfunktionen är det mjukare 4-graders Smoothersteget (med de tre första derivatorna lika med noll på klämgränserna) och inte det grundläggande linjära steget. Detta undviker synliga artefakter, särskilt längs hörn eller diagonaler som förenar provtagningshörnen, där resultatet skulle vara synligt anisotropt (att färga det önskade vita bruset till rosa brus ; om bruset användes för att generera en solid kristall skulle det inte vara helt svart och ogenomskinlig för ljuset, men delvis genomskinlig och färgad i vissa diskreta observationsriktningar).
 




       
    



           
    







  
      
 



     
    
          
           
          
               
               
      
              
     
         
     



         
    
        

    
         
         

    
       



     
    
       
         
       
         

    
    
         
         

    
         

         
         
        

         
         
        

        
      
 #include  <math.h>  /* Funktion för att linjärt interpolera mellan a0 och a1  *  Vikt w ska vara i intervallet [0.0, 1.0]  */  float  interpolate  (  float  a0  ,  float  a1  ,  float  w )   {  /* // Du kanske vill klämma genom att infoga:  * if (0,0 > w) returnera a0;  * if (1,0 < w) returnera a1;  */  return  (  a1  -  a0  )  *  w  +  a0  ;  /* // Använd denna kubiska interpolation [[Smoothstep]] istället för ett smidigt utseende:  * return (a1 - a0) * (3,0 - w * 2,0) * w * w + a0;  *  * // Använd [[Smootherstep]] för ett ännu jämnare resultat med en andraderivata lika med noll på gränser:  * retur (a1 - a0) * ((w * (w * 6,0 - 15,0) + 10,0) * w * w * w) + aO;  */  }  typedef  struct  {  float  x  ,  y  ;  }  vektor2  ;  /* Skapa pseudoslumpmässig riktningsvektor  */  vektor2  randomGradient  (  int  ix  ,  int  iy  )  {  // Inga förberäknade gradienter betyder att detta fungerar för valfritt antal rutnätskoordinater  const  unsigned  w  =  8  *  sizeof  (  unsigned  );  const  unsigned  s  =  w  /  2  ;  // rotationsbredd  utan tecken  a  =  ix  ,  b  =  iy  ;  a  *=  3284157443  ;  b  ^=  a  <<  s  |  a  >>  w  -  s  ;  b  *=  1911520717  ;  a  ^=  b  <<  s  |  b  >>  w  -  s  ;  a  *=  2048419325  ;  float  slumpmässig  =  a  *  (  3,14159265  /  ~  (  ~  0u  >>  1  ));  // i [0, 2*Pi]  vektor2  v  ;  v  .  x  =  cos  (  slumpmässigt  );  v  .  y  =  sin  (  slumpmässigt  );  returnera  v  ;  }  // Beräknar punktprodukten av avstånds- och gradientvektorerna.  float  dotGridGradient  (  int  ix  ,  int  iy  ,  float  x  ,  float  y  )  {  // Få gradient från heltalskoordinater  vektor2  gradient  =  randomGradient  (  ix  ,  iy  );  // Beräkna avståndsvektorn  float  dx  =  x  -  (  float  )  ix  ;  float  dy  =  y  -  (  float  )  iy  ;  // Beräkna dot-product  return  (  dx  *  gradient  .  x  +  dy  *  gradient  .  y  );  }  // Beräkna Perlin-brus vid koordinaterna x, y  float  perlin  (  float  x  ,  float  y  )  {  // Bestäm grid cell coordinates  int  x0  =  (  int  )  floor  (  x  );  int  xl  =  x0  +  1  ;  int  y0  =  (  int  )  våning  (  y  );  int  yl  =  y0  +  1  ;  // Bestäm interpolationsvikter  // Kan även använda högre ordnings polynom/s-kurva här  float  sx  =  x  -  (  float  )  x0  ;  float  sy  =  y  -  (  float  )  y0  ;  // Interpolera mellan rutnätsgradienter  flytande  n0  ,  n1  ,  ix0  ,  ix1  ,  värde  ;  n0  =  dotGridGradient  (  x0  ,  y0  ,  x  ,  y  );  n1  =  dotGridGradient  (  x1  ,  y0  ,  x  ,  y  );  ix0  =  interpolera  (  no  ,  nl  ,  sx  );  n0  =  dotGridGradient  (  x0  ,  y1  ,  x  ,  y  );  n1  =  dotGridGradient  (  x1  ,  y1  ,  x  ,  y  );  ixl  =  interpolera  (  no  ,  nl  ,  sx  );  värde  =  interpolera  (  ix0  ,  ix1  ,  sy  );  returvärde  ;  _  // Kommer tillbaka i intervallet -1 till 1. För att göra det i intervallet 0 till 1, multiplicera med 0,5 och lägg till 0,5  } 

Permutation

Många implementeringar av Perlin-brus använder samma permutationsuppsättning som Ken Perlin använde i sin ursprungliga implementering. Den implementeringen är som följer:

                      
                        int  permutation  [  ]  =  {  151  ,  160  ,  137  ,  91  ,  90  ,  15  ,  131  ,  13  ,  201  ,  95  ,  96  ,  53  ,  194 ,   233  ,  7  ,  205  ,  3 1   ,  3 01   ,  3  01  ,  3  69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 
                      26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 
                      87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 
                      77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 
                      46, 245, 40, 244, 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 
                      187, 208, 89, 18, 169, 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 
                      198, 173, 186, 3, 64, 52, 217, 226, 250, 124, 123, 5, 202, 38, 147, 118, 126, 
                      255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 
                      170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 
                      172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 
                      104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 
                      241, 81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 
                      157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 
                      93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180 };

Denna specifika permutation är inte absolut nödvändig, även om den kräver en randomiserad uppsättning av värdena [0–255] (inklusive). Om man skapar en ny permutationstabell bör man se till att en enhetlig fördelning av värdena säkerställs.

Komplexitet

För varje utvärdering av brusfunktionen måste punktprodukten av positions- och gradientvektorerna utvärderas vid varje nod i den innehållande rutnätscellen. Perlin-brus skalas därför med komplexitet för dimensioner. Alternativ till Perlin-brus som ger liknande resultat med förbättrad komplexitetsskalning inkluderar simplexbrus och OpenSimplex-brus .

Se även

externa länkar