22sook00 logo
SookDev
🪐

Three.js card interaction

tag
3d
date
Jan 25, 2024

01_ShapeGeometry 를 이용한 카드의 곡선표현

absarc 앱솔루트아크 메소드
border-radius 와 비슷한 개념
absarc 는 총 여섯개의 인자를 받을 수 있다.
radius인 border-radius 가 있는 직사각형을 표현하기 위해서 반시계 혹은 시계방향으로 회전한 만큼을 생각하면 된다.
startAngle, endAngle 은 각각 부채꼴 중심각의 시작, 끝 각도를 의미하며,
clockwise 는 시계방향으로 꺾을지, 반시계로 꺾을지 정하는 값을 받는다.
notion image
위 그림과 설명을 토대로 곡선이 있는 부드러운 카드를 만든다면
우측상단의 곡선
notion image
  • 회전의 중심점 x,y 좌표를 구한다.
  • 전체카드 width의 절반값에서 radius 를 뺀 값이 x 좌표가 된다.
  • 전체카드 height 의 절반값에서 radius 를 뺀 값이 y 좌표가 된다.
    • const x = width / 2 - radius; const y = height / 2 - radius;
notion image
  • 회전각의 시작과 끝값을 정해준다.
  • x 축 양의방향을 기준으로 90도에서 0도 방향으로, 시계방향으로 회전시킨다.
  • 이때 각도가 아닌, 파이 형식으로 넣어줘야 하기 때문에 90도는 Math.PI 를 2로 나눈값이되고 0은 그냥 0 처리 한다.
    • shape.absarc(x, y, radius, Math.PI / 2, 0, true)
notion image
notion image
 
  • 첫번째 부채꼴이 끝나는 시점부터 그다음 부채꼴이 시작되는 지점까지의 직선길이를 구하려면 radius 의 길이를 뺀 나머지가 되어야 한다.
  • 우측하단의 x 값은 방금 계산한 x 값에 radius 를 더한값이 되고, y 값은 방금 계산한 y값의 부호만 반대로 설정해주면 된다.
    • shape .absarc(x, y, radius, Math.PI / 2, 0, true) // 앱솔루트아크 메소드는 타워모양의 곡선을 그릴때 사용 가능 .lineTo(x + radius, -y);
  • 길이를 구했으니 부채꼴의 중심점을 알아내어 x,y 좌표를 구해야 한다.
  • 이전과 x 좌표는 똑같고, y 좌표는 부호만 반대로 하여 -y가 된다.
  • 회전의 시작과 끝 각도는 0도에서 -90도인 시계방향으로 진행된다.
    • shape .absarc(x, y, radius, Math.PI / 2, 0, true) // 앱솔루트아크 메소드는 타워모양의 곡선을 그릴때 사용 가능 .lineTo(x + radius, -y) .absarc(x, -y, radius, 0, -Math.PI / 2, true);
이런식으로 나머지 부분도 계산한다면 다음과 같이 최종 코드가 작성된다.
notion image
//https://threejs.org/docs/?q=shape#api/en/geometries/ShapeGeometry const shape = new THREE.Shape(); shape .absarc(x, y, radius, Math.PI / 2, 0, true) // 앱솔루트아크 메소드는 타워모양의 곡선을 그릴때 사용 가능 .lineTo(x + radius, -y) .absarc(x, -y, radius, 0, -Math.PI / 2, true) .lineTo(-x, -(y + radius)) .absarc(-x, -y, radius, -Math.PI / 2, Math.PI, true) .lineTo(-(x + radius), y, radius, Math.PI, Math.PI / 2, true) .absarc(-x, y, radius, Math.PI, Math.PI / 2, true);

02_카드의 두께감 표현하기

ExtrudeGeometry
shapeGeometry 는 두께감을 표현하지 못하기 때문에 ExtrudeGeometry 를 대신 이용할 수 있다.
앞서 설정한 shape 인스턴스를 인자로 받을 수 있고 다양한 속성들을 두번째 인자로 설정할 수 있다.
const geometry = new THREE.ExtrudeGeometry(shape, { depth: 0.01, bevelThickness: 0.1, });
ShapeGeometry
ShapeGeometry
ExtrudeGeometry
ExtrudeGeometry
 
ExtrudeGeometry 를 사용했을때 최대로 확대해보면 여러개의 경계면이 있는것을 볼 수 있다.
이러한 경사진면의 두께를 더 부드럽게 표현하기 위해서 TextGeometry에서 다뤘던 bevel 옵션을 사용할 수 있다.
const geometry = new THREE.ExtrudeGeometry(shape, { depth: 0.01, bevelThickness: 0.1, });
notion image
bevelThickness 적용
bevelThickness 적용
 

03_카드 애니메이션 구현하기

gsap
import { gsap } from "gsap"; gsap.to(card.mesh.rotation, { y: -Math.PI * 4, //한바퀴 돌리려면 파이값으로 2이므로 두바퀴에 해당하는 4를 곱한다. duration: 2.5, ease: "back.out(2.5)", });