๐ŸŒŸ p5.js ์ปฌ๋Ÿฌ Part. 3 : ์ƒ‰์ƒ ๋ณด๊ฐ„๊ณผ Lerp

BamgasiJMยท2025๋…„ 11์›” 29์ผ

p5.js Art

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

p5.js๋ฅผ ํฌํ•จํ•œ ๋Œ€๋ถ€๋ถ„์˜ ๊ทธ๋ž˜ํ”ฝ ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์ƒ‰์ƒ ๋ณด๊ฐ„(Color Interpolation), ํŠนํžˆ Lerp (Linear Interpolation)์— ๋Œ€ํ•œ ์„ค๋ช…์ž…๋‹ˆ๋‹ค.


1. ์„ ํ˜• ๋ณด๊ฐ„(Linear Interpolation, Lerp)์˜ ๊ฐœ๋…

Lerp๋Š” ๊ฐ€์žฅ ์ผ๋ฐ˜์ ์ธ ํ˜•ํƒœ์˜ ๋ณด๊ฐ„์œผ๋กœ, ๋‘ ๊ฐ’ A์™€ B ์‚ฌ์ด๋ฅผ ์ง์„ ์ ์œผ๋กœ ์—ฐ๊ฒฐํ•˜๋Š” ์ค‘๊ฐ„๊ฐ’ V๋ฅผ ์ฐพ๋Š” ์ˆ˜ํ•™์  ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

๐Ÿ“ Lerp์˜ ์ˆ˜ํ•™์  ๊ณต์‹

Lerp ํ•จ์ˆ˜๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ •์˜๋ฉ๋‹ˆ๋‹ค:

V=A+(Bโˆ’A)ร—tV = A + (B - A) ร— t

  • VV : ๊ฒฐ๊ณผ ๊ฐ’
  • AA : ์‹œ์ž‘ ๊ฐ’ (Start Value)
  • BB : ๋ ๊ฐ’ (End Value)
  • tt : ๋ณด๊ฐ„ ๊ณ„์ˆ˜ (Interpolation Factor), 0.0์—์„œ 1.0 ์‚ฌ์ด์˜ ๊ฐ’

tt ๊ฐ’์— ๋”ฐ๋ฅธ ๊ฒฐ๊ณผ:

t ๊ฐ’๊ฒฐ๊ณผ V์˜๋ฏธ
0.0A์‹œ์ž‘ ๊ฐ’๊ณผ ๋™์ผ
0.25A + (B-A)ร—0.25์‹œ์ž‘์ ์—์„œ 25% ์ง€์ 
0.5(A+B)/2์ •ํ™•ํžˆ ์ค‘๊ฐ„
0.75A + (B-A)ร—0.75๋์ ์—์„œ 25% ์ „
1.0B๋ ๊ฐ’๊ณผ ๋™์ผ

A์™€ B์˜ ๋น„์œจ์ด t์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง€๋Š” ์›๋ฆฌ๋Š” ์ด๋ ‡๊ฒŒ ์ดํ•ดํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

  • t=0์ผ ๋•Œ: 100% A, 0% B
  • t=0.3์ผ ๋•Œ: 70% A, 30% B
  • t=0.5์ผ ๋•Œ: 50% A, 50% B
  • t=1์ผ ๋•Œ: 0% A, 100% B

์‹ค์ œ ์ฝ”๋“œ์—์„œ ์ˆซ์ž๋งŒ ๊ฐ€์ง€๊ณ  Lerp๋ฅผ ์ดํ•ดํ•ด๋ด…์‹œ๋‹ค. ์‹œ์ž‘์ด 10์ด๊ณ  ๋์ด 100์ธ ๋ฒ”์œ„๋ฅผ ๋ณด๊ฐ„ํ•˜๋Š” ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.

// ์ˆซ์ž Lerp ์˜ˆ์ œ
function setup() {
  let start = 10;
  let end = 100;
  
  // t=0.0 โ†’ 10
  console.log(lerp(start, end, 0.0));   // 10
  
  // t=0.5 โ†’ 55 (์ค‘๊ฐ„๊ฐ’)
  console.log(lerp(start, end, 0.5));   // 55
  
  // t=1.0 โ†’ 100
  console.log(lerp(start, end, 1.0));   // 100
}

2. p5.js์—์„œ์˜ ์ƒ‰์ƒ Lerp

p5.js์—์„œ๋Š” lerpColor() ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ƒ‰์ƒ์„ ๋ณด๊ฐ„ํ•ฉ๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ ์ƒ‰์ƒ์˜ ๊ฐ ์ฑ„๋„(R, G, B, A ๋“ฑ)์— ๋Œ€ํ•ด ๊ฐœ๋ณ„์ ์œผ๋กœ ์„ ํ˜• ๋ณด๊ฐ„์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

โš™๏ธ lerpColor() ํ•จ์ˆ˜ ๊ตฌ๋ฌธ

lerpColor(c1, c2, amt)

ํŒŒ๋ผ๋ฏธํ„ฐ:

  • c1: ์‹œ์ž‘ ์ƒ‰์ƒ (p5.Color ๊ฐ์ฒด)
  • c2: ๋ ์ƒ‰์ƒ (p5.Color ๊ฐ์ฒด)
  • amt: ๋ณด๊ฐ„ ๊ณ„์ˆ˜ t (0.0์—์„œ 1.0 ์‚ฌ์ด์˜ float ๊ฐ’)

๋ฐ˜ํ™˜๊ฐ’:

  • ๋ณด๊ฐ„๋œ ์ค‘๊ฐ„ ์ƒ‰์ƒ (p5.Color ๊ฐ์ฒด)

๐Ÿ“ ์ƒ‰์ƒ ๋ณด๊ฐ„์˜ ์ž‘๋™ ์›๋ฆฌ

์ƒ‰์ƒ ๋ณด๊ฐ„์€ ์„ ํƒ๋œ ์ƒ‰์ƒ ๋ชจ๋“œ(RGB, HSB ๋“ฑ)์˜ ๊ฐ ์ฑ„๋„์— ๋Œ€ํ•ด ๋…๋ฆฝ์ ์œผ๋กœ Lerp ๊ณต์‹์„ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค.

RGB ๋ชจ๋“œ์—์„œ ์ƒ‰์ƒ Cโ‚ = (Rโ‚, Gโ‚, Bโ‚)๊ณผ Cโ‚‚ = (Rโ‚‚, Gโ‚‚, Bโ‚‚)๋ฅผ t๋งŒํผ ๋ณด๊ฐ„ํ•˜๋ฉด:

R_lerp = Rโ‚ + (Rโ‚‚ - Rโ‚) ร— t
G_lerp = Gโ‚ + (Gโ‚‚ - Gโ‚) ร— t
B_lerp = Bโ‚ + (Bโ‚‚ - Bโ‚) ร— t

๋นจ๊ฐ•(255, 0, 0)๊ณผ ํŒŒ๋ž‘(0, 0, 255)์„ t=0.5๋กœ ๋ณด๊ฐ„ํ•˜๋Š” ๊ณผ์ •์„ ๊ณ„์‚ฐํ•ด๋ณด๋ฉด,

  • R: 255 + (0 - 255) ร— 0.5 = 127.5
  • G: 0 + (0 - 0) ร— 0.5 = 0
  • B: 0 + (255 - 0) ร— 0.5 = 127.5
  • ๊ฒฐ๊ณผ: (127.5, 0, 127.5) โ†’ ๋ณด๋ผ์ƒ‰

์ด๋ ‡๊ฒŒ ๊ณ„์‚ฐ๋˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


3. ๊ธฐ๋ณธ ์‚ฌ์šฉ ์˜ˆ์ œ

์˜ˆ์ œ 1: ๋งˆ์šฐ์Šค ์œ„์น˜๋กœ ์ƒ‰์ƒ ๋ณด๊ฐ„ํ•˜๊ธฐ

let colorA, colorB;

function setup() {
  createCanvas(400, 200);
  
  // ์ƒ‰์ƒ ๊ฐ์ฒด ์ƒ์„ฑ
  colorMode(RGB);
  colorA = color(255, 0, 0);    // ๋นจ๊ฐ„์ƒ‰
  colorB = color(0, 0, 255);    // ํŒŒ๋ž€์ƒ‰
  
  noStroke();
}

function draw() {
  // ๋งˆ์šฐ์Šค X ์ขŒํ‘œ๋ฅผ 0.0~1.0 ์‚ฌ์ด์˜ t ๊ฐ’์œผ๋กœ ๋งคํ•‘
  let t = map(mouseX, 0, width, 0.0, 1.0, true);
  // true๋Š” ๊ฐ’์„ 0.0~1.0 ์‚ฌ์ด๋กœ ํด๋žจํ”„(์ œํ•œ)

  // ๋‘ ์ƒ‰์ƒ์„ t๋งŒํผ ๋ณด๊ฐ„
  let interpolatedColor = lerpColor(colorA, colorB, t);

  // ๋ณด๊ฐ„๋œ ์ƒ‰์ƒ์œผ๋กœ ๋ฐฐ๊ฒฝ ์ฑ„์šฐ๊ธฐ
  background(interpolatedColor);

  // ์ •๋ณด ํ‘œ์‹œ
  fill(255);
  textAlign(CENTER, CENTER);
  textSize(16);
  text("๋งˆ์šฐ์Šค๋ฅผ ์ขŒ์šฐ๋กœ ์›€์ง์—ฌ ๋ณด์„ธ์š”", width / 2, height / 2 - 20);
  text("t = " + t.toFixed(2), width / 2, height / 2 + 10);
}

์˜ˆ์ œ 2: ์• ๋‹ˆ๋ฉ”์ด์…˜์œผ๋กœ ์ƒ‰์ƒ ์ˆœํ™˜ํ•˜๊ธฐ

let colorA, colorB;
let t = 0;

function setup() {
  createCanvas(400, 200);
  
  colorA = color(255, 100, 0);   // ์ฃผํ™ฉ์ƒ‰
  colorB = color(100, 0, 255);   // ๋ณด๋ผ์ƒ‰
  
  noStroke();
}

function draw() {
  // sin ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด t๋ฅผ 0~1 ์‚ฌ์ด์—์„œ ์™•๋ณต
  t = (sin(frameCount * 0.02) + 1) / 2;
  
  let c = lerpColor(colorA, colorB, t);
  background(c);
  
  fill(255);
  textAlign(CENTER, CENTER);
  text("t = " + t.toFixed(2), width / 2, height / 2);
}

4. ์ƒ‰์ƒ ๋ณด๊ฐ„ ๋ชจ๋“œ์˜ ์ค‘์š”์„ฑ (RGB vs HSB)

Lerp๋Š” ์„ ํ˜•์ ์ด์ง€๋งŒ, ์ธ๊ฐ„์˜ ๋ˆˆ์€ ์ƒ‰์ƒ์„ ์„ ํ˜•์ ์œผ๋กœ ์ธ์ง€ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์–ด๋–ค ์ƒ‰์ƒ ๋ชจ๋“œ์—์„œ ๋ณด๊ฐ„ํ•˜๋А๋ƒ์— ๋”ฐ๋ผ ์ค‘๊ฐ„์ƒ‰์ด ๋งค์šฐ ๋‹ค๋ฅด๊ฒŒ ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค.

A. RGB ๋ณด๊ฐ„์˜ ํŠน์ง• (์ง์„  ๊ฒฝ๋กœ)

RGB ๊ณต๊ฐ„์—์„œ Lerp๋Š” 3์ฐจ์› ํ๋ธŒ ๋‚ด๋ถ€๋ฅผ ๊ฐ€์žฅ ์ง์„ ์œผ๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.

์žฅ์ :

  • ๊ณ„์‚ฐ์ด ๊ฐ„๋‹จํ•˜๊ณ  ๋น ๋ฆ„
  • ์˜ˆ์ธก ๊ฐ€๋Šฅํ•œ ๊ฒฐ๊ณผ

๋‹จ์ :

  • ๋ณด๊ฐ„ ๊ณผ์ •์—์„œ '์น™์น™ํ•œ(muddy)' ๋˜๋Š” 'ํšŒ์ƒ‰๋น›'์ด ๋„๋Š” ์ค‘๊ฐ„์ƒ‰ ์ƒ์„ฑ ๊ฐ€๋Šฅ
  • ํŠนํžˆ ๋ณด์ƒ‰(Complementary Colors) ์‚ฌ์ด๋ฅผ ๋ณด๊ฐ„ํ•  ๋•Œ ์ฑ„๋„๊ฐ€ ๋‚ฎ์€ ์ค‘๊ฐ„์ƒ‰์ด ๋‚˜์˜ค๊ธฐ ์‰ฌ์›€
  • ๋‘ ์ƒ‰์ƒ์˜ ๋น›์ด ์„œ๋กœ ์ƒ์‡„๋˜๋Š” ํšจ๊ณผ

function setup() {
  createCanvas(600, 200);
  
  colorMode(RGB);
  let red = color(255, 0, 0);
  let green = color(0, 255, 0);
  
  // RGB ๋ณด๊ฐ„ - ์น™์น™ํ•œ ์ค‘๊ฐ„์ƒ‰
  for (let i = 0; i < width; i++) {
    let t = i / width;
    let c = lerpColor(red, green, t);
    stroke(c);
    line(i, 0, i, height);
  }
  
  fill(255);
  noStroke();
  textAlign(CENTER);
  text("RGB ๋ณด๊ฐ„: ์ค‘๊ฐ„์— ํšŒ์ƒ‰๋น›์ด ๋„๋Š” ์ƒ‰", width/2, height/2);
}

B. HSB/HSL ๋ณด๊ฐ„์˜ ํŠน์ง• (์ƒ‰์ƒํ™˜ ๊ฒฝ๋กœ)

HSB ๋˜๋Š” HSL ๊ณต๊ฐ„์—์„œ ๋ณด๊ฐ„์„ ์ˆ˜ํ–‰ํ•˜๋ฉด ์ƒ‰์กฐ(Hue)๋Š” ์ƒ‰์ƒํ™˜์„ ๋”ฐ๋ผ ์ด๋™ํ•˜๊ณ , ์ฑ„๋„(Saturation)์™€ ๋ฐ๊ธฐ(Brightness)๋Š” ๋…๋ฆฝ์ ์œผ๋กœ ๋ณ€ํ•ด์š”.

์žฅ์ :

  • ์‚ฌ๋žŒ์ด ์ธ์ง€ํ•˜๊ธฐ์— ๋” ์ž์—ฐ์Šค๋Ÿฝ๊ณ  ์ƒ๋™๊ฐ ์žˆ๋Š” ์ƒ‰์ƒ ๋ณ€ํ™”
  • ์ค‘๊ฐ„์ƒ‰์˜ ์ฑ„๋„๋ฅผ ๋†’๊ฒŒ ์œ ์ง€
  • ๋ฌด์ง€๊ฐœ ๊ทธ๋ผ๋””์–ธํŠธ ๊ฐ™์€ ์ž์—ฐ์Šค๋Ÿฌ์šด ์ „ํ™˜

์ฃผ์˜์‚ฌํ•ญ:

  • ๋‘ ์ƒ‰์ƒ ์‚ฌ์ด์˜ ๊ฑฐ๋ฆฌ๊ฐ€ 180๋„ ์ด์ƒ์ผ ๊ฒฝ์šฐ, ์ƒ‰์ƒํ™˜์„ ๋Œ์•„๊ฐ€๋Š” ๋ฐฉํ–ฅ(์‹œ๊ณ„ ๋ฐฉํ–ฅ ๋˜๋Š” ๋ฐ˜์‹œ๊ณ„ ๋ฐฉํ–ฅ)์„ ๊ณ ๋ คํ•ด์•ผ ํ•จ

function setup() {
  createCanvas(600, 200);
  
  colorMode(HSB, 360, 100, 100);
  let red = color(0, 100, 100);      // Hue 0
  let green = color(120, 100, 100);  // Hue 120
  
  // HSB ๋ณด๊ฐ„ - ์„ ๋ช…ํ•œ ์ค‘๊ฐ„์ƒ‰
  for (let i = 0; i < width; i++) {
    let t = i / width;
    let c = lerpColor(red, green, t);
    stroke(c);
    line(i, 0, i, height);
  }
  
  fill(255);
  noStroke();
  textAlign(CENTER);
  text("HSB ๋ณด๊ฐ„: ์ƒ๋™๊ฐ ์žˆ๋Š” ์ƒ‰์ƒ ์ „ํ™˜", width/2, height/2);
}

5. ์‹ค์ „ ํ™œ์šฉ ์˜ˆ์ œ

์˜ˆ์ œ 1: ๋‹ค์ค‘ ์ƒ‰์ƒ ๊ทธ๋ผ๋””์–ธํŠธ

function setup() {
  createCanvas(600, 200);
  
  colorMode(HSB, 360, 100, 100);
  
  // ์—ฌ๋Ÿฌ ์ƒ‰์ƒ ์ •์˜
  let colors = [
    color(0, 100, 100),      // ๋นจ๊ฐ•
    color(60, 100, 100),     // ๋…ธ๋ž‘
    color(120, 100, 100),    // ์ดˆ๋ก
    color(240, 100, 100),    // ํŒŒ๋ž‘
    color(300, 100, 100)     // ์žํ™
  ];
  
  noStroke();
  
  let segmentWidth = width / (colors.length - 1);
  
  for (let i = 0; i < width; i++) {
    // ํ˜„์žฌ ์œ„์น˜๊ฐ€ ์–ด๋А ๊ตฌ๊ฐ„์— ์†ํ•˜๋Š”์ง€ ๊ณ„์‚ฐ
    let segment = floor(i / segmentWidth);
    let t = (i % segmentWidth) / segmentWidth;
    
    // ๋งˆ์ง€๋ง‰ ๊ตฌ๊ฐ„ ์ฒ˜๋ฆฌ
    if (segment >= colors.length - 1) {
      segment = colors.length - 2;
      t = 1;
    }
    
    let c = lerpColor(colors[segment], colors[segment + 1], t);
    stroke(c);
    line(i, 0, i, height);
  }
}

์˜ˆ์ œ 2: ์›ํ˜• ์ƒ‰์ƒ ๊ทธ๋ผ๋””์–ธํŠธ

function setup() {
  createCanvas(400, 400);
  
  colorMode(HSB, 360, 100, 100);
  
  let centerColor = color(200, 80, 100);  // ์ค‘์‹ฌ: ํŒŒ๋ž€์ƒ‰
  let edgeColor = color(0, 100, 50);      // ๊ฐ€์žฅ์ž๋ฆฌ: ์–ด๋‘์šด ๋นจ๊ฐ•
  
  noStroke();
  
  let maxDist = dist(0, 0, width/2, height/2);
  
  for (let y = 0; y < height; y++) {
    for (let x = 0; x < width; x++) {
      // ์ค‘์‹ฌ์œผ๋กœ๋ถ€ํ„ฐ์˜ ๊ฑฐ๋ฆฌ ๊ณ„์‚ฐ
      let d = dist(x, y, width/2, height/2);
      let t = d / maxDist;
      t = constrain(t, 0, 1);  // 0~1๋กœ ์ œํ•œ
      
      let c = lerpColor(centerColor, edgeColor, t);
      stroke(c);
      point(x, y);
    }
  }
}

์˜ˆ์ œ 3: ์‹œ๊ฐ„ ๊ธฐ๋ฐ˜ ์ƒ‰์ƒ ๋ณ€ํ™”

function setup() {
  createCanvas(600, 400);
  noStroke();
}

function draw() {
  colorMode(HSB, 360, 100, 100);
  
  // ์‹œ๊ฐ„์„ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ (0~1, ํ•˜๋ฃจ๋ฅผ ํ‘œํ˜„)
  let timeOfDay = (frameCount * 0.005) % 1;
  
  let dawn = color(30, 70, 60);      // ์ƒˆ๋ฒฝ: ์ฃผํ™ฉ๋น›
  let day = color(200, 60, 90);      // ๋‚ฎ: ๋ฐ์€ ํ•˜๋Š˜์ƒ‰
  let dusk = color(15, 80, 50);      // ์ €๋…: ๋ถ‰์€๋น›
  let night = color(240, 70, 20);    // ๋ฐค: ์–ด๋‘์šด ํŒŒ๋ž‘
  
  let skyColor;
  
  if (timeOfDay < 0.25) {
    // ์ƒˆ๋ฒฝ โ†’ ๋‚ฎ
    let t = timeOfDay * 4;
    skyColor = lerpColor(dawn, day, t);
  } else if (timeOfDay < 0.5) {
    // ๋‚ฎ โ†’ ์ €๋…
    let t = (timeOfDay - 0.25) * 4;
    skyColor = lerpColor(day, dusk, t);
  } else if (timeOfDay < 0.75) {
    // ์ €๋… โ†’ ๋ฐค
    let t = (timeOfDay - 0.5) * 4;
    skyColor = lerpColor(dusk, night, t);
  } else {
    // ๋ฐค โ†’ ์ƒˆ๋ฒฝ
    let t = (timeOfDay - 0.75) * 4;
    skyColor = lerpColor(night, dawn, t);
  }
  
  background(skyColor);
  
  // ์ •๋ณด ํ‘œ์‹œ
  colorMode(RGB);
  fill(255);
  textSize(50);
  textAlign(CENTER);
  text("์‹œ๊ฐ„: " + (timeOfDay * 24).toFixed(1) + "์‹œ", width/2, height/2);
}

์˜ˆ์ œ 4: ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒ ํŒ”๋ ˆํŠธ ์ƒ์„ฑ๊ธฐ

let baseColor;
let numColors = 5;

function setup() {
  createCanvas(600, 400);
  colorMode(HSB, 360, 100, 100);
  
  baseColor = color(random(360), 80, 90);
  noStroke();
}

function draw() {
  background(220);
  
  // ๋ณด์ƒ‰ ๊ณ„์‚ฐ
  let hue = hue(baseColor);
  let complementaryColor = color((hue + 180) % 360, 80, 90);
  
  // ์ƒ‰์ƒ ํŒ”๋ ˆํŠธ ๊ทธ๋ฆฌ๊ธฐ
  let boxWidth = width / numColors;
  
  for (let i = 0; i < numColors; i++) {
    let t = i / (numColors - 1);
    let c = lerpColor(baseColor, complementaryColor, t);
    
    fill(c);
    rect(i * boxWidth, 0, boxWidth, height * 0.7);
    
    // ์ƒ‰์ƒ ์ •๋ณด ํ‘œ์‹œ
    fill(0);
    textAlign(CENTER);
    textSize(12);
    text("t=" + t.toFixed(2), i * boxWidth + boxWidth/2, height * 0.75);
    text("H=" + hue(c).toFixed(0), i * boxWidth + boxWidth/2, height * 0.8);
  }
  
  // ์•ˆ๋‚ด ํ…์ŠคํŠธ
  fill(0);
  textSize(16);
  textAlign(CENTER);
  text("ํด๋ฆญํ•˜์—ฌ ์ƒˆ๋กœ์šด ์ƒ‰์ƒ ํŒ”๋ ˆํŠธ ์ƒ์„ฑ", width/2, height * 0.95);
}

function mousePressed() {
  baseColor = color(random(360), 80, 90);
}

6. ๊ณ ๊ธ‰ ๊ธฐ๋ฒ•

A. easing ํ•จ์ˆ˜์™€ ๊ฒฐํ•ฉํ•˜๊ธฐ

์„ ํ˜• ๋ณด๊ฐ„ ๋Œ€์‹  easing ํ•จ์ˆ˜๋ฅผ ์ ์šฉํ•˜๋ฉด ๋”์šฑ ์ž์—ฐ์Šค๋Ÿฌ์šด ์ƒ‰์ƒ ๋ณ€ํ™”๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

function setup() {
  createCanvas(600, 200);
  colorMode(HSB, 360, 100, 100);
  noStroke();
}

function draw() {
  let c1 = color(0, 100, 100);
  let c2 = color(240, 100, 100);
  
  for (let i = 0; i < width; i++) {
    let t = i / width;
    
    // easeInOut ์ ์šฉ
    let easedT = t < 0.5 
      ? 2 * t * t 
      : 1 - pow(-2 * t + 2, 2) / 2;
    
    let c = lerpColor(c1, c2, easedT);
    stroke(c);
    line(i, 0, i, height);
  }
}

B. ๋‹ค์ค‘ ์ฑ„๋„ ๋…๋ฆฝ ์ œ์–ด

function setup() {
  createCanvas(400, 400);
  colorMode(HSB, 360, 100, 100);
  
  let h1 = 0, s1 = 100, b1 = 100;
  let h2 = 240, s2 = 50, b2 = 80;
  
  for (let y = 0; y < height; y++) {
    for (let x = 0; x < width; x++) {
      let tX = x / width;
      let tY = y / height;
      
      // X์ถ•: Hue ๋ณ€ํ™”, Y์ถ•: Saturation ๋ณ€ํ™”
      let h = lerp(h1, h2, tX);
      let s = lerp(s1, s2, tY);
      let b = b1;  // ๋ฐ๊ธฐ๋Š” ๊ณ ์ •
      
      stroke(h, s, b);
      point(x, y);
    }
  }
}

7. ์„ฑ๋Šฅ ์ตœ์ ํ™” ํŒ

A. Color ๊ฐ์ฒด ์žฌ์‚ฌ์šฉ

๋ฐ˜๋ณต๋ฌธ์—์„œ ๋งค๋ฒˆ lerpColor()๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋Œ€์‹ , ๊ฐ€๋Šฅํ•˜๋ฉด ๋ฏธ๋ฆฌ ๊ณ„์‚ฐ๋œ ์ƒ‰์ƒ ๋ฐฐ์—ด์„ ์‚ฌ์šฉํ•˜์„ธ์š”.

// ๋น„ํšจ์œจ์ 
function draw() {
  for (let i = 0; i < 1000; i++) {
    let c = lerpColor(colorA, colorB, random());
    // ...
  }
}

// ํšจ์œจ์ 
let colorPalette = [];
function setup() {
  for (let i = 0; i < 100; i++) {
    colorPalette[i] = lerpColor(colorA, colorB, i / 100);
  }
}

function draw() {
  for (let i = 0; i < 1000; i++) {
    let c = colorPalette[floor(random(100))];
    // ...
  }
}

B.ํ”ฝ์…€ ๋‹จ์œ„ ๊ทธ๋ผ๋””์–ธํŠธ๋Š” createGraphics() ์‚ฌ์šฉ

๋ณต์žกํ•œ ๊ทธ๋ผ๋””์–ธํŠธ๋Š” ํ•œ ๋ฒˆ๋งŒ ๊ทธ๋ฆฐ ํ›„ ์ด๋ฏธ์ง€๋กœ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

let gradient;

function setup() {
  createCanvas(400, 400);
  
  // ๊ทธ๋ผ๋””์–ธํŠธ๋ฅผ ํ•œ ๋ฒˆ๋งŒ ์ƒ์„ฑ
  gradient = createGraphics(width, height);
  gradient.colorMode(HSB, 360, 100, 100);
  
  for (let i = 0; i < width; i++) {
    let t = i / width;
    let c = lerpColor(color(0, 100, 100), color(240, 100, 100), t);
    gradient.stroke(c);
    gradient.line(i, 0, i, height);
  }
}

function draw() {
  // ๋ฏธ๋ฆฌ ๋งŒ๋“  ๊ทธ๋ผ๋””์–ธํŠธ ์‚ฌ์šฉ
  image(gradient, 0, 0);
  
  // ๋‹ค๋ฅธ ๊ทธ๋ฆฌ๊ธฐ ์ž‘์—…...
}

8. ์ •๋ฆฌ

RGB ๋ณด๊ฐ„์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ:

  • ๋น„์Šทํ•œ ์ƒ‰์กฐ์˜ ์ƒ‰์ƒ ๊ฐ„ ๋ณด๊ฐ„
  • ๋ฐ๊ธฐ๋‚˜ ํˆฌ๋ช…๋„๋งŒ ๋ณ€๊ฒฝ
  • ๋น ๋ฅธ ๊ณ„์‚ฐ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ

HSB/HSL ๋ณด๊ฐ„์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ:

  • ๋ฌด์ง€๊ฐœ ๊ทธ๋ผ๋””์–ธํŠธ
  • ์ž์—ฐ์Šค๋Ÿฌ์šด ์ƒ‰์ƒ ์ „ํ™˜
  • UI/UX ๋””์ž์ธ์˜ ๋ถ€๋“œ๋Ÿฌ์šด ์ƒ‰์ƒ ๋ณ€ํ™”
  • ์˜ˆ์ˆ ์ ์ด๊ณ  ์ƒ๋™๊ฐ ์žˆ๋Š” ํ‘œํ˜„
  1. Lerp๋Š” ์„ ํ˜• ๋ณด๊ฐ„: V = A + (B - A) ร— t
  2. lerpColor()๋Š” ๊ฐ ์ฑ„๋„์„ ๋…๋ฆฝ์ ์œผ๋กœ ๋ณด๊ฐ„: RGB์˜ ๊ฒฝ์šฐ R, G, B ๊ฐ๊ฐ Lerp ์ ์šฉ
  3. ์ƒ‰์ƒ ๋ชจ๋“œ๊ฐ€ ๊ฒฐ๊ณผ์— ํฐ ์˜ํ–ฅ: RGB๋Š” ์ง์„  ๊ฒฝ๋กœ, HSB๋Š” ์ƒ‰์ƒํ™˜ ๊ฒฝ๋กœ
  4. ์ž์—ฐ์Šค๋Ÿฌ์šด ์ƒ‰์ƒ ์ „ํ™˜์—๋Š” HSB ์ถ”์ฒœ: ์ค‘๊ฐ„์ƒ‰์˜ ์ฑ„๋„์™€ ์ƒ๋™๊ฐ ์œ ์ง€
  5. ์„ฑ๋Šฅ ๊ณ ๋ ค: ๋ฐ˜๋ณต ๊ณ„์‚ฐ๋ณด๋‹ค๋Š” ๋ฏธ๋ฆฌ ๊ณ„์‚ฐ๋œ ํŒ”๋ ˆํŠธ ํ™œ์šฉ

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

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