๐ŸŽ‡ Hairline on noise field

BamgasiJMยท2026๋…„ 1์›” 23์ผ

p5.js Art

๋ชฉ๋ก ๋ณด๊ธฐ
55/67
post-thumbnail

๐Ÿ“ p5.js

const noiseScale = 0.0005;
const numCurves = 1000;
let curves = [];

function setup() {
  createCanvas(1000, 1000);
  background(0);
  noiseSeed(1000);

  for (let i = 0; i < numCurves; i++) {
    curves.push(new FlowCurve());
  }
}

function draw() {
  background(0, 20);

  for (let curve of curves) {
    curve.update();
    curve.display();
  }
}

class FlowCurve {
  constructor() {
    this.pos = createVector(random(width), random(height));
    this.history = [];
    this.maxLength = floor(random(30, 80));
    this.strokeW = random(0.1, 0.3);
    this.speed = random(1, 5);
    this.age = 0;
    this.lifespan = this.maxLength + random(300, 500);
    this.growthPhase = this.maxLength;
    this.dying = false;
  }

  update() {
    this.age++;

    // ์„ฑ์žฅ ๋‹จ๊ณ„: ์ ์ง„์ ์œผ๋กœ ๊ธธ์–ด์ง
    if (this.age < this.growthPhase) {
      this.updatePosition();
    }
    // ์„ฑ์ˆ™ ๋‹จ๊ณ„: ์ตœ๋Œ€ ๊ธธ์ด ์œ ์ง€
    else if (this.age < this.lifespan - this.maxLength) {
      this.updatePosition();
    }
    // ์†Œ๋ฉธ ๋‹จ๊ณ„: ๊ผฌ๋ฆฌ๋ถ€ํ„ฐ ์‚ฌ๋ผ์ง
    else {
      this.dying = true;
      if (this.history.length > 0) {
        this.history.shift();
      }
    }

    // ์™„์ „ํžˆ ์†Œ๋ฉธํ•˜๋ฉด ์žฌ์ƒ์„ฑ
    if (this.dying && this.history.length === 0) {
      this.pos.set(random(width), random(height));
      this.history = [];
      this.age = 0;
      this.lifespan = this.maxLength + random(300, 500);
      this.dying = false;
    }

    // ํ™”๋ฉด ๋ฐ–์œผ๋กœ ๋‚˜๊ฐ€๋ฉด ์žฌ์ƒ์„ฑ
    if (
      this.pos.x < -10 ||
      this.pos.x > width + 10 ||
      this.pos.y < -10 ||
      this.pos.y > height + 10
    ) {
      this.pos.set(random(width), random(height));
      this.history = [];
      this.age = 0;
      this.lifespan = this.maxLength + random(300, 500);
      this.dying = false;
    }
  }

  updatePosition() {
    let angle =
      noise(this.pos.x * noiseScale, this.pos.y * noiseScale) * TWO_PI * 2;
    this.pos.x += cos(angle) * this.speed;
    this.pos.y += sin(angle) * this.speed;

    this.history.push(this.pos.copy());
    if (this.history.length > this.maxLength) {
      this.history.shift();
    }
  }

  display() {
    const len = this.history.length;
    if (len < 2) return;

    noFill();

    for (let i = 0; i < len - 1; i++) {
      let t = i / (len - 1);
      let alpha = (1 - t) * 255;

      stroke(255, alpha);
      strokeWeight(this.strokeW * (1 - t * 0.5));

      let p1 = this.history[i];
      let p2 = this.history[i + 1];
      line(p1.x, p1.y, p2.x, p2.y);
    }
  }
}

// ๋…ธ์ด์ฆˆ ์Šค์ผ€์ผ: Perlin ๋…ธ์ด์ฆˆ์˜ ์ƒ˜ํ”Œ๋ง ๊ฐ„๊ฒฉ์„ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค.
// ๊ฐ’์ด ์ž‘์„์ˆ˜๋ก ๋” ๋„“๊ณ  ๋ถ€๋“œ๋Ÿฌ์šด ํ๋ฆ„์ด ์ƒ์„ฑ๋˜๊ณ , ํด์ˆ˜๋ก ๊ธ‰๊ฒฉํ•œ ๋ณ€ํ™”๊ฐ€ ์ƒ๊น๋‹ˆ๋‹ค.
const noiseScale = 0.0005;

// ์ƒ์„ฑํ•  ๊ณก์„ (ํŒŒํ‹ฐํด)์˜ ์ด ๊ฐœ์ˆ˜์ž…๋‹ˆ๋‹ค.
// ๋งŽ์„์ˆ˜๋ก ํ™”๋ฉด์ด ๋” ๋ฐ€์ง‘๋˜๊ณ  ๋ณต์žกํ•œ ํŒจํ„ด์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
const numCurves = 1000;

// ๋ชจ๋“  ๊ณก์„  ๊ฐ์ฒด๋ฅผ ์ €์žฅํ•˜๋Š” ๋ฐฐ์—ด์ž…๋‹ˆ๋‹ค.
let curves = [];

/**
 * setup ํ•จ์ˆ˜: ํ”„๋กœ๊ทธ๋žจ ์‹œ์ž‘ ์‹œ ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.
 * ์บ”๋ฒ„์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ๋…ธ์ด์ฆˆ ์‹œ๋“œ๋ฅผ ๊ณ ์ •ํ•˜๋ฉฐ, ๊ณก์„  ๊ฐ์ฒด๋“ค์„ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค.
 */
function setup() {
  // 1000x1000 ํ”ฝ์…€์˜ ์บ”๋ฒ„์Šค๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
  createCanvas(1000, 1000);
  
  // ๋ฐฐ๊ฒฝ์„ ๊ฒ€์€์ƒ‰(0)์œผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
  background(0);
  
  // Perlin ๋…ธ์ด์ฆˆ์˜ ์‹œ๋“œ๋ฅผ 1000์œผ๋กœ ๊ณ ์ •ํ•ฉ๋‹ˆ๋‹ค.
  // ์‹œ๋“œ๋ฅผ ๊ณ ์ •ํ•˜๋ฉด ์‹คํ–‰ํ•  ๋•Œ๋งˆ๋‹ค ๋™์ผํ•œ ๋…ธ์ด์ฆˆ ํŒจํ„ด์ด ์ƒ์„ฑ๋˜์–ด ์žฌํ˜„ ๊ฐ€๋Šฅํ•œ ๊ฒฐ๊ณผ๋ฅผ ์–ป์Šต๋‹ˆ๋‹ค.
  noiseSeed(1000);

  // numCurves ๊ฐœ์ˆ˜๋งŒํผ ๊ณก์„  ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ๋ฐฐ์—ด์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
  for (let i = 0; i < numCurves; i++) {
    curves.push(new FlowCurve());
  }
}

/**
 * draw ํ•จ์ˆ˜: ๋งค ํ”„๋ ˆ์ž„(๋ณดํ†ต ์ดˆ๋‹น 60ํšŒ)๋งˆ๋‹ค ๋ฐ˜๋ณต ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.
 * ๋ฐฐ๊ฒฝ์„ ์ง€์šฐ๊ณ (์ž”์ƒ ํšจ๊ณผ๋ฅผ ์œ„ํ•ด ํˆฌ๋ช…ํ•˜๊ฒŒ), ๋ชจ๋“  ๊ณก์„ ์„ ์—…๋ฐ์ดํŠธํ•˜๊ณ  ๊ทธ๋ฆฝ๋‹ˆ๋‹ค.
 */
function draw() {
  // ๋ฐฐ๊ฒฝ์„ ๊ฒ€์€์ƒ‰์œผ๋กœ ๋ฎ๋˜, ์•ŒํŒŒ๊ฐ’ 20์„ ์‚ฌ์šฉํ•˜์—ฌ ์ž”์ƒ(trail) ํšจ๊ณผ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
  // ์•ŒํŒŒ๊ฐ’์ด ๋‚ฎ์„์ˆ˜๋ก ์ด์ „ ํ”„๋ ˆ์ž„์ด ์ฒœ์ฒœํžˆ ์‚ฌ๋ผ์ ธ ๋ถ€๋“œ๋Ÿฌ์šด ์ž”์ƒ์ด ๋‚จ์Šต๋‹ˆ๋‹ค.
  background(0, 20);

  // curves ๋ฐฐ์—ด์˜ ๋ชจ๋“  ๊ณก์„  ๊ฐ์ฒด๋ฅผ ์ˆœํšŒํ•˜๋ฉฐ ์—…๋ฐ์ดํŠธ์™€ ํ‘œ์‹œ๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  for (let curve of curves) {
    curve.update();    // ์œ„์น˜์™€ ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.
    curve.display();   // ํ™”๋ฉด์— ๊ทธ๋ฆฝ๋‹ˆ๋‹ค.
  }
}

/**
 * FlowCurve ํด๋ž˜์Šค: ๊ฐ๊ฐ์˜ ํ๋ฆ„ ๊ณก์„ ์„ ๋‚˜ํƒ€๋‚ด๋Š” ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค.
 * ์œ„์น˜ ์ด๋ ฅ(history)์„ ์ €์žฅํ•˜์—ฌ ๊ผฌ๋ฆฌ์ฒ˜๋Ÿผ ๋ณด์ด๊ฒŒ ํ•˜๊ณ , 
 * ์„ฑ์žฅโ†’์„ฑ์ˆ™โ†’์†Œ๋ฉธ์˜ ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค.
 */
class FlowCurve {
  /**
   * ์ƒ์„ฑ์ž: ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋  ๋•Œ ์ดˆ๊ธฐ ์†์„ฑ์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
   */
  constructor() {
    // ํ˜„์žฌ ์œ„์น˜๋ฅผ ํ™”๋ฉด ๋‚ด ๋ฌด์ž‘์œ„ ์ขŒํ‘œ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
    // createVector๋Š” x, y ์ขŒํ‘œ๋ฅผ ๊ฐ€์ง„ ๋ฒกํ„ฐ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
    this.pos = createVector(random(width), random(height));
    
    // ๊ณผ๊ฑฐ ์œ„์น˜๋“ค์„ ์ €์žฅํ•˜๋Š” ๋ฐฐ์—ด์ž…๋‹ˆ๋‹ค.
    // ์„ ์„ ๊ทธ๋ฆด ๋•Œ ์ด์ „ ์œ„์น˜๋“ค์„ ์—ฐ๊ฒฐํ•˜์—ฌ ๊ผฌ๋ฆฌ ๋ชจ์–‘์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
    this.history = [];
    
    // ๊ผฌ๋ฆฌ์˜ ์ตœ๋Œ€ ๊ธธ์ด(ํžˆ์Šคํ† ๋ฆฌ ๋ฐฐ์—ด์˜ ์ตœ๋Œ€ ํฌ๊ธฐ)์ž…๋‹ˆ๋‹ค.
    // 30์—์„œ 80 ์‚ฌ์ด์˜ ๋ฌด์ž‘์œ„ ์ •์ˆ˜๋กœ ์„ค์ •๋ฉ๋‹ˆ๋‹ค.
    this.maxLength = floor(random(30, 80));
    
    // ์„ ์˜ ๊ตต๊ธฐ์ž…๋‹ˆ๋‹ค. 0.1์—์„œ 0.3 ์‚ฌ์ด์˜ ๋งค์šฐ ๊ฐ€๋Š” ์„ ์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
    this.strokeW = random(0.1, 0.3);
    
    // ์ด๋™ ์†๋„์ž…๋‹ˆ๋‹ค. 1์—์„œ 5 ์‚ฌ์ด์˜ ๋ฌด์ž‘์œ„ ๊ฐ’์œผ๋กœ,
    // ๋…ธ์ด์ฆˆ ํ•„๋“œ๋ฅผ ๋”ฐ๋ผ ์ด๋™ํ•˜๋Š” ์†๋„๋ฅผ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค.
    this.speed = random(1, 5);
    
    // ๊ฐ์ฒด์˜ ํ˜„์žฌ ๋‚˜์ด(ํ”„๋ ˆ์ž„ ์ˆ˜)์ž…๋‹ˆ๋‹ค.
    // ์ƒ๋ช…์ฃผ๊ธฐ ๊ด€๋ฆฌ์— ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
    this.age = 0;
    
    // ์ „์ฒด ์ˆ˜๋ช…(ํ”„๋ ˆ์ž„ ์ˆ˜)์ž…๋‹ˆ๋‹ค.
    // maxLength(์„ฑ์žฅ/์†Œ๋ฉธ ๋‹จ๊ณ„) + 300~500(์„ฑ์ˆ™ ๋‹จ๊ณ„)์œผ๋กœ ๊ณ„์‚ฐ๋ฉ๋‹ˆ๋‹ค.
    this.lifespan = this.maxLength + random(300, 500);
    
    // ์„ฑ์žฅ ๋‹จ๊ณ„์˜ ๊ธธ์ด์ž…๋‹ˆ๋‹ค.
    // maxLength๋งŒํผ ์„ฑ์žฅํ•˜์—ฌ ์ตœ๋Œ€ ๊ธธ์ด์— ๋„๋‹ฌํ•ฉ๋‹ˆ๋‹ค.
    this.growthPhase = this.maxLength;
    
    // ์†Œ๋ฉธ ์ค‘์ธ์ง€ ์—ฌ๋ถ€๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ํ”Œ๋ž˜๊ทธ์ž…๋‹ˆ๋‹ค.
    this.dying = false;
  }

  /**
   * update ๋ฉ”์„œ๋“œ: ๋งค ํ”„๋ ˆ์ž„๋งˆ๋‹ค ๊ฐ์ฒด์˜ ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.
   * ์„ฑ์žฅ, ์„ฑ์ˆ™, ์†Œ๋ฉธ ๋‹จ๊ณ„๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ  ํ™”๋ฉด ๋ฐ–์œผ๋กœ ๋‚˜๊ฐ€๋ฉด ์žฌ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
   */
  update() {
    // ๋‚˜์ด๋ฅผ 1 ์ฆ๊ฐ€์‹œํ‚ต๋‹ˆ๋‹ค.
    this.age++;

    // 1๋‹จ๊ณ„: ์„ฑ์žฅ ๋‹จ๊ณ„
    // ๋‚˜์ด๊ฐ€ growthPhase๋ณด๋‹ค ์ž‘์„ ๋•Œ๋Š” ๊ผฌ๋ฆฌ๊ฐ€ ์ ์  ๊ธธ์–ด์ง‘๋‹ˆ๋‹ค.
    if (this.age < this.growthPhase) {
      this.updatePosition();
    }
    // 2๋‹จ๊ณ„: ์„ฑ์ˆ™ ๋‹จ๊ณ„
    // ์ตœ๋Œ€ ๊ธธ์ด๋ฅผ ์œ ์ง€ํ•˜๋ฉฐ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.
    // ์ˆ˜๋ช…์ด lifespan - maxLength์— ๋„๋‹ฌํ•  ๋•Œ๊นŒ์ง€ ์ง€์†๋ฉ๋‹ˆ๋‹ค.
    else if (this.age < this.lifespan - this.maxLength) {
      this.updatePosition();
    }
    // 3๋‹จ๊ณ„: ์†Œ๋ฉธ ๋‹จ๊ณ„
    // ๊ผฌ๋ฆฌ๊ฐ€ ๋จธ๋ฆฌ๋ถ€ํ„ฐ ์ ์  ์งง์•„์ง‘๋‹ˆ๋‹ค(shift๋กœ ์•ž๋ถ€๋ถ„ ์ œ๊ฑฐ).
    else {
      this.dying = true;
      if (this.history.length > 0) {
        // ๋ฐฐ์—ด์˜ ์ฒซ ๋ฒˆ์งธ ์š”์†Œ(๊ฐ€์žฅ ์˜ค๋ž˜๋œ ์œ„์น˜)๋ฅผ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.
        this.history.shift();
      }
    }

    // ์™„์ „ํžˆ ์†Œ๋ฉธํ•˜๋ฉด(ํžˆ์Šคํ† ๋ฆฌ๊ฐ€ ๋น„๋ฉด) ์ƒˆ๋กœ์šด ์œ„์น˜์—์„œ ์žฌ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
    if (this.dying && this.history.length === 0) {
      this.reset();
    }

    // ํ™”๋ฉด ๋ฐ–์œผ๋กœ ๋‚˜๊ฐ€๋ฉด(์—ฌ๋ฐฑ 10ํ”ฝ์…€) ์ฆ‰์‹œ ์žฌ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
    if (
      this.pos.x < -10 ||
      this.pos.x > width + 10 ||
      this.pos.y < -10 ||
      this.pos.y > height + 10
    ) {
      this.reset();
    }
  }

  /**
   * reset ๋ฉ”์„œ๋“œ: ๊ฐ์ฒด๋ฅผ ์ดˆ๊ธฐ ์ƒํƒœ๋กœ ๋ฆฌ์…‹ํ•˜์—ฌ ์ƒˆ๋กœ์šด ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.
   */
  reset() {
    // ์œ„์น˜๋ฅผ ํ™”๋ฉด ๋‚ด ๋ฌด์ž‘์œ„๋กœ ์žฌ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
    this.pos.set(random(width), random(height));
    // ํžˆ์Šคํ† ๋ฆฌ๋ฅผ ๋น„์›๋‹ˆ๋‹ค.
    this.history = [];
    // ๋‚˜์ด๋ฅผ 0์œผ๋กœ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค.
    this.age = 0;
    // ์ƒˆ๋กœ์šด ์ˆ˜๋ช…์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
    this.lifespan = this.maxLength + random(300, 500);
    // ์†Œ๋ฉธ ์ƒํƒœ๋ฅผ ํ•ด์ œํ•ฉ๋‹ˆ๋‹ค.
    this.dying = false;
  }

  /**
   * updatePosition ๋ฉ”์„œ๋“œ: Perlin ๋…ธ์ด์ฆˆ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค์Œ ์œ„์น˜๋ฅผ ๊ณ„์‚ฐํ•˜๊ณ  ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.
   */
  updatePosition() {
    // ํ˜„์žฌ ์œ„์น˜์— Perlin ๋…ธ์ด์ฆˆ๋ฅผ ์ ์šฉํ•˜์—ฌ ๊ฐ๋„๋ฅผ ๊ณ„์‚ฐํ•ฉ๋‹ˆ๋‹ค.
    // noiseScale์„ ๊ณฑํ•˜์—ฌ ์ƒ˜ํ”Œ๋ง ์œ„์น˜๋ฅผ ์กฐ์ •ํ•˜๊ณ , TWO_PI * 2(720๋„) ๋ฒ”์œ„๋กœ ๋งคํ•‘ํ•ฉ๋‹ˆ๋‹ค.
    let angle =
      noise(this.pos.x * noiseScale, this.pos.y * noiseScale) * TWO_PI * 2;
    
    // ์‚ผ๊ฐํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ x, y ๋ฐฉํ–ฅ์œผ๋กœ ์ด๋™๋Ÿ‰์„ ๊ณ„์‚ฐํ•ฉ๋‹ˆ๋‹ค.
    this.pos.x += cos(angle) * this.speed;
    this.pos.y += sin(angle) * this.speed;

    // ํ˜„์žฌ ์œ„์น˜๋ฅผ ํžˆ์Šคํ† ๋ฆฌ ๋ฐฐ์—ด์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค(๋ณต์‚ฌ๋ณธ์„ ์ €์žฅ).
    this.history.push(this.pos.copy());
    
    // ํžˆ์Šคํ† ๋ฆฌ๊ฐ€ maxLength๋ฅผ ์ดˆ๊ณผํ•˜๋ฉด ๊ฐ€์žฅ ์˜ค๋ž˜๋œ ์œ„์น˜๋ฅผ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.
    if (this.history.length > this.maxLength) {
      this.history.shift();
    }
  }

  /**
   * display ๋ฉ”์„œ๋“œ: ํžˆ์Šคํ† ๋ฆฌ ๋ฐฐ์—ด์˜ ์ ๋“ค์„ ์„ ์œผ๋กœ ์—ฐ๊ฒฐํ•˜์—ฌ ํ™”๋ฉด์— ๊ทธ๋ฆฝ๋‹ˆ๋‹ค.
   * ๊ทธ๋ผ๋ฐ์ด์…˜ ํšจ๊ณผ๋ฅผ ์œ„ํ•ด ์„ ๋ถ„๋งˆ๋‹ค ํˆฌ๋ช…๋„๋ฅผ ๋‹ค๋ฅด๊ฒŒ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค.
   */
  display() {
    // ํžˆ์Šคํ† ๋ฆฌ ๊ธธ์ด๋ฅผ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
    const len = this.history.length;
    // ์ ์ด 2๊ฐœ ๋ฏธ๋งŒ์ด๋ฉด ์„ ์„ ๊ทธ๋ฆด ์ˆ˜ ์—†์œผ๋ฏ€๋กœ ์ข…๋ฃŒํ•ฉ๋‹ˆ๋‹ค.
    if (len < 2) return;

    // ์ฑ„์šฐ๊ธฐ ์—†์ด ์„ ๋งŒ ๊ทธ๋ฆฝ๋‹ˆ๋‹ค.
    noFill();

    // ํžˆ์Šคํ† ๋ฆฌ์˜ ๊ฐ ์ ์„ ์ˆœํšŒํ•˜๋ฉฐ ์„ ๋ถ„์„ ๊ทธ๋ฆฝ๋‹ˆ๋‹ค.
    for (let i = 0; i < len - 1; i++) {
      // ํ˜„์žฌ ์ธ๋ฑ์Šค๋ฅผ 0~1 ๋ฒ”์œ„๋กœ ์ •๊ทœํ™”ํ•ฉ๋‹ˆ๋‹ค.
      // t=0์€ ๊ผฌ๋ฆฌ(์˜ค๋ž˜๋œ ๋ถ€๋ถ„), t=1์€ ๋จธ๋ฆฌ(์ƒˆ๋กœ์šด ๋ถ€๋ถ„)์ž…๋‹ˆ๋‹ค.
      let t = i / (len - 1);
      
      // ํˆฌ๋ช…๋„๋ฅผ ๊ณ„์‚ฐํ•ฉ๋‹ˆ๋‹ค.
      // t๊ฐ€ 0(๊ผฌ๋ฆฌ)์ผ ๋•Œ alpha=255(๋ถˆํˆฌ๋ช…),
      // t๊ฐ€ 1(๋จธ๋ฆฌ)์— ๊ฐ€๊นŒ์šธ์ˆ˜๋ก alpha๊ฐ€ 0์— ๊ฐ€๊นŒ์›Œ์ง‘๋‹ˆ๋‹ค.
      // ๊ทธ๋Ÿฌ๋‚˜ ์—ฌ๊ธฐ์„œ๋Š” (1-t)๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ผฌ๋ฆฌ๊ฐ€ ํ๋ฆฟํ•˜๊ฒŒ, ๋จธ๋ฆฌ๊ฐ€ ์„ ๋ช…ํ•˜๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
      let alpha = (1 - t) * 255;

      // ํฐ์ƒ‰(255)์— ๊ณ„์‚ฐ๋œ ํˆฌ๋ช…๋„๋ฅผ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค.
      stroke(255, alpha);
      
      // ์„  ๊ตต๊ธฐ๋„ t์— ๋”ฐ๋ผ ๋ณ€ํ™”์‹œํ‚ต๋‹ˆ๋‹ค.
      // ๋จธ๋ฆฌ(t=1)์ชฝ์œผ๋กœ ๊ฐˆ์ˆ˜๋ก ๊ฐ€๋Š˜์–ด์ง‘๋‹ˆ๋‹ค(0.5๋ฐฐ).
      strokeWeight(this.strokeW * (1 - t * 0.5));

      // ํ˜„์žฌ ์ ๊ณผ ๋‹ค์Œ ์ ์„ ์—ฐ๊ฒฐํ•˜๋Š” ์„ ์„ ๊ทธ๋ฆฝ๋‹ˆ๋‹ค.
      let p1 = this.history[i];
      let p2 = this.history[i + 1];
      line(p1.x, p1.y, p2.x, p2.y);
    }
  }
}

profile
Coding Art with Blender / oF / Processing / p5.js / nannou

0๊ฐœ์˜ ๋Œ“๊ธ€