Mandelbrot Set Example


This example is a Mandelbrot Set Generation Playground making use of Atomic Operations, enabling multiple threads to modify a single piece of data in parallel without expensive memory copies.

The Mandelbrot set is a collection of complex numbers that forms a fractal, named after mathematician Benoît B. Mandelbrot. It is defined by iterating the function 𝑓𝑐(𝑧)=𝑧2+𝑐fc​ (z)=z2 +c, where 𝑧z starts at zero, and 𝑐c is a complex parameter. The set consists of all complex values of 𝑐c for which the sequence does not escape to infinity. Visually, the Mandelbrot set displays an intricate, infinitely detailed boundary with self-similar patterns, making it a key example in the study of chaotic systems and complex dynamics.

Provided example will generate 10 frames of the mandelbrot set at different zoom levels using the number of selected threads, and display the average rendering time of all 10 frames.

You can play around with the different settings to see how those inpact the performance and results of the simulation, the full source code is available on the github repository page.


                    
                      const mandelbrotOperator = function () {
                        const sharedArray = params.sharedArray;
                        const maxIterations = params.maxIterations;
                        const width = params.width;
                        const height = params.height;
                        const xMin = params.xMin;
                        const xMax = params.xMax;
                        const yMin = params.yMin;
                        const yMax = params.yMax;

                        const map = (value, low1, high1, low2, high2) => low2 + (high2 - low2) * (value - low1) / (high1 - low1);

                        const start = params.index.start || 0;
                        const end = params.index.end;

                        for (let index = start; index <= end; index++) {
                          const x = index % width;
                          const y = Math.floor(index / width);

                          let a = map(x, 0, width, xMin, xMax);
                          let b = map(y, 0, height, yMin, yMax);
                          let n = 0;
                          let z = 0;
                          let zi = 0;

                          while (n < maxIterations) {
                            let aa = z * z - zi * zi + a;
                            let bb = 2 * z * zi + b;
                            z = aa;
                            zi = bb;

                            if (Math.abs(z + zi) > 16) {
                              break;
                            }
                            n++;
                          }

                          Atomics.store(sharedArray, index, n);
                        }
                      };
                      
                      function renderNextZoom(mandelbrotSet) {
                        if (currentZoom < zoomLevels.length && isRendering) {
                          const params = {
                            sharedArray: mandelbrotSet,
                            maxIterations: maxIterations,
                            width: width,
                            height: height,
                            dataType: 'Uint32',
                            threads: parseInt(document.getElementById('threadCount').value, 10) || 1 // Number of threads
                          };

                          const startTime = performance.now();

                          hamsters.promise(params, mandelbrotOperator).then((newMandelbrotSet) => {
                            if (!isRendering) return; // Exit if rendering was stopped
                            drawMandelbrot(newMandelbrotSet);
                            currentZoom++;
                            setTimeout(() => renderNextZoom(newMandelbrotSet), 4); // Wait for 4ms before rendering the next zoom level
                          });
                        }
                      }

                      function drawMandelbrot(mandelbrotSet) {
                        loadPixels();
                        for (let index = 0; index < width * height; index++) {
                          let n = mandelbrotSet[index];
                          let x = index % width;
                          let y = Math.floor(index / width);
                          let brightness = map(n, 0, maxIterations, 0, 255);

                          let pixelIndex = (x + y * width) * 4;
                          pixels[pixelIndex] = brightness;        // Red
                          pixels[pixelIndex + 1] = brightness;    // Green
                          pixels[pixelIndex + 2] = brightness;    // Blue
                          pixels[pixelIndex + 3] = 255;           // Alpha
                        }
                        updatePixels();
                      }
                    
                

Client Summary

  • Hamsters.js Version:
  • Maximum Threads:
  • Browser:
  • Legacy Mode:
  • Atomic Operations Support:
  • Transferable Object Support:




Results

Frame: 0/10

Average Rendering Time: 0 ms