코스틱

Caustics

빛이 휘어진 투명한 표면(물, 유리)을 통과하며 굴절되어 한 곳으로 모이거나 퍼지면서 만드는 일렁이는 빛의 그물 무늬.

다른 이름: Caustic pattern
···
html
<canvas id="ca-canvas"></canvas><span class="ca-cap">faked caustics · layered sine distortion</span>
css
#ca-canvas{width:100%;height:100%;display:block}
.ca-cap{position:absolute;left:0;right:0;bottom:4%;text-align:center;font-size:clamp(9px,2.4vmin,12px);color:#cfe8ffcc}
js
const canvas = document.getElementById('ca-canvas');
const ctx = canvas.getContext('2d');
function resize() {
  const r = canvas.getBoundingClientRect();
  canvas.width = Math.round(r.width);
  canvas.height = Math.round(r.height);
}
addEventListener('resize', resize); resize();

function draw(t) {
  const w = canvas.width, h = canvas.height;
  const bg = ctx.createLinearGradient(0, 0, 0, h);
  bg.addColorStop(0, '#0b2540'); bg.addColorStop(1, '#04101d');
  ctx.fillStyle = bg; ctx.fillRect(0, 0, w, h);

  ctx.globalCompositeOperation = 'lighten';
  const time = t * 0.00035;
  for (let l = 0; l < 3; l++) {
    ctx.beginPath();
    const rows = 9;
    for (let r = 0; r <= rows; r++) {
      const y0 = (r / rows) * h;
      ctx.moveTo(0, y0);
      for (let x = 0; x <= w; x += 8) {
        const n = Math.sin(x * 0.045 + time * (1.2 + l * 0.4) + r * 0.9) * 9
          + Math.sin(x * 0.018 - time * (0.7 + l * 0.3) + r * 1.6) * 13;
        ctx.lineTo(x, y0 + n);
      }
    }
    const cols = 11;
    for (let cIdx = 0; cIdx <= cols; cIdx++) {
      const x0 = (cIdx / cols) * w;
      ctx.moveTo(x0, 0);
      for (let y = 0; y <= h; y += 8) {
        const n = Math.sin(y * 0.05 - time * (1.1 + l * 0.35) + cIdx * 0.9) * 9
          + Math.sin(y * 0.02 + time * (0.6 + l * 0.25) + cIdx * 1.5) * 13;
        ctx.lineTo(x0 + n, y);
      }
    }
    ctx.strokeStyle = l === 0 ? 'rgba(120,200,255,0.3)' : l === 1 ? 'rgba(160,230,255,0.24)' : 'rgba(210,248,255,0.2)';
    ctx.lineWidth = 1.3;
    ctx.stroke();
  }
  ctx.globalCompositeOperation = 'source-over';
  requestAnimationFrame(draw);
}
requestAnimationFrame(draw);

수영장 바닥에 일렁이는 빛의 그물 무늬, 와인잔 옆에 지는 초승달 모양 빛 — 둘 다 코스틱입니다. 물결이나 유리 표면의 굴곡마다 빛이 조금씩 다른 각도로 굴절되면서, 어떤 지점에서는 광선이 촘촘히 모이고(밝은 선) 어떤 지점에서는 퍼져서(어두운 영역) 이 특유의 무늬가 생깁니다.

물리적으로 정확한 코스틱은 패스 트레이싱 계열 렌더러가 광자 매핑(photon mapping)이나 양방향 경로 추적 같은 기법으로 계산하는데, 굴절면을 지나 수렴하는 빛을 추적해야 해서 계산 비용이 특히 큽니다. 그래서 게임이나 실시간 그래픽에서는 대부분 "가짜" 코스틱을 씁니다 — 미리 렌더링해 둔 애니메이션 텍스처를 바닥에 투영하거나, 이 데모처럼 여러 겹의 일그러진 사인파를 겹쳐서 비슷한 그물 무늬를 실시간으로 만들어냅니다.

Blender Cycles나 Corona 같은 렌더러는 코스틱 계산을 따로 켜고 끌 수 있는 옵션으로 두는데, 정확도를 올릴수록 렌더 시간이 크게 늘기 때문입니다. 데모의 무늬는 물리 시뮬레이션이 아니라 순수한 시각적 흉내임을 기억하세요.

언제 쓰나

물·유리·보석 근처의 바닥이나 벽에 사실감을 더하고 싶을 때. 실시간에서는 정확한 시뮬레이션 대신 흉내 낸 텍스처로 대체하세요.