# Help creating organic looking "blobs"

**URL:** <https://discourse.processing.org/t/help-creating-organic-looking-blobs/8777>\
**Category:** Libraries\
**Created:** [February 27, 2019, 8:02pm UTC](https://discourse.processing.org/t/help-creating-organic-looking-blobs/8777 "2019-02-27T20:02:39Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![Hetoft](https://avatars.discourse-cdn.com/v4/letter/h/67e7ee/32.png) [@Hetoft](https://discourse.processing.org/u/Hetoft)\
**Post date:** [February 27, 2019, 8:02pm UTC](https://discourse.processing.org/t/help-creating-organic-looking-blobs/8777/1 "2019-02-27T20:02:39Z")

</div>

Hello there!

I recently started getting to grips with Processing - and I love it so far!

I want to be able to randomly create organic looking “blob” shapes - like these (which were drawn in Illustrator): [Blobs](http://hetoft.com/wp-content/themes/hetoftportfolio/svg/bg_front.svg)

What I have now is based on this example: [Noisy Circle](https://www.openprocessing.org/sketch/112858/)

The example uses perlin noise on vertices forming a circle. I’ve changed it to make curveVertex instead to make the shape softer. It works sort of okay, but it still looks a bit “edgy” and not as smooth.

I tried experimenting with bezierVertex, but it takes 6 parameters - and I’m afraid I don’t have the brain power to figure out if I can use bezierVertex to generate a random, organic shape…

This is what I have now (including my own Danish comments):

```auto
float resolution = 13; // Antal vertices i blob (virker bedst fra 13+)
float rad = 300; // Radius på blob
float x; // X-koordinat på vertex
float y; // Y-koordinat på vertex
float round = random(0, 100); // Rundhed - jo større tal, jo mere aflang

float nVal; // Noise: Værdi
float nInt = 10; // Noise: Intensitet
float nAmp = 0.4; // Noise: Udsving
float nSeed = random(0, 1000); // Noise: Unik værdi

float t = 0; // Tid passeret
float tChange = 0.01; // Hvor hurtigt tiden går

void setup() {
  size(1000, 1000);
}

void draw() {
  background(255);
  pushMatrix(); // Isolér placering til hver enkelt blob (push)
  translate(width/2, height/2); // Placering af blob (samt bevægelse på Y-aksen)
  noiseDetail(3, 0); // Noiseværdier
  noStroke(); // Ingen streg
  fill(100); // Fyldfarve

  /* Oprettelse af blobform */

  beginShape(); // Begynd form
  for (float a=-1; a <= TWO_PI; a += TWO_PI/resolution) { // Skab punkter rundt i hel cirkel (TWO_PI) og fordel dem ud fra resolution

    nVal = map(noise(cos(a)*nInt+nSeed, sin(a)*nInt+nSeed, t), 0.0, 1.0, nAmp, 1.0); // Map noiseværdi for at matche udsvinget

    x = cos(a)*(rad+round) *nVal; // Punktets X-koordinat (radius+rundhed)
    y = sin(a)*rad *nVal; // Punktets Y-koordinat

    curveVertex(x, y); // Opret curveVertex punkt ud fra koordinater
  }
  endShape(CLOSE); // Afslut form

  popMatrix(); // Isolér placering til hver enkelt blob (pop)

  t += tChange;
}

```

How do I make the shapes more fluid, smooth and rounded?

All comments are highly appreciated. 🙂

---

<div class="post-metadata">

**Author:** ![solub](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/solub/32/333_2.png) [@solub](https://discourse.processing.org/u/solub)\
**Post date:** [February 27, 2019, 9:00pm UTC](https://discourse.processing.org/t/help-creating-organic-looking-blobs/8777/2 "2019-02-27T21:00:17Z")

</div>

Hi @Hetoft,

Do you want your final output to be a static image or an animation ?

---

<div class="post-metadata">

**Author:** ![Hetoft](https://avatars.discourse-cdn.com/v4/letter/h/67e7ee/32.png) [@Hetoft](https://discourse.processing.org/u/Hetoft)\
**Post date:** [February 27, 2019, 10:12pm UTC](https://discourse.processing.org/t/help-creating-organic-looking-blobs/8777/3 "2019-02-27T22:12:30Z")

</div>

Hi solub,

Thanks for replying. Animated is ultimately the end goal, but static would be fine as a start.

---

<div class="post-metadata">

**Author:** ![solub](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/solub/32/333_2.png) [@solub](https://discourse.processing.org/u/solub)\
**Post date:** [February 28, 2019, 5:26pm UTC](https://discourse.processing.org/t/help-creating-organic-looking-blobs/8777/4 "2019-02-28T17:26:27Z")

</div>

There are different ways to achieve that organic look you’re looking for but I’m afraid that noising a circle isn’t the best option.

The edges on your example sketch do look “smooth” (no need to use `bezierVertex()`) but the reason you’re not satisfied with it is because the height around the center is lacking contrast / variation. Based on the picture you provided I’d say that “splatter effect” is what you’re actually after.

Still, we can try to change your sketch a bit. Modifying the noise function and do some scaling will somewhat improve both the motion and the shape of the circle:

![Noicy%20circle](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/e/e018f6caa9f6ca020317b4ebd9b27397c50a06d9.png)

see motion [here](https://giphy.com/gifs/8rFNEqgk6w2WTMIALn/fullscreen)

_(please note that I’m using Python mode but it should be really easy to port it to Java)_

```auto
n_points, radius = 200, 300
angle = radians(360) / n_points
factor = .2

def setup():
    size(800, 600, P2D)
    noStroke()
    smooth(8)

    beginShape() #Avoid calling beginShape() at each iteration 
        
def draw():
    background(255)

    translate(width>>1, height>>1)
    
    for e in range(n_points+1):
        x = cos(angle * e) * radius
        y = sin(angle * e) * radius 
        p = PVector(x, y).normalize()
        n = map(noise(p.x * factor + frameCount*.01, p.y * factor + frameCount*.01), 0, 1, 10, 200)
        p.mult(n)
        fill(100 - e / 10 - abs(p.y), (90 + e) - (p.y/4), 220)
        vertex(p.x, p.y)
    endShape(CLOSE)

```

In order to get a more blob looking shape I would suggest different approaches:

**1/ Iso-surface (Metaballs)**

Daniel Shiffman did a [coding challenge](https://www.youtube.com/watch?v=ccYLb7cLB1I) on Metaballs a while ago. You can implement your own distance field based on his code or you can chose to use a library instead. I’ve found [Computational Geometry](http://www.thecloudlab.org/processing/library.html) to be one of the easiest to use for this purpose.

 ![mb1](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/6/656d6ba426914267f6b8cb4141095e3e467e060b.png)

_(see the bunddled examples for Java sketches)_

```auto
add_library('ComputationalGeometry')

def setup():
    size(800, 500, P3D)
    rectMode(CENTER)
    background(255)
    noStroke()
    smooth(8)
    
    iso1 = IsoContour(this, PVector(), PVector(width, height), 200, 125) #last 2 int are the number of columns and rows. The higher, the better the resolution
    iso2 = IsoContour(this, PVector(), PVector(width, height), 200, 125)
    thresh = .0004 #the lower, the bigger the blobs
    
    for i in range(20):
        p1 = PVector(random(50, width - 50), random(height), 0)
        p2 = PVector(random(50, width - 50), random(height), 0)
        iso1.addPoint(p1)
        if i> 5: iso2.addPoint(p2)
        
    
    fill('#002d6b')
    rect(width>>1, height>>1, width - 120, height)
    
    fill('#e01a2c')
    iso1.plot(thresh)
    fill('#ffc20e')
    iso2.plot(thresh)

```

2 majors drawbacks:

- because of the need to compute distances from each point on the grid to the ball (and this, for each ball), the algorithm is computationally expensive. Hence the difficulty to make an animation, unless you decide to implement it in a shader.
- because it is making use of the whole array of pixels (`loadPixels` / `updatePixels` in its naive implementation) it is not possible to select the color of a specific ball.

**2/ “Gooey Effect”**

Visually similar to metaballs, it is a technique coming from the Web design community that consists in applying SVG filters (gaussian blur + high contrast in the alpha channel) on moving ellipses in order to get blob-like motions.

 ![](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/9/9464effc1cc1e18ac2989783449a341d2b49b03e.jpeg)

_Example of a gooey effect implemented in three.js by [Misaki Nakano](https://twitter.com/misaki_mofu/). See it live [here](https://www.youmakeshibuya.jp/)_

Although the melting effect doesn’t look as good as in the original Javascript version, _noahbuddy_ from the forum did a fantastic job trying to port that technique in Processing with a shader.

 ![Gooey_](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/f/fdcacd60bd6a18bcbe2cea1fdbe141d6bb3a93f7.jpeg)

(See original Java version [here](https://forum.processing.org/two/discussion/27751/implementing-a-gooey-effect-with-a-shader))

```auto
def setup():
    global buf, balls, contrast, blurry
    size(1240, 720, OPENGL)
    rectMode(CENTER)
    noStroke()
    smooth(8)

    buf = createGraphics(width, height, P2D)
    contrast = loadShader("colFrag.glsl")
    blurry = loadShader("blurFrag.glsl")
    
    blurry.set("sigma", 10.5)
    blurry.set("blurSize", 30)
    
    balls = [Ball() for e in range(40)]

def draw():
    background(255)
    
    fill('#002d6b')
    rect(width>>1, height>>1, width - 120, height)
    
    buf.beginDraw()
    buf.background(190, 0)
    buf.noStroke()
    for b in balls:
        b.update()
        b.render()
        
    blurry.set("horizontalPass", 1)
    buf.filter(blurry)
    blurry.set("horizontalPass", 0)
    buf.filter(blurry)
    buf.endDraw()
    
    shader(contrast)
    image(buf, 0, 0, width, height)
    
             
class Ball(object):
    def __init__ (self):
        self.loc = PVector(random(width), random(height), 0)
        self.vel = PVector.random2D()
        self.radius = random(60, 140)
        self.c = [[224,26,44], [255,194,14]]
        self.r = int(random(2))
        
    def update(self):
        self.loc.add(self.vel)
        
        if self.loc.x > width or self.loc.x < 0: self.vel.x *= -1
        if self.loc.y > height or self.loc.y < 0: self.vel.y *= -1
        
    def render(self):
        buf.fill(self.c[self.r][0], self.c[self.r][1], self.c[self.r][2])
        buf.ellipse(self.loc.x, self.loc.y, self.radius, self.radius)

```

> **colFrag.glsl**
>
> ```auto
> #define PROCESSING_TEXTURE_SHADER
>  
> uniform sampler2D texture;
> varying vec4 vertTexCoord;
>  
> uniform vec4 o = vec4(0, 0, 0, -8.0); 
> uniform lowp mat4 colorMatrix = mat4(1.0, 0.0, 0.0, 0.0, 
> 0.0, 1.0, 0.0, 0.0, 
> 0.0, 0.0, 1.0, 0.0, 
> 1.0, 1.0, 1.0, 8.0);
>  
> void main() {
> vec4 pix = texture2D(texture, vertTexCoord.st);
>  
> vec4 color = (pix * colorMatrix) * 1.15 + o ;
> gl_FragColor = color;
> }
> 
> ```

> **blurFrag.glsl**
>
> ```auto
> // Adapted from:
> // <a href="http://callumhay.blogspot.com/2010/09/gaussian-blur-shader-glsl.html" target="_blank" rel="nofollow">http://callumhay.blogspot.com/2010/09/gaussian-blur-shader-glsl.html</a>
>  
> #ifdef GL_ES
> precision mediump float;
> precision mediump int;
> #endif
> 
>  
> #define PROCESSING_TEXTURE_SHADER
>  
> uniform sampler2D texture;
>  
> // The inverse of the texture dimensions along X and Y
> uniform vec2 texOffset;
>  
> varying vec4 vertColor;
> varying vec4 vertTexCoord;
>  
> uniform int blurSize;       
> uniform int horizontalPass; // 0 or 1 to indicate vertical or horizontal pass
> uniform float sigma; // The sigma value for the gaussian function: higher value means more blur
> // A good value for 9x9 is around 3 to 5
> // A good value for 7x7 is around 2.5 to 4
> // A good value for 5x5 is around 2 to 3.5
> // ... play around with this based on what you need <span class="Emoticon Emoticon1"><span>:)</span></span>
>  
> const float pi = 3.14159265;
>  
> void main() {  
> float numBlurPixelsPerSide = float(blurSize / 2); 
>  
> vec2 blurMultiplyVec = 0 < horizontalPass ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
>  
> // Incremental Gaussian Coefficent Calculation (See GPU Gems 3 pp. 877 - 889)
> vec3 incrementalGaussian;
> incrementalGaussian.x = 1.0 / (sqrt(2.0 * pi) * sigma);
> incrementalGaussian.y = exp(-0.5 / (sigma * sigma));
> incrementalGaussian.z = incrementalGaussian.y * incrementalGaussian.y;
>  
> vec4 avgValue = vec4(0.0, 0.0, 0.0, 0.0);
> float coefficientSum = 0.0;
>  
> // Take the central sample first...
> avgValue += texture2D(texture, vertTexCoord.st) * incrementalGaussian.x;
> coefficientSum += incrementalGaussian.x;
> incrementalGaussian.xy *= incrementalGaussian.yz;
>  
> // Go through the remaining 8 vertical samples (4 on each side of the center)
> for (float i = 1.0; i <= numBlurPixelsPerSide; i++) { 
> avgValue += texture2D(texture, vertTexCoord.st - i * texOffset * 
> blurMultiplyVec) * incrementalGaussian.x;         
> avgValue += texture2D(texture, vertTexCoord.st + i * texOffset * 
> blurMultiplyVec) * incrementalGaussian.x;         
> coefficientSum += 2.0 * incrementalGaussian.x;
> incrementalGaussian.xy *= incrementalGaussian.yz;
> }
>  
> gl_FragColor = avgValue / coefficientSum;
> }
> 
> ```

**3/ Physics (springs + repulsion behaviors)**

Another possibilty would be to connect particles (displayed around a circle) with springs and give them a repulsion force from each other that is proportional to distance.

 ![ZL%20Blob](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/5/53eb2faff24463289e085e4c1785d2369ea1faf9.jpeg)  
_(blob by Zach Lieberman, taken from [this post](https://medium.com/@zachlieberman/daily-sketches-2016-28586d8f008e))_

see motion [here](https://cdn-images-1.medium.com/max/800/1*gapWpxJSlBSFiXVd-2RinQ.gif)

I remember trying to implement it with the _toxiclibs_ library but failed eventually because it wa impossible to give particles an individual repulsion force that would target another specific particle. So, if you decide go down that road I would suggest to code your own physics engine from scratch (check these videos on [attractors](https://www.youtube.com/watch?v=fML1KpvvQTc&t=1082s) and [springs](https://www.youtube.com/watch?v=cluKQOY92Dw) from Daniel Shiffman).

**4/ Differential Growth**

Probably the more elaborate solution but mentionning it here just for brainstroming. It starts the same way (particles with repulsion force connected by springs around a circle) except new cells (particles) are randomly added between pre-existing cells as the sketch is iterating. Very quickly (during the early stages of the growth) the circle turns into a blob like shape with that splatter effect you’re looking for:

 ![](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/d/dc29f98d72821b579962bac8e1f69472b4a0ac5c.gif)

Check the fantastic [tutorials](http://igeo.jp/tutorial/55.html) from Satoru Sugihara for more info.

Drawbacks:

- can be tricky to implement (managing / updating the connections)
- the order of the cells needs to be re-computed every time a cell division occurs (only if you want to fill the shape)
- becomes slow at some point

---

<div class="post-metadata">

**Author:** ![Hetoft](https://avatars.discourse-cdn.com/v4/letter/h/67e7ee/32.png) [@Hetoft](https://discourse.processing.org/u/Hetoft)\
**Post date:** [March 4, 2019, 8:28am UTC](https://discourse.processing.org/t/help-creating-organic-looking-blobs/8777/5 "2019-03-04T08:28:25Z")

</div>

Woooooow, thank you so, so much for your detailed explanations and tryouts. A bit overwhelming, haha! Interesting to see what possibilites you have with Processing/P5 and the seemingly endless range of options…

The Iso-surface comes closest to the shapes I want, but since I want it animated (and only have so much time to work on this), I think I’ll stick to the first solution. I’ll try to port what you wrote into Java. Really appreciate your work on this!

---

<div class="post-metadata">

**Author:** ![pirkadat](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/pirkadat/32/17613_2.png) [@pirkadat](https://discourse.processing.org/u/pirkadat)\
**Post date:** [December 15, 2022, 4:14pm UTC](https://discourse.processing.org/t/help-creating-organic-looking-blobs/8777/6 "2022-12-15T16:14:22Z")

</div>

Hi @solub!

I ported your approach (with noise+scaling) to Java, it looks sooo good 😃 Thanks for sharing it!

```auto
int nPoints = 200;
int radius = 300;
float angle = radians(360) / nPoints;
float factor = 0.2f;
float x, y;
PVector p;
float n;

void setup() {
    size(800, 600, P2D);
    noStroke();
    smooth(10);
    frameRate(24);

    beginShape();
}

void draw() {
    background(0);
    translate(width >> 1, height >> 1);
    
    for (int i = 0; i <= nPoints; i++) {
        x = cos(angle * i) * radius;
        y = sin(angle * i) * radius;
        p = new PVector(x, y).normalize();
        n = map(noise(p.x * factor + frameCount * 0.01f, p.y * factor + frameCount * 0.01f), 0, 1, 10, 200);
        p.mult(n);
        fill(40 - i / 40 - abs(p.y), (90 + i) - (p.y/4), 220);
        vertex(p.x, p.y);   
    }
    endShape(CLOSE);
}

```

![blob_2d-2022-12-15_18.50.17](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/a/4/a4f009b4ed101e45b25873192c31f95be12efcf7.gif)

However, when there is a sudden change in the size of the blob, some pixels on the right side have the same color (highlighted in red in the image below).

 ![blob2d-pixels-with-same-color-left-side_highlighted](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/d/8/d8bc31ffa06a82505c5b0e0c684f08c01356b23f.png)  
Why is it happening and how can I avoid it? I want a smooth transition in color in the whole shape.

---

<div class="post-metadata">

**Author:** ![debxyz](https://avatars.discourse-cdn.com/v4/letter/d/58956e/32.png) [@debxyz](https://discourse.processing.org/u/debxyz)\
**Post date:** [December 15, 2022, 5:07pm UTC](https://discourse.processing.org/t/help-creating-organic-looking-blobs/8777/7 "2022-12-15T17:07:59Z")

</div>

Hello @pirkadat 🙂

> [@pirkadat](#):
>
> ```auto
> fill(40 - i / 40 - abs(p.y), (90 + i) - (p.y/4), 220);
> vertex(p.x, p.y); 
> 
> ```

I’ve recently been playing with blob shapes so this topic is interesting to me.  
In trying to understand what’s happening I added an additional line of code (maybe you already tried this 🙂 ):

```auto
fill(40 - i / 40 - abs(p.y), (90 + i) - (p.y/4), 220);
vertex(p.x, p.y);
circle(p.x, p.y, 10);

```

But it it clear where the abrupt transition happens viewed in the outline.

I don’t know specifically how to solve that but it seems that if you can somehow implement a sin/cos wave equal to the nPoints linked to the color this would loop back to its start color instead of ending abruptly at a different color. 🤔  
That is where I would begin. (Though I could be completely wrong… 🙃 )

🤓

---

<div class="post-metadata">

**Author:** ![pirkadat](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/pirkadat/32/17613_2.png) [@pirkadat](https://discourse.processing.org/u/pirkadat)\
**Post date:** [December 15, 2022, 5:22pm UTC](https://discourse.processing.org/t/help-creating-organic-looking-blobs/8777/8 "2022-12-15T17:22:08Z")

</div>

@debxyz Worth a try, thanks! 😁

---

<div class="post-metadata">

**Author:** ![debxyz](https://avatars.discourse-cdn.com/v4/letter/d/58956e/32.png) [@debxyz](https://discourse.processing.org/u/debxyz)\
**Post date:** [December 15, 2022, 5:30pm UTC](https://discourse.processing.org/t/help-creating-organic-looking-blobs/8777/9 "2022-12-15T17:30:50Z")

</div>

I just tried this and it works BUT now there’s a bit of magenta in the lower left corner. I have no idea how to eliminate that!  
It looks smooth all around though… 🙂

```auto
fill((40 - i / 40 - abs(p.y) + y), ((90 + i) - (p.y/4) + x), 220); // addition of x and y
vertex(p.x, p.y);
circle(p.x, p.y, 10);

```

🤓

---

<div class="post-metadata">

**Author:** ![solub](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/solub/32/333_2.png) [@solub](https://discourse.processing.org/u/solub)\
**Post date:** [December 15, 2022, 11:41pm UTC](https://discourse.processing.org/t/help-creating-organic-looking-blobs/8777/10 "2022-12-15T23:41:21Z")

</div>

Hi @pirkadat,

What happens is that the green value (R **G** B) varies according to the index `i` of the points that make up the ouline of the circle.

> (90 + i)

As soon as the loop ends, the index jumps from `nPoints = 199` to `0` and creates a sudden drop in the green value giving way to a predominantly blue colour instead. The constrast is even more pronounced when the perlin noise moves the end points away from the start points.

A workaround would be to simply remove the point index from the colour value.

Also, it looks the calculations of the RGB values are unnecessarily complicated. Overall my example script is poorly written (sorry you had to go through this) so here is a simpler version that hopefully will make things clearer.

```auto
W, H = 700, 400 # Dimensions of canvas
N = 100 # Number of vertices
A = TAU / N # Step angle
K = .2 # Noise factor

def setup():
    size(W, H, P2D)
    noStroke()
    smooth(8)
    
    beginShape()
    
def draw():
    background('#FFFFFF')
    translate(W>>1, H>>1)
    
    fc = frameCount * .01
    
    for i in xrange(N):
        p = PVector(cos(A*i), sin(A*i))
        n = noise(p.x * K + fc, p.y * K + fc) * 200
        p.mult(n)

        fill(0, 190 - p.y, 220)
        vertex(p.x, p.y)
    endShape(CLOSE)

```

---

<div class="post-metadata">

**Author:** ![solub](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/solub/32/333_2.png) [@solub](https://discourse.processing.org/u/solub)\
**Post date:** [December 16, 2022, 12:33am UTC](https://discourse.processing.org/t/help-creating-organic-looking-blobs/8777/11 "2022-12-16T00:33:44Z")

</div>

I’d like to take this opportunity to post another technique that I didn’t know about at the time of this post and that I’ve been meaning to add to the above list for a couple of years now.

Some call it the “shrink-wrap” method, it consists in approximating the _[closing](https://en.wikipedia.org/wiki/Closing_(morphology))_ of a set of polygons by offsetting inward the outward offset of the whole. In more specific words, it’s the “erosion” of the “dilatation” process that precedes it.

 ![closing](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/6/b/6b2e4ad209cdb192965220e596f6c3145172c874.png)

_5 circles (white) are offsetted outward. The result (dashed line) is offsetted back inward (black outline)_

It’s nothing new but gives great results and is easy to implement with the help of a good library for offsetting polygons. Here’s a quick example in Python mode with a port of the [Clipper](http://www.angusj.com/clipper2/Docs/Overview.htm) library.

```auto
import clipper as cp

W, H = 600, 400 # Dimensions of canvas
N = 60 # Number of vertices for each circle
A = TAU/N # Step angle
D = 37 # Offset distance

RAD = (43, 32, 15, 54, 95) # List of radii
PTS = (PVector(355, 198), # List of points (circles' centers)
       PVector(407, 260), 
       PVector(475, 164), 
       PVector(301, 290), 
       PVector(187, 150))

def setup():
    size(W, H, P2D)
    background('#FFFFFF')
    strokeWeight(2)
    smooth(8)
    noFill()
    
    vertices = [] # List of vertices for each circle
    
    # Create a circle around each point (p) with a specific radius (r)
    for p, r in zip(PTS, RAD):
        
        # Convert circle vertices to Clipper 'Point' format
        v_list = [cp.Point(p.x + cos(A*i) * r, p.y + sin(A*i) * r) for i in xrange(N)]
        vertices.append(v_list)
        
        # Draw circles
        pushStyle()
        strokeWeight(1)
        stroke(180)
        fill(255)
        circle(p.x, p.y, r*2)
        popStyle()
    
    # Compute outward offset + inward offset (dilatation + erosion)  
    ### Args:
    ### points (Clipper Point) - Vertices of the polygon to offset
    ### delta (Float) - Offset distance
    ### jointype (Int) - 0=Square, 1=Round, 2=Miter
    
    out_offset = cp.OffsetPolygons(vertices, D, jointype=0)
    in_offset = cp.OffsetPolygons(out_offset, -D+10, jointype=1) 
    
    # Draw outline
    beginShape()
    for p in in_offset[0]:
        vertex(*p)
    endShape(CLOSE)

```

Edit: I believe @micycle 's [PGS library](https://github.com/micycle1/PGS/tree/master) does that as well (see _Erosion-Dilation_ example gif) but never had the chance to try.

---

<div class="post-metadata">

**Author:** ![pirkadat](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/pirkadat/32/17613_2.png) [@pirkadat](https://discourse.processing.org/u/pirkadat)\
**Post date:** [December 16, 2022, 8:54pm UTC](https://discourse.processing.org/t/help-creating-organic-looking-blobs/8777/12 "2022-12-16T20:54:08Z")

</div>

@solub Thanks for the explanation and the examples. This thread starts to look like a (initial) wiki page on 2D blob creation 😁

Huge shoutout to @micycle’s [PGS library](https://github.com/micycle1/PGS/tree/master), looks like an incredible tool for everything 2D geometry related. He also created a [port of Clipper for Java](https://github.com/micycle1/Clipper2-java).

---

<div class="post-metadata">

**Author:** ![micycle](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/micycle/32/201_2.png) [@micycle](https://discourse.processing.org/u/micycle)\
**Post date:** [December 18, 2022, 3:22pm UTC](https://discourse.processing.org/t/help-creating-organic-looking-blobs/8777/13 "2022-12-18T15:22:01Z")

</div>

Aye, 3 lines in PGS 😉

```auto
var circles = List.of(new PVector(355, 198, 43), new PVector(407, 260, 32), new PVector(475, 164, 15), new PVector(301, 290, 54), new PVector(187, 150, 95));
var circlesShape = PGS_Conversion.flatten(circles.stream().map(c -> createShape(ELLIPSE, c.x, c.y, c.z * 2, c.z * 2)).toList());
shape(PGS_Morphology.dilationErosion(circlesShape, mouseX));

```
