Learning
레슨 5 / 8·20분

애니메이션과 카메라 컨트롤

키프레임 애니메이션과 트윈

Three.js는 glTF 모델에 포함된 키프레임 애니메이션을 AnimationMixer로 재생할 수 있습니다. 또한 코드 기반으로 부드러운 전환(tween) 애니메이션을 구현하거나, 다양한 카메라 컨트롤로 사용자 시점을 제어할 수 있습니다.

javascript
import * as THREE from 'three';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';

const gltfLoader = new GLTFLoader();
let animMixer;

gltfLoader.load('/models/character.glb', (gltf) => {
  const model = gltf.scene;
  scene.add(model);

  // AnimationMixer 생성
  animMixer = new THREE.AnimationMixer(model);

  // 모든 애니메이션 클립 확인
  console.log('Animations:', gltf.animations.map(a => a.name));

  // 첫 번째 애니메이션 재생
  const action = animMixer.clipAction(gltf.animations[0]);
  action.play();
});

// 애니메이션 루프에서 mixer 업데이트
const clock = new THREE.Clock();
function animate() {
  requestAnimationFrame(animate);
  const delta = clock.getDelta();
  if (animMixer) animMixer.update(delta);
  renderer.render(scene, camera);
}
animate();

코드 기반 트윈 애니메이션

javascript
// Lerp(선형 보간) 애니메이션
function lerp(start, end, t) {
  return start + (end - start) * t;
}

const targetPos = new THREE.Vector3(3, 1, 0);

function animate() {
  requestAnimationFrame(animate);

  // 매 프레임 5%씩 목표에 접근
  cube.position.x = lerp(cube.position.x, targetPos.x, 0.05);
  cube.position.y = lerp(cube.position.y, targetPos.y, 0.05);
  cube.position.z = lerp(cube.position.z, targetPos.z, 0.05);

  renderer.render(scene, camera);
}

// 클릭 시 목표 위치 변경
window.addEventListener('click', () => {
  targetPos.set(
    (Math.random() - 0.5) * 6,
    Math.random() * 3,
    (Math.random() - 0.5) * 6
  );
});
javascript
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { PointerLockControls } from 'three/addons/controls/PointerLockControls.js';

// OrbitControls — 마우스로 회전/줌/패닝
const orbitControls = new OrbitControls(camera, renderer.domElement);
orbitControls.enableDamping = true;
orbitControls.dampingFactor = 0.05;
orbitControls.minDistance = 2;
orbitControls.maxDistance = 20;
orbitControls.autoRotate = true;
orbitControls.autoRotateSpeed = 2.0;

// PointerLockControls — FPS 게임 스타일 카메라
const fpControls = new PointerLockControls(camera, document.body);
document.addEventListener('click', () => fpControls.lock());

const velocity = new THREE.Vector3();
document.addEventListener('keydown', (e) => {
  if (e.code === 'KeyW') velocity.z = -0.1;
  if (e.code === 'KeyS') velocity.z = 0.1;
  if (e.code === 'KeyA') velocity.x = -0.1;
  if (e.code === 'KeyD') velocity.x = 0.1;
});
document.addEventListener('keyup', () => velocity.set(0, 0, 0));
  • AnimationMixer — glTF 모델의 키프레임 애니메이션을 관리/재생
  • clipAction() — AnimationClip을 Action으로 변환하여 제어
  • lerp — 선형 보간으로 부드러운 이동/전환 구현
  • OrbitControls — 궤도 카메라 (3D 뷰어에 적합)
  • PointerLockControls — FPS 스타일 카메라 (게임에 적합)
💡

AnimationMixer.update(delta)는 반드시 매 프레임 호출해야 합니다. delta 대신 고정 값을 사용하면 프레임 속도에 따라 애니메이션 속도가 달라집니다.