  Play with vars

What are the important variables? Obviously, Z and C. Then, what would happen if we changed the number of Zs calculated for a C? And what about increasing the number of Cs to check before painting the image?

it's important to realize that what we're trying here is to create images of great aesthetic beauty. We've seen this "mathematica object" cannot be faithfully represented; what we want is a series of spectacular pictures, leaving its exactitude to the artist's taste:

Modifying Cs

The number of Cs checked could be associated with the image resolution. Inspecting few Cs would result in a picture representing few points outside M.

As far as I know, checking 100 Cs per pixel produces quite a smooth finish. In the example code, 10000 Cs are inspected per axis, since it's a 1000x1000 image; hence, we're looking at 108 Cs on the complex plane.

To illustrate what happens as we check more Cs, I've prepared this animation (left). We start checking 1 C per pixel, and finish with 10000. By the way, `maxN` is set to 1000.

Modifying Zs

Whereas increasing the number of Cs produces pictures essentially very similar, changing the number of Zs has a significant impact on the image we'll be looking at. Just take a look at this animation, where `maxN` goes from 1 to 10000 (where we checked 100 Cs per pixel).

Impressive, right? Is that really the same "object"? The explanation is this: if `maxN` is very small, many Cs ouside M get confused with part of the set, and their trajectories never get painted. For example, if we paint a Buddhabrot with `maxN` = 1, we'll get a black circle -since Z1 equals C, and C is always inside the examined complex plane, all Cs within radius 2 from the origin of coordinates are taken as part of M, and nothing gets painted.

On the other extreme, when `maxN` is huge, certaing initially blurry shapes -the buddha's 'shoulders'- or plain invisible -the flying 'mini-Buddhabrots'- become apparent.

Fact: the closer a C outside M is to the border, the larger `maxN` will have to be not to confuse it with part of the set. Consequently, it would be a good idea to increase `maxN` as we examine more and more Cs on the plane.

Coloring the Buddhabrot

This process is analogous to coloring telescopic images. For these, light is not registeres with regular cameras, instead, emissions from different kinds of atoms are captured with electronic detectors, thus producing gray-scale images. Then they assign a different color channel to different takes, merge them on the same picture, et voilà, they've got color.

As Green suggests, we can take advantage of the fact that different `maxN` give place to different "versions" of the same objectto color the Buddhabrot. We have to create 3 images -one for each color channel- with different `maxN`, and merge them.

The code should look like this:

```import java.awt.image.*;

public static BufferedImage generaBuddhaBrot() {
int i, j, rojo, verde, azul, maxRojo = 50, maxVerde = 500, maxAzul = 5000;
int lado = 1000;
float increm = 4 / 10000f;

int[] pixels = new int[lado * lado];
BufferedImage imagen;

// We generate an image for each color channel using different 'maxN'.
float[][] pixelsRojos  = getPixels(maxRojo, increm, lado);
float[][] pixelsVerdes = getPixels(maxVerde, increm, lado);
float[][] pixelsAzules = getPixels(maxAzul, increm, lado);

// We merge the three color channels on one image.

float factorRojo  = 255f / encuentraMax(pixelsRojos);
float factorVerde = 255f / encuentraMax(pixelsVerdes);
float factorAzul  = 255f / encuentraMax(pixelsAzules);
for (i = 0; i < ancho; i++) for (j = 0; j < alto; j++) {
rojo  = (int)(pixelsRojos[i][j] * factorRojo);
verde = (int)(pixelsVerdes[i][j] * factorVerde);
azul  = (int)(pixelsAzules[i][j] * factorAzul);
pixels[i * ancho + j] = rojo << 16 | verde << 8 | azul;
}
return imagen;
}

private static float[][] getPixels(int maxN, float increm, int lado) {
int i, n, coordX, coordY;
float Cr, Ci, Zr, Zi, ZrAux, ZiAux;
float[][] trayectoria = new float[maxN];

for (Cr = -2; Cr < 2; Cr += increm) for (Ci = -2; Ci < 2; Ci += increm) {
ZrAux = ZiAux = 0;
for (n = 0; n < maxN; n++) {
Zr = calculaReal(ZrAux, ZiAux, Cr);
Zi = calculaImaginaria(ZrAux, ZiAux, Ci);
trayectoria[n] = ZrAux = Zr;
trayectoria[n] = ZiAux = Zi;
if (Zr * Zr + Zi * Zi > 4) break;
}
if (n < maxN)

for (i = 0; i < n; i++) {
coordX = (int)(((trayectoria[i] + 2) / 4) * ancho);
coordY = (int)(((trayectoria[i] + 2) / 4) * alto);
if (coordX < 0 || coordX >= ancho || coordY < 0 || coordY >= alto)
continue;
pixels[coordX][coordY]++;
}
}
return pixels;
}```

The pixels array now gets filled in a conveniency method, `getPixels(int maxN, float increm, int lado)`, that takes arguments to modify the number of Zs and Cs checked, and the dimensions of the image to generate.