I'd like to generate some visually-pleasing animations of clouds, fog or smoke with Mathematica. My idea of "visually-pleasing" is along the lines of one of the images on the Wikipedia article for random Perlin noise.
Image description: "Perlin noise rescaled and added into itself to create fractal noise."
Based on the example MATLAB code found here, I wrote the following function in Mathematica:
perlin3D[n_, t_, r_] := Module[{s, w, i, d},
s = ConstantArray[0., {t, n, n}];
w = n;
i = 0;
While[w > 3,
i++;
d = GaussianFilter[RandomReal[{0, 1}, {t, n, n}], r*i];
s = s + i*d;
w = w - Ceiling[w/2 - 1];
];
s = (s - Min@s)/(Max@s - Min@s)
]
The results are OK, but not as good as I'd like. It's not as smooth as the example image above, nor is the image contrast as strong.
(* Generate 100 frames of 128*128 pixels *)
res = perlin3D[128, 100, 4];
imgres = Image@# &/@ res;
ListAnimate[imgres, 16]
How can I improve the quality of the generation using Mathematica, and is there anyway to speed it up for larger and/or longer animations?
Update
The contrast can be improved a little, as pointed out by N.J.Evans in a comment, by removing the first and last few frames before scaling, namely s = s[[r*i ;; -r*i]]
. However it's still not as "fog-like" as the Wikipedia example.
Answer
This is a 2D Gaussian random field with a $1/k^2$ spectrum and linear dispersion $\omega \propto k$. I clip the field to positive values and square root it to give an edge to the "clouds".
n = 256;
k2 = Outer[Plus, #, #] &[RotateRight[N@Range[-n, n - 1, 2]/n, n/2]^2];
spectrum = With[{d := RandomReal[NormalDistribution[], {n, n}]},
(1/n) (d + I d)/(0.000001 + k2)];
spectrum[[1, 1]] *= 0;
im[p_] := Clip[Re[InverseFourier[spectrum Exp[I p]]], {0, ∞}]^0.5
p0 = p = Sqrt[k2];
Dynamic @ Image @ im[p0 += p]
Comments
Post a Comment