使用 p5.js 为 mandelbrot 设置平滑颜色

问题描述 投票:0回答:1

我正在使用 p5.js 尝试重新创建 Mandelbrot 集。 我已经创建了该集合本身,但我在以正确的方式着色时遇到问题。

我已经跟踪了 wiki 页面中的伪代码,但我无法用正确的颜色对其进行着色。

这是我写的p5.js代码:

let slider;

function setup() {
  createCanvas(400, 400);
  background(51)
  colorMode(HSL, 360, 100, 100)
  slider = createSlider(10, 1000, 500, 1)
}

let k = 0;

function draw() {
  loadPixels()

  for (let i = 0; i < width; i++) {
    for (let j = 0; j < height; j++) {
      let index = (i + j * width) * 4
      let x0 = map(i, 0, width, -2.0, 0.47);
      let y0 = map(j, 0, height, -1.12, 1.12);

      let x = 0;
      let y = 0;

      let iteration = 0;
      let maxIteration = slider.value();

      while (magn(x, y) <= 4 && iteration < maxIteration) {
        let xTemp = x * x - y * y + x0;
        y = 2 * x * y + y0;
        x = xTemp;
        iteration++

      }

      pixels[index + 0] = pow(iteration / maxIteration * 360, 1.5) % 360
      pixels[index + 1] = 50
      pixels[index + 2] = (iteration / maxIteration) * 100

    }
  }
  
  updatePixels()
}

function magn(a, b) {
  return a * a + b * b;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.8.0/p5.js"></script>

这是生成的图像:

mandelbrot set

图像本身还不错,但我不明白为什么我的背景颜色是绿色的,而且我无法获得维基页面中显示的颜色。

我想要一个类似于这个guy的效果,但我无法用c代码理解它。

javascript p5.js complex-numbers mandelbrot
1个回答
0
投票

在您链接到的代码中,着色器(第一个代码片段是 GLSL 而不是 C)根据当前种子点转义所需的 maxIterations 分数从 1d 纹理获取颜色值。因此,如果不知道他们如何生成构成该纹理的颜色,就很难推断出他们正在使用的算法。

但是,在您的代码中存在一些可识别的问题:1)无论颜色模式如何,像素数组始终使用 RGB,2)当您使用高 maxIterations 值时,您看到的许多点最终会非常相似,低,值。这是因为当查看缩小的曼德尔布罗特集时,许多距离边界不太近的点在几次迭代后就会逃逸,因此所有这些点最终都会具有非常相似(并且非常暗)的颜色。

因此,要解决此问题,您需要手动将所需的 HSV 值转换为 RGB 以在像素数组中使用,并减少默认的 maxIterations 值。

let slider;

function setup() {
  createCanvas(400, 400);
  pixelDensity(1)
  background(51)
  // This had no effect
  // colorMode(HSL, 360, 100, 100)
  
  // Decreased the default to 80 instead of 500
  slider = createSlider(10, 1000, 80, 1)
  
  // Avoid unnecessary re-renders
  slider.input(() => {
    redraw();
  });
  noLoop();
}

let k = 0;

function draw() {
  loadPixels()

  for (let i = 0; i < width; i++) {
    for (let j = 0; j < height; j++) {
      let index = (i + j * width) * 4
      let x0 = map(i, 0, width, -2.0, 0.47);
      let y0 = map(j, 0, height, -1.12, 1.12);

      let x = 0;
      let y = 0;

      let iteration = 0;
      let maxIteration = slider.value();

      while (magn(x, y) <= 4 && iteration < maxIteration) {
        let xTemp = x * x - y * y + x0;
        y = 2 * x * y + y0;
        x = xTemp;
        iteration++

      }
      
      if (iteration < maxIteration) {
        let [r, g, b] = hsv2rgb(
          pow(iteration / maxIteration * 360, 1.5) % 360,
          0.5,
          (iteration / maxIteration) * 0.8 + 0.2
        );

        pixels[index + 0] = r * 255;
        pixels[index + 1] = g * 255;
        pixels[index + 2] = b * 255;
      } else {
        pixels[index + 0] = 0;
        pixels[index + 1] = 0;
        pixels[index + 2] = 0;
      }

    }
  }
  
  updatePixels()
}

function magn(a, b) {
  return a * a + b * b;
}

// Source: https://stackoverflow.com/a/54024653/229247
// Author: Kamil Kiełczewski
// CC-BY-SA 4.0 
function hsv2rgb(h, s, v) {                              
  function f(n) {
    const k = (n + h / 60) % 6;
    return v - v * s * Math.max(Math.min(k, 4 - k, 1), 0);     
  }
  return [f(5),f(3),f(1)];       
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.8.0/p5.js"></script>

© www.soinside.com 2019 - 2024. All rights reserved.