Bill Hsu
YaBB Newbies
Offline
Posts: 9
Re: generating random blobs
Reply #6 - May 8th , 2009, 11:19pm
[Ok, let's see if I can fake out the forum software...] The code is at the end of this post. Press any key to generate some blobs. Press again to generate new blobs. makeBlob() is the blob generator function. The input parameters are the approximate center of the blob, the diameter, a parameter to control how blob-like or noisy the result is, and a parameter to very roughly control the density. I've tried to make this fairly efficient; I haven't looked into using lots of metaballs instead, but I think this might be faster. I'm using the blobs in a project where I do a lot of pixel hacking, so I write straight into the pixel array. Two sets of blobs are displayed. The bottom shows the blobs without trimming the circular border; if that's what you need, great, but I think it makes the splatters look unnatural. I use a hack-y scaling function to trim the borders; that's the top. Because it's just Perlin noise with thresholds, sometimes you get more than one blob. And the density control is very approximate. I suppose I could look into segmenting or parameterizing the blobs better, but I think this is workable for what I need. Hope this is interesting to someone. Comments appreciated! Bill // Random Blob Generation // by Bill Hsu // Uses Perlin noise with threshold to generate blobs // at specified center and radius // Kludge-y scaling kernel to trim borders int bgCol = 0; int fgCol = color(255, 255, 255); PGraphics pg; void setup() { size(200, 400); pg = createGraphics(200, 400, P3D); pg.beginDraw(); pg.background(bgCol); pg.noStroke(); pg.endDraw(); image(pg, 0, 0); pg.loadPixels(); } void draw() { } void keyPressed() { pg.beginDraw(); pg.background(bgCol); makeBlob(width/2, width/2, width/2, .05, .25); pg.endDraw(); image(pg, 0, 0); } void makeBlob(int midX, int midY, // (x,y) coordinates of center int side, // length of a side, or diameter of blob float noiseMult, // position multiplier .02-.25 // very blobby to very noisy float percentDev) // percent deviation .005-.5 // very sparse to very dense { float xoff = random(10); float yoff = random(10); float baseLevel = noise(midX*noiseMult + xoff, midY*noiseMult + yoff); float pixelScaleBoundary = 40.; // start scaling 40 pixels from circle edge for (int i=midX-side/2; i<midX+side/2; i++) { for (int j=midY-side/2; j<midY+side/2; j++) { float radius = sqrt((i - midX) * (i - midX) + (j - midY) * (j - midY)); float diffRad = radius - side/2.; if (diffRad >= 0.) continue; float newNoise = noise(i*noiseMult + xoff,j*noiseMult + yoff); // "fade out" if too close to circular boundary float fudgeFactor = -diffRad / pixelScaleBoundary; if (fudgeFactor > 1.) fudgeFactor = 1.; float newRatio = newNoise / baseLevel; // bound base noise level if original is too low if (baseLevel < .25) { newRatio = newNoise * 4.; } // draw blob if (newRatio > 1 && newRatio < (1. + percentDev * fudgeFactor)) { pg.pixels[j*width + i] = fgCol; } else if (newRatio < 1. && newRatio > (1. - percentDev * fudgeFactor)) { pg.pixels[j*width + i] = fgCol; } // draw blob without boundary scaling for comparison if (newRatio > (1.-percentDev) && newRatio < (1. + percentDev)) { pg.pixels[(j+height/2)*width + i] = fgCol; } } } }