모프 타겟

Morph targets

같은 정점 개수를 가진 두 형태 사이를 부드럽게 보간해 하나의 메시가 다른 모양으로 변형되게 하는 기법.

다른 이름: Blend shapesShape keysmorphTargetInfluences
···
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(0x0c0c16);
const camera = new THREE.PerspectiveCamera(45, 1, 0.1, 100);
camera.position.set(0, 0, 4.6);

scene.add(new THREE.AmbientLight(0x556080, 1.2));
const dLight = new THREE.DirectionalLight(0xffffff, 1.1);
dLight.position.set(3, 4, 4);
scene.add(dLight);

const geo = new THREE.IcosahedronGeometry(1.3, 3);
const basePos = geo.attributes.position;
const spike = new Float32Array(basePos.count * 3);
const v = new THREE.Vector3();
for (let i = 0; i < basePos.count; i++) {
  v.fromBufferAttribute(basePos, i);
  const n = v.clone().normalize();
  const bump = 0.55 * (0.5 + 0.5 * Math.sin(i * 12.9898));
  v.addScaledVector(n, bump);
  spike[i * 3] = v.x; spike[i * 3 + 1] = v.y; spike[i * 3 + 2] = v.z;
}
geo.morphAttributes.position = [new THREE.Float32BufferAttribute(spike, 3)];

const mesh = new THREE.Mesh(geo, new THREE.MeshStandardMaterial({ color: 0x8f7bff, roughness: 0.4, flatShading: true }));
mesh.frustumCulled = false;
scene.add(mesh);

function resize() { renderer.setSize(innerWidth, innerHeight); camera.aspect = innerWidth / innerHeight; camera.updateProjectionMatrix(); }
addEventListener('resize', resize); resize();
renderer.setAnimationLoop((t) => {
  const time = t * 0.001;
  mesh.morphTargetInfluences[0] = 0.5 + 0.5 * Math.sin(time * 1.2);
  mesh.rotation.y = time * 0.3;
  renderer.render(scene, camera);
});

모프 타겟(블렌드 셰이프)은 본(bone)을 움직이는 스켈레탈 애니메이션과 달리, 정점 위치 자체를 다른 "목표 위치" 집합으로 직접 섞습니다. 얼굴 표정(입꼬리를 올린 버전, 눈을 감은 버전)처럼 뼈대로는 표현하기 어려운 변형에 특히 유용합니다.

전제 조건은 기본 지오메트리와 목표(morph target) 지오메트리가 정점 개수와 순서가 정확히 같아야 한다는 것입니다. geometry.morphAttributes.position에 목표 위치들을 배열로 넣으면(반드시 Mesh를 생성하기 전에!) three.js가 자동으로 mesh.morphTargetInfluences 배열을 만들어줍니다. 이 배열의 각 값(0~1)이 "그 목표쪽으로 얼마나 섞였는지"를 뜻합니다.

데모는 아이코사헤드론의 정점 배열을 그대로 복제한 뒤 각 정점을 법선 방향으로 제각각 다르게 밀어내 "뾰족한 성게" 모양의 목표를 만들고, morphTargetInfluences[0]을 사인파로 오가게 해서 매끈한 구와 뾰족한 형태 사이를 끊임없이 오가게 합니다. flatShading을 켜두면 변형 중에도 면 하나하나의 각도 변화가 잘 드러납니다.

언제 쓰나

캐릭터 표정·립싱크, 두 형태 사이를 매끄럽게 전환해야 하는 UI/제품 애니메이션에.