범프 vs 디스플레이스먼트

Bump vs. displacement

둘 다 같은 흑백 높이 텍스처를 쓰지만, 범프는 셰이딩만 속이고 디스플레이스먼트는 정점을 실제로 밀어 올립니다.

다른 이름: Bump mapDisplacement mapHeight map
···
html
<div class="sub-caps"><span>bump map · silhouette unchanged</span><span>displacement · silhouette changes</span></div>
css
.sub-caps{position:absolute;left:0;right:0;bottom:6%;display:flex;justify-content:space-around;font-size:clamp(8px,2.4vmin,12px);color:#dfe3ffcc;text-align:center;padding:0 3%}
js
import * as THREE from 'three';
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(Math.min(devicePixelRatio, 2));
document.body.appendChild(renderer.domElement);
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x0b0b14);
const camera = new THREE.PerspectiveCamera(42, 1, 0.1, 100);
camera.position.set(0, 0.5, 6.4);

const cv = document.createElement('canvas');
cv.width = cv.height = 128;
const cx = cv.getContext('2d');
cx.fillStyle = '#777'; cx.fillRect(0, 0, 128, 128);
for (let i = 0; i < 26; i++) {
  const x = Math.random() * 128, y = Math.random() * 128, r = 6 + Math.random() * 10;
  const g = cx.createRadialGradient(x, y, 0, x, y, r);
  g.addColorStop(0, '#fff'); g.addColorStop(1, 'rgba(119,119,119,0)');
  cx.fillStyle = g; cx.beginPath(); cx.arc(x, y, r, 0, Math.PI * 2); cx.fill();
}
const tex = new THREE.CanvasTexture(cv);

const bumpSphere = new THREE.Mesh(
  new THREE.SphereGeometry(1.05, 64, 64),
  new THREE.MeshStandardMaterial({ color: 0x8ecbff, bumpMap: tex, bumpScale: 0.06, roughness: 0.55 })
);
bumpSphere.position.x = -1.7;
const dispSphere = new THREE.Mesh(
  new THREE.SphereGeometry(1.05, 128, 128),
  new THREE.MeshStandardMaterial({ color: 0xffb648, displacementMap: tex, displacementScale: 0.34, roughness: 0.55 })
);
dispSphere.position.x = 1.7;
scene.add(bumpSphere, dispSphere);
const key = new THREE.DirectionalLight(0xffffff, 1.8); key.position.set(3, 4, 5); scene.add(key);
scene.add(new THREE.AmbientLight(0xffffff, 0.45));
function resize() { renderer.setSize(innerWidth, innerHeight); camera.aspect = innerWidth / innerHeight; camera.updateProjectionMatrix(); }
addEventListener('resize', resize); resize();
renderer.setAnimationLoop((t) => {
  const r = t * 0.00028;
  bumpSphere.rotation.y = r; dispSphere.rotation.y = r;
  camera.lookAt(0, 0, 0);
  renderer.render(scene, camera);
});

범프 맵은 노멀 맵의 원조 격인 더 단순한 버전입니다 — 흑백 높이 텍스처의 밝기 변화로부터 기울기를 즉석에서 계산해 셰이딩에만 반영합니다. 지오메트리는 정점 하나도 움직이지 않으므로, 옆에서 실루엣을 보면 여전히 완벽하게 매끈합니다.

디스플레이스먼트 맵은 같은 흑백 텍스처를 쓰지만 그 값을 셰이딩이 아니라 정점 위치 자체에 더합니다. 그러려면 표면에 옮길 정점이 충분히 많아야 하므로(세그먼트가 촘촘한 메시가 필요) 계산 비용이 범프보다 훨씬 큽니다. 대신 실루엣이 실제로 울퉁불퉁해지고, 그림자도 진짜 지오메트리처럼 드리워집니다.

Blender·C4D는 이 둘을 재질 노드의 "Bump"와 "Displace" 입력으로 구분하고, 실시간 렌더러는 디스플레이스먼트를 GPU 테셀레이션이나 정점 셰이더로 처리합니다. 클로즈업이 없고 성능이 중요하면 범프로 충분하고, 카메라가 표면에 바짝 붙거나 윤곽선이 중요하면 디스플레이스먼트가 필요합니다.

언제 쓰나

클로즈업 샷이나 실루엣이 중요하면 디스플레이스먼트, 먼 배경이나 성능이 우선이면 범프를 선택하세요.