Beklager, du har ikke den krævede version af Flash Player. Du kan hente den fra http://www.adobe.com/go/getflash/
Intro
Denne guide er beregnet som en introduktion til og nem opsætning af et animeret Perlin noise. Den er baseret på arbejdet af Seb Lee-Delisle, Ron Valstar og selvfølgelig Ken Perlin.
Perlin noise er et specialiseret slags noise som har en smoothing/gradient:

Denne type noise kan bruges til mange ting, både direkte visuelt, men også til at styre visuelle elementer eller pathing, flocking og animation af objekter. Da Perlin noise består af gradienter egner det sig godt til at generere organiske og flydende animationer.
Perlin noise som 3D terræn
Perlin noise til at lave flocking
Princippet
Her i guiden vil jeg fokusere på at lave et animeret Perlin noise ligesom det Seb har lavet.
Princippet bag et animeret Perlin noise er at generere et 3D Perlin noise og så animere ved at tage "slices" på z-aksen, dette giver en flydende animation, hvorimod hvis man bare gentegnede et 2D Perlin noise med et nyt seed (tilfældighed) ville det give et meget hakkende resultat.
Flash understøtter som standard kun 2D Perlin noise med BitmapData.perlinNoise(), men heldigvis har Ron Valstar konverteret Ken Perlin's originale 3D Perlin Noise til AS3 hvorefter Mario Klingemann har lavet nogle optimeringer af klassen.
Her er et eksempel lavet af Ron Valstar hvor klassen er brugt, den viser også de forskellige parametre man kan stille på:
Beklager, du har ikke den krævede version af Flash Player. Du kan hente den fra http://www.adobe.com/go/getflash/
Inden jeg viser hele koden der skal til for at få et animeret Perlin Noise til at køre så lad os lige kigge på et par kodestumper.
Perlin settings
Først de settings vi laver på OptimizedPerlin klassen(den vi downloadede), det er de samme parametre som vi havde i ovenstående eksempel.
1 2 3 4 5 6 7 | // settings for the perlin noise renderer // size of areas, integers, higher = smaller areas = more detailed OptimizedPerlin.octaves = 3; // smoothing, values: 0-1, lower = more smooth OptimizedPerlin.falloff = 0.5; // generate perlin seed(randomness) OptimizedPerlin.seed = Math.round(Math.random() * 123); |
Octaves er mængden/størrelsen af "områder" og dermed også detaljegraden, højere betyder flere "områder" mere detaljeret. Falloff er mængden af smoothing(gradient graden), lavere betyder mere smoothing. Seed er hvilken "opsætning" man får, så man sætter den til et random tal hver gang til at få et forskelligt resultet.
1 2 3 4 5 | // create bitmapdata that we will draw perlin map onto, keep size small for fast render _perlinData = new BitmapData(50,25,false,0x000000); // create bitmap for perlin bitmapdata, smoothing is important cause it will be scaled var perlinBitmap:Bitmap = new Bitmap(_perlinData,"auto",true); |
Det bitmapData vi genererer vores Perlin noise på skal være meget lille(her 50x25px) for at vi kan generere vores noise hurtigt nok til at animere det, men heldigvis kan vi bare skalere vores bitmap op med smoothing på og stadig få et godt resultet.
Draw Perlin
Her er metoden som genererer og tegner vores Perlin noise:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | // DRAW PERLIN private function drawPerlin():void { // lock the bitmapdata (block updates) _perlinData.lock(); // run through each pixel in the bitmapdata for (var i:Number = 0; i < _perlinData.width; ++i) { for (var j:Number = 0; j < _perlinData.height; ++j) { // get value from perlin noise (0-1) var noiseValue:Number = OptimizedPerlin.noise( i/_perlinData.width, j/_perlinData.height, _zValue ); // convert value to color amount (0-255) var noiseColorValue:int = int( (.5+1.*(noiseValue-.5))*255 ); // create blue color between full blue and full white var color:uint = noiseColorValue << 16 | noiseColorValue << 8 | 255; // set color on bitmapdata pixel _perlinData.setPixel(i, j, color); } } //unlock the bitmapdata _perlinData.unlock(); } |
Vi starter og slutter med at låse vores bitmapdata så der ikke bliver sendt updates til vores bitmap for hver pixel vi løber igennem. Efter den er låst så løber vi igennem hver pixel vi har i vores bitmapdata og får Perlin noise værdien med OptimizedPerlin.noise(), som tager imod x, y og z parametre som alle skal være meget lave tal. Herefter konverterer vi værdien fra 0-1 til 0-255 så vi kan bruge det til at lave en farve, så laver vi en blå farve mellem helt blå og helt hvid, og til sidst tegner vi farven på den pixel i vores bitmapdata som vi er kommet til.
Enter Frame
Til sidst har vi den funktion der sørger for at animere vores Perlin noise, den bliver kaldt hver frame.
1 2 3 4 5 6 7 8 9 | // ENTER FRAME HANDLER private function enterFrameHandler(event:Event):void { // draw perlin map drawPerlin(); // increment z value used for perlin map _zValue += 0.04; } |
Her tegner vi vores Perlin noise og hæver z værdien.
Dette er stort set alt der skal til for at få lavet et animeret Perlin noise, den fulde kode som jeg bare har sat som document class i Flash CS4 kan ses her:
Kildekode
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | package { // IMPORTS import flash.display.Sprite; import flash.display.StageScaleMode; import flash.display.StageAlign; import flash.display.BitmapData; import flash.display.Bitmap; import flash.events.Event; import nl.ronvalstar.math.OptimizedPerlin; // CLASS public class PerlinAnim extends Sprite { //PRIVATE VARS private var _perlinData:BitmapData; private var _perlinHolder:Sprite; private var _zValue:Number = 1; // CONSTRUCTOR public function PerlinAnim() { // set stage scale and align stage.scaleMode = StageScaleMode.NO_SCALE; stage.align = StageAlign.TOP_LEFT; // initialize init(); } // INIT private function init():void { // create the perlin bitmaps etc. setupPerlin(); // listen for stage resize and enter frame stage.addEventListener(Event.RESIZE, stageResizeHandler, false, 0, true); addEventListener(Event.ENTER_FRAME, enterFrameHandler, false, 0, true); } // SETUP PERLIN private function setupPerlin():void { // settings for the perlin noise renderer // size of areas, integers, higher = smaller areas = more detailed OptimizedPerlin.octaves = 3; // smoothing, values: 0-1, lower = more smooth OptimizedPerlin.falloff = 0.5; // generate perlin seed(randomness) OptimizedPerlin.seed = Math.round(Math.random() * 123); // create bitmapdata that we will draw perlin map onto, keep size small for fast render _perlinData = new BitmapData(50,25,false,0x000000); // create bitmap for perlin bitmapdata, smoothing is important cause it will be scaled var perlinBitmap:Bitmap = new Bitmap(_perlinData,"auto",true); // setup holder and add to stage _perlinHolder = new Sprite(); _perlinHolder.addChild(perlinBitmap); addChild(_perlinHolder); // scale perlin holder to stage size stageResizeHandler(null); } // DRAW PERLIN private function drawPerlin():void { // lock the bitmapdata (block updates) _perlinData.lock(); // run through each pixel in the bitmapdata for (var i:Number = 0; i < _perlinData.width; ++i) { for (var j:Number = 0; j < _perlinData.height; ++j) { // get value from perlin noise (0-1) var noiseValue:Number = OptimizedPerlin.noise( i/_perlinData.width, j/_perlinData.height, _zValue ); // convert value to color amount (0-255) var noiseColorValue:int = int( (.5+1.*(noiseValue-.5))*255 ); // create blue color between full blue and full white var color:uint = noiseColorValue << 16 | noiseColorValue << 8 | 255; // set color on bitmapdata pixel _perlinData.setPixel(i, j, color); } } //unlock the bitmapdata _perlinData.unlock(); } // ENTER FRAME HANDLER private function enterFrameHandler(event:Event):void { // draw perlin map drawPerlin(); // increment z value used for perlin map _zValue += 0.04; } // STAGE RESIZE HANDLER private function stageResizeHandler(event:Event):void { // scale perlin holder to stage _perlinHolder.scaleX = stage.stageWidth/_perlinData.width; _perlinHolder.scaleY = stage.stageHeight/_perlinData.height; } } } |
3 kommentarer
Hej Artmos.
Vildt inspirerende, det glæder jeg mig til at komme i dybden med, tak for en fin artikel.
Et enkelt spørgsmål:
- Tror du dette ville fungere som fullsize baggrund på et website, eller vil det være for processor-intensivt?
Og lidt opklarende:
- Vil du prøve at forklare hvordan jeg f. eks. ændrer de farven den arbejder imellem, denne linie giver nemlig ikke helt mening for mig:
var color:uint = noiseColorValue << 16 | noiseColorValue << 8 | 255;
På forhånd tak
Felix
du kan IKKE bruge perlin noise i stor størrelse vil max sige 400x400
ved ikke mht den noise som anders bruger - men hvis du bruger den indbyggede så kan du vælge farve kanal under component color -
BitmapDataChannel.RED | BitmapDataChannel.GREEN | BitmapDataChannel.BLUE | BitmapDataChannel.ALPHE
her vælger du rød og grøn og blå og alpha - og jeg vil tro de specielle opnås ved at at bruge matrixfilter on top
du kan teste din teori her http://www.thonbo.com/PERLINLAB/
hvis du klikker show map kan du se hvor skidt den performer bare i de 500x500 der er dér