Skip to main content
Variable `ratio` was not used in code (.15 instead of `ratio`).
Source Link
István Zachar
  • 47.2k
  • 20
  • 147
  • 307
f = perlinNoise[{{-1, 1}, {-1, 1}}, {res, res}, seed]; tab1 = Table[Exp[-(x^2 + y^2)] + .15 f[xratio*f[x, y], {x, -1, 1, 1/(2 res)}, {y, -1, 1, 1/(2 res)}]; pl = ListContourPlot[ArrayPad[tab1, {{1, 1}, {1, 1}}], InterpolationOrder -> 2, Contours -> {level}, ContourShading -> None, Frame -> False]; pl/. {___, a__Line} :> FilledCurve[Thread[{{a}}]] 
f = perlinNoise[{{-1, 1}, {-1, 1}}, {res, res}, seed]; tab1 = Table[Exp[-(x^2 + y^2)] + .15 f[x, y], {x, -1, 1, 1/(2 res)}, {y, -1, 1, 1/(2 res)}]; pl = ListContourPlot[ArrayPad[tab1, {{1, 1}, {1, 1}}], InterpolationOrder -> 2, Contours -> {level}, ContourShading -> None, Frame -> False]; pl/. {___, a__Line} :> FilledCurve[Thread[{{a}}]] 
f = perlinNoise[{{-1, 1}, {-1, 1}}, {res, res}, seed]; tab1 = Table[Exp[-(x^2 + y^2)] + ratio*f[x, y], {x, -1, 1, 1/(2 res)}, {y, -1, 1, 1/(2 res)}]; pl = ListContourPlot[ArrayPad[tab1, {{1, 1}, {1, 1}}], InterpolationOrder -> 2, Contours -> {level}, ContourShading -> None, Frame -> False]; pl/. {___, a__Line} :> FilledCurve[Thread[{{a}}]] 
Source Link
Heike
  • 36.2k
  • 3
  • 111
  • 158

This solution uses Perlin noise to generate the blobs.

To generate the noise we use the following function. Here, range is the domain on which we will generate the noise, res is the number of points in x and y direction, and seed is the seed for the random number generator.

perlinNoise[range_: {{0, 1}, {0, 1}}, res_: {30, 30}, seed_: 1] := With[{ grid = (SeedRandom[seed]; Table[With[{t = RandomReal[2 Pi]}, {Cos[t], Sin[t]}], {res[[1]]}, {res[[2]]}]), intf = 3 #^2 - 2 #^3 &}, Function[{x, y}, Module[{ind, xr, yr, pmat}, (* ind=={{xmin,xmax},{ymin, ymax}} *) {xr, yr} = MapThread[Rescale[#1, #2, {1, #3}] &, {{x, y}, range, res}]; ind = Floor[{xr, yr}]; ind = MapThread[Min[#1, #2 - 1] &, {ind, res}]; {xr, yr} -= ind; pmat = {{{xr, yr}.grid[[ind[[1]], ind[[2]]]], {xr, yr - 1}.grid[[ind[[1]], ind[[2]] + 1]]}, {{xr - 1, yr}.grid[[ind[[1]] + 1, ind[[2]]]], {xr - 1, yr - 1}.grid[[ind[[1]] + 1, ind[[2]] + 1]]}}; {1 - intf[xr], intf[xr]}.pmat.{1 - intf[yr], intf[yr]}]]] 

Next we're going to superpose some noise on top of a two-dimensional Gaussian function and we use ListContourPlot to plot the region where the resulting function is larger than some level (note that we could use RegionPlot as well, but ListContourPlot is faster). There are a lot of parameters to play with here, such as the resolution of the noise, the ratio between the noise and Gaussian surface, and the level of the contour. For example for

res = 30; seed = 3; level = .6; ratio = .15; 

we get

f = perlinNoise[{{-1, 1}, {-1, 1}}, {res, res}, seed]; tab1 = Table[Exp[-(x^2 + y^2)] + .15 f[x, y], {x, -1, 1, 1/(2 res)}, {y, -1, 1, 1/(2 res)}]; pl = ListContourPlot[ArrayPad[tab1, {{1, 1}, {1, 1}}], InterpolationOrder -> 2, Contours -> {level}, ContourShading -> None, Frame -> False]; pl/. {___, a__Line} :> FilledCurve[Thread[{{a}}]] 

Mathematica graphics

By increasing the ratio get more splattering:

res = 30; seed = 3; level = .6; ratio = .8; 

Mathematica graphics

And by lowering the resolution you get smoother blobs:

res = 8; seed = 3; level = .6; ratio = .8; 

Mathematica graphics