애니메이션

0

Three.js

목록 보기
2/14
post-thumbnail

개요

이전 시리즈에 이어서 Three.js에서 애니메이션을 적용하는 방법에 대해 실습한 내용을 정리하고자 한다.

Three.js에서도 canvas와 마찬가지로 애니메이션을 적용할때 requestAnimationFrame 함수를 이용해서 적용할 수 있는데, Three.js에서 지원하는 setAnimationLoop 함수를 이용해서 애니메이션을 처리해도된다.

setAnimationLoop도 내부적으로는 requestAnimationFrame을 이용해서 구현되어 있다고 하니원하는 메서드를 사용하면 된다. 잡소리 그만하고 Three.js에서 지원하는거 써라

다만 setAnimationLoop 함수를 반드시 사용해야 하는 경우가 존재하는데 Three.js를 이용해서 AR/VR을 구현할때는 setAnimationLoop 함수를 반드시 사용하라고 공식문서에 나와있다. 아래 그림에 나와있는 WebXR이 AR과 VR을 의미한다.

실습

애니메이션 구현

import * as THREE from "three";

export default function example() {
  // 정적으로 캔버스 조립
  const canvas = document.querySelector("#three-canvas");
  const renderer = new THREE.WebGLRenderer({
    canvas,
    antialias: true,
  });

  // 렌더러 사이즈
  renderer.setSize(window.innerWidth, window.innerHeight);
  // 고해상도 표현해줄때 사용하는 메서드
  renderer.setPixelRatio(window.devicePixelRatio > 1 ? 2 : 1);

  // 씬 생성
  const scene = new THREE.Scene();

  // 카메라 생성
  const camera = new THREE.PerspectiveCamera(
    75,
    window.innerWidth / window.innerHeight, // aspect
    0.1,
    1000
  );

  camera.position.z = 5;
  scene.add(camera);

  // 조명 추가 (색상, 빛의 강도)
  const light = new THREE.DirectionalLight(0xffffff, 1);
  light.position.z = 5;
  light.position.x = 1;
  scene.add(light);

  // Mesh
  const geometry = new THREE.BoxGeometry(1, 1, 1);
  const material = new THREE.MeshStandardMaterial({
    color: "#ff0000",
  });

  const mesh = new THREE.Mesh(geometry, material);
  scene.add(mesh);

  // 그리기
  const draw = () => {
    // 라디안(호도값)을 이용해서 각도를 계산함
    mesh.rotation.y += THREE.MathUtils.degToRad(1);
    mesh.position.y += 0.01;
    if (mesh.position.y > 3) {
      mesh.position.y = 0;
    }
    renderer.render(scene, camera);
    renderer.setAnimationLoop(draw);
  };

  // 반응형 적용
  const setSize = () => {
    // 카메라 조정
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
    draw();
  };

  draw();

  // 이벤트
  window.addEventListener("resize", setSize);
}

애니메이션 성능보정

requestionAnimation 함수는 초당 60프레임을 목표로 실행이 되지만 컴퓨터 사양에 따라서 초당 프레임이 달라지는 경우가 생긴다.

따라서 모든 컴퓨터 사양이 동일하게 애니메이션이 동작하는 보정작업을 진행해주어야 한다.

보정작업의 경우 2가지의 방법이 있는데 첫번째는 경과시간을 이용하는 것이고 두번째는 실행간격을 이용하는 방법이다.

경과시간

Three.js에서는 친절하게도 getElapsedTime 함수를 이용해 경과 시간을 가져올 수 있다. 이를 적용해서 애니메이션을 적용한다.

예를 들어 A 컴퓨터와 B 컴퓨터가 존재하는데 두개의 컴퓨터는 0초에서 10초까지 실행하는 횟수는 다를지언정 두 컴퓨터 모두 5초일때는 5초이기 때문에 성능에는 영향을 주지 않는다는 개념을 적용한것이다.

  // 그리기
  const clock = new THREE.Clock();
  const draw = () => {
    const time = clock.getElapsedTime();
    // 라디안(호도값)을 이용해서 각도를 계산함
    mesh.rotation.y = time;
    // mesh.rotation.y += THREE.MathUtils.degToRad(1);
    mesh.position.y += 0.01;
    if (mesh.position.y > 3) {
      mesh.position.y = 0;
    }
    renderer.render(scene, camera);
    renderer.setAnimationLoop(draw);
  };

실행간격

다른 방법으로는 requestAnimation 함수가 실행됬을때의 시간차를 구해서 값을 보정하는 방법이다. 이방법은 이전 getElapsedTime과 새로운 getElapsedTime의 차이라고 생각해도 된다.

  • Three.js
  const clock = new THREE.Clock();

  const draw = () => {
    const time = clock.getDelta();
    // 라디안(호도값)을 이용해서 각도를 계산함
    mesh.rotation.y += time;
    mesh.position.y += time;
    if (mesh.position.y > 3) {
      mesh.position.y = 0;
    }
    renderer.render(scene, camera);
    renderer.setAnimationLoop(draw);
  };

  • javascript
    Three.js의 함수를 사용하지 않고 자바스크립트 Date클래스를 사용하는 방법도 있다.
  // 그리기
  let oldTime = Date.now();

  const draw = () => {
    const newTime = Date.now();
    const deltaTime = newTime - oldTime;
    oldTime = newTime;
    // 라디안(호도값)을 이용해서 각도를 계산함
    mesh.rotation.y += deltaTime * 0.001;
    mesh.position.y += deltaTime * 0.001;
    if (mesh.position.y > 3) {
      mesh.position.y = 0;
    }
    renderer.render(scene, camera);
    renderer.setAnimationLoop(draw);
  };

profile
업무하면서 쌓인 노하우를 정리하는 블로그🚀 풀스택 개발자를 지향하고 있습니다👻

0개의 댓글