빌보드

Billboarding

씬이 아무리 회전해도 라벨·아이콘이 항상 카메라 정면을 향하게 만드는 기법 — 광고판이 늘 도로 쪽을 보는 것과 같다.

다른 이름: Camera-facing spritelookAt(camera)
···
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(0x0a0b14);
const camera = new THREE.PerspectiveCamera(50, 1, 0.1, 30);
camera.position.set(0, 1.4, 7.4);
function makeLabel(text, color) {
  const c = document.createElement('canvas'); c.width = 256; c.height = 96;
  const ctx = c.getContext('2d');
  ctx.fillStyle = 'rgba(10,11,20,.85)'; ctx.beginPath(); ctx.roundRect(4, 20, 248, 56, 20); ctx.fill();
  ctx.fillStyle = color; ctx.font = 'bold 34px system-ui'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle';
  ctx.fillText(text, 128, 50);
  const sprite = new THREE.Sprite(new THREE.SpriteMaterial({ map: new THREE.CanvasTexture(c), transparent: true }));
  sprite.scale.set(1.3, 0.49, 1);
  return sprite;
}
const group = new THREE.Group(); scene.add(group);
const data = [{ x: -2.4, c: '#8ecbff', t: 'North' }, { x: 0, c: '#ff9d7a', t: 'Core' }, { x: 2.4, c: '#9dff9d', t: 'East' }];
data.forEach((d) => {
  const sphere = new THREE.Mesh(new THREE.IcosahedronGeometry(0.6, 1), new THREE.MeshBasicMaterial({ color: d.c, wireframe: true }));
  sphere.position.x = d.x;
  const label = makeLabel(d.t, d.c);
  label.position.set(d.x, 1.05, 0);
  group.add(sphere, label);
});
function resize() { renderer.setSize(innerWidth, innerHeight); camera.aspect = innerWidth / innerHeight; camera.updateProjectionMatrix(); }
addEventListener('resize', resize); resize();
renderer.setAnimationLoop((t) => {
  group.rotation.y = t * 0.00045;
  camera.lookAt(0, 0.3, 0);
  renderer.render(scene, camera);
});

3D 오브젝트에 이름표나 아이콘을 붙일 때, 그것도 오브젝트와 함께 회전하게 두면 옆이나 뒤로 돌아가는 순간 글자가 뒤집히거나 아예 안 보인다. 빌보딩은 그 라벨만 따로, 매 프레임 카메라를 향하도록 회전시켜서 항상 정면으로 읽히게 만든다.

three.js에서 가장 쉬운 방법은 THREE.Sprite를 쓰는 것 — 스프라이트는 원래 항상 카메라를 향하도록 설계돼 있다. 평면(Plane) 메시로 직접 구현하려면 매 프레임 `object.quaternion.copy(camera.quaternion)` 로 카메라의 회전값을 그대로 복사한다.

데모는 회전하는 구체 세 개에 각각 라벨을 붙였다. 구체 자체(와이어프레임)는 씬을 따라 계속 돌지만, 라벨은 항상 화면 정면을 보고 있어서 글자가 절대 뒤집히지 않는 걸 확인할 수 있다.

언제 쓰나

3D 씬 위의 이름표, HP바, 마커 아이콘처럼 항상 읽혀야 하는 2D 요소에 씁니다. 오브젝트 자체의 앞뒤를 보여줘야 하는 경우(캐릭터 얼굴 등)에는 쓰지 않습니다.