JEasings를 사용해 변하는 값을 업데이트 하기 위해서는, 애니메이션 루프에서 update 함수를 호출해야 한다.
import * as THREE from 'three';
import JEASINGS from 'jeasings';
/* 생략 */
function animate() {
requestAnimationFrame(animate);
JEASINGS.update();
}
animate();
JEasings을 통해 값을 변환하기 위해서는 JEasing 객체를 생성한다.
import * as THREE from 'three';
import JEASINGS from 'jeasings';
/* 일부 코드 생략 */
// Raycaster를 사용하여 얻어낸 교차점의 좌표 P
const p = intersects[0].point;
new JEASINGS.JEasing(controls.target)
.to(
{
x: p.x,
y: p.y,
z: p.z
},
500
)
//.delay (1000)
//.easing(JEASINGS.Cubic.Out)
//.onUpdate(() => render())
.start();
JEasing 생성자로 객체를 선언하며, 변환할 값인 controls.target(OrbitControls의 target)을 전달하고 있다.
JEasings에서는 JEASINGS.[방정식 이름].[방향] 의 포맷으로 함수를 사용할 수 있다(참고).
GLTF Animations
Mixamo: 다양한 3D 모델과 애니메이션을 다운로드 받을 수 있는 사이트(링크). 에셋을 다운받기 위해서는 어도비 계정이 필요하다.
실습을 위해 Mixamo 에서 애니메이션이 붙어있는 모델 파일을 fbx 형식으로 받는다.
받은 파일을 Blender를 사용해 glTF 파일로 변경해준다.
받은 모델을 Three.js에서 로딩하고, console.log로 확인해보면 animations 속성이 존재하고 같이 붙여준 animation이 들어가 있음을 알 수 있다.
AnimationMixer
Scene에 존재하는 특정 물체의 애니메이션을 재생시키는 플레이어 역할을 수행한다.
AnimationMixer 생성자로 AnimationMixer 객체를 생성하여 사용할 수 있다.
애니메이션을 갖는 복수의 모델이 있다면, 한 모델 당 하나의 mixer를 가져야 한다.
import * as THREE from 'three';
let mixer: THREE.AnimationMixer;
new GLTFLoader().load('models/eve$@walk.glb', (gltf) => {
mixer = new THREE.AnimationMixer(gltf.scene);
console.log(gltf);
mixer.clipAction(gltf.animations[0]).play();
scene.add(gltf.scene);
})
// 생략
const clock = new THREE.Clock();
let delta = 0;
function animate() {
requestAnimationFrame(animate);
delta = clock.getDelta();
controls.update();
mixer.update(delta);
renderer.render(scene, camera);
}
AnimationMixer 생성자를 사용해 mixer 변수에 할당하고, 생성자의 인자로 로딩한 모델을 넘겨준다.
clipAction 메서드를 사용해 모델 객체에 존재하는 animation 중 하나를 가져와, play 메서드로 재생한다.
Animation 루프에서는 mixer.update()를 통해 애니메이션을 업데이트한다.
모델 파일에 존재하는 애니메이션(걷기)을 재생한 모습
모델과 함께 붙어있는 애니메이션이 아닌, 오직 애니메이션’만’을 가져와 모델에 재생시키는 것도 가능하다.
다만, 이 경우 재생하려는 애니메이션이 현재 모델과 잘 맞는지 미리 살펴봐야 한다.
import * as THREE from 'three';
async function loadEve() {
const loader = new GLTFLoader()
const [eve, idle] = await Promise.all([
loader.loadAsync('models/eve$@walk.glb'),
loader.loadAsync('models/eve@idle.glb'),
]);
mixer = new THREE.AnimationMixer(eve.scene);
mixer.clipAction(idle.animations[0]).play();
scene.add(eve.scene);
}
await loadEve();