3D 기반의 웹을 개발하다보면 오보젝트 클릭 시 카메라가 이동하고 해당 오브젝트에 포커싱되는 기능을 한번쯤 구현하게 된다.
이때 GSAP 라이브러리를 사용하면 쉽게 구현할 수 있다.
GSAP(The GreenSock Animation Platform)는 타임라인 기반의 애니메이션 자바스크립트 라이브러리이다.
css와 바닐라 자바스크립트의 keyframe과 animation보다 세밀한 컨트롤이 가능하다는 장점이 있기 때문에 2d, 3d 인터랙티브 웹 사이트를 제작할 때 쉽게 사용할 수 있다.
애니메이션 적용을 위해 gsap의 여러 메소드를 사용할 수 있고 아래 공식 문서에서 확인할 수 있다.
https://gsap.com/resources/get-started#creating-an-animation
"현재 상태"를 기준으로 어떤 상태로 애니메이션을 적용하는 경우 일반적으로 gsap.to()
메소드를 사용한다.
모델을 띄워놓은 상태에서 클릭하면 카메라 위치만 움직일 것이기 때문에 gsap.to()
메소드를 사용했다.
우선 position
, target
값을 초기에 설정해놓는다.
CameraControls
내에서 OrbitControls
ref
의 position
과 target
값을 업데이트해주면서 애니메이션이 발생하는 방식이다.
추가한 3D 모델 에셋과 초기 카메라 세팅값에 맞게 애니메이션 적용 후 설정할 position
, target
값을 적절히 설정한다.
코드는 아래와 같고 duration
을 통해 애니메이션 발생 속도를 설정하고 ease
의 종류는 공식 문서에서 확인하여 설정할 수 있다.
import { Canvas } from '@react-three/fiber'
import React, { useState } from 'react'
import { OrbitControls } from '@react-three/drei'
import { House } from './House'
import { CameraControls } from './Camera'
export default function View() {
const [position, setPosition] = useState({ x: 25, y: 4, z: -8})
const [target, setTarget] = useState({x: 0, y: 0, z: 0})
const handleOnclick = () => {
setPosition({x: 5, y: 2, z: 0})
setTarget({x: 3, y: 2, z: 0 })
}
return (
<>
<Canvas camera={{position:[25,4,-8]}}>
<axesHelper args={[200, 200, 200]} />
<ambientLight intensity={1} />
<CameraControls position={position} target={target}/>
<group rotation-y={-Math.PI / 2} onClick={handleOnclick}>
<House/>
</group>
</Canvas>
</>
)
}
import { OrbitControls } from "@react-three/drei";
import { useThree } from "@react-three/fiber";
import { useEffect, useRef } from "react";
import gsap from 'gsap'
const CameraControls = ({position, target}) => {
const { camera } = useThree();
const ref = useRef(null);
function cameraAnimate() {
if (ref.current) {
gsap.timeline().to(
camera.position,
{
duration: 2,
repeat: 0,
x: position.x,
y: position.y,
z: position.z,
ease: "power3.inOut",
});
gsap.timeline().to(
ref.current.target,
{
duration: 2,
repeat: 0,
x: target.x,
y: target.y,
z: target.z,
ease: "power3.inOut",
}
);
}
}
useEffect(() => {
cameraAnimate();
}, [target, position]);
return (
<OrbitControls ref={ref} />
);
};
export { CameraControls };
해당 포스트에서는 현재 상태에서 카메라 이동 애니메이션을 한번만 적용시켰기 때문에 간단하게 구현했지만,
클릭 시 애니메이션을 적용할 오브젝트가 여러 개인 경우라면 인덱스 값마다 position
과 target
좌표를 미리 설정해놓은 후, handleOnClick
함수에 각 오브젝트를 식별할 수 있는 인덱스 값을 넘겨주고 CameraControls
에서 애니메이션이 발생하도록 응용할 수 있다.
추가로, 포커싱 이후 다시 클릭했을 때 기존 상태로 position
과 target
좌표를 설정하고 싶다면?
클릭했던 오브젝트의 인덱스와 새로 클릭하는 오브젝트의 인덱스가 같은지를 판단하고 같은 경우 이 함수를 호출하는 방식으로 응용할 수 있다.
원상태의 카메라 positin
과 target
좌표가 공통으로 쓰인다면setCamera
와 같은 이름의 함수를 추가하여 필요할 때마다 setCamera
함수를 호출하는 방식으로 구현할 수 있다.
Camera Animation using React Three Fiber and GSAP
https://vaisakhnp.hashnode.dev/camera-animation-using-react-three-fiber-and-gsap#heading-adding-animation-to-scene
오 JS에도 animation tweening 라이브러리가 있군요!
이걸 three.js에 사용하는 건 신기하네요!