> Frontend/ThreeJS

TIL-2024.03.14 - 3js - Interactive Card - 1. 카드 모형 만들기

Janku 2024. 3. 14. 15:37

 

 

 

목표:

  1. Card Class
  2. Shape Geometry
  3. Extrude Geometry
  4. Orbit Controls 컨트롤 설정
  5. GSAP을 이용한 애니메이션 구현

 

 

Card Class

 

- card.js

import * as THREE from "three";

class Card {
    constructor({width, height, color}) {
        const shape = new THREE.Shape()
        const geometry = new THREE.ShapeGeometry(shape);
        const material = new THREE.MeshStandardMaterial({color, side: THREE.DoubleSide}); // 정면만 렌더링

        const mesh = new THREE.Mesh(geometry, material);
        console.log(1, this)
        console.log(2, mesh)
        this.mesh = mesh;
    }
}

export default Card;

 

  • Mesh는 Three.js에서 3D 객체를 나타내는 기본적인 요소로.  Geometry(기하)와 Material(재질)로 구성됨

  • Geometry(기하):
    - Mesh의 모양이나 구조를 정의.
    - 객체의 형태, 꼭짓점, 면 및 경계를 결정.
    - Geometry는 점, 선, 면 또는 이들의 조합으로 구성됩니다.

  • Material(재질):
    - Mesh가 어떻게 보일지를 결정.
    - 객체의 색상, 빛, 반사율 등을 제어.
    - 재질은 Mesh를 렌더링할 때 표면의 시각적 특성을 정의.

-> MeshGeometryMaterial을 결합하여 실제로 화면에 그려지는 3D 객체를 형성

 

 

 

- main.js

import * as THREE from "three";
import Card from "./card";
import { OrbitControls } from "three/addons";
import {GUI} from 'lil-gui'

window.addEventListener("load", () => {
    init();
});

const init = () => {
    const gui = new GUI();
    const card = new Card({
        width: 10,
        height: 15.8,
        color: "#0077ff",
    });


... 생략 ...

 

이와 같이, Class 로 만들어서, 다른 파일에서 Obj를 생성해서 사용.

 

 

 

Shape Geometry

import * as THREE from "three";

class Card {
    constructor({width, height, radius, color}) {
        const shape = new THREE.Shape();
        const x = width / 2 - radius;
        const y = height / 2 - radius;

        // shape의 Geometry 를 카드 형태로 변경
        shape
            .absarc(x, y, radius, Math.PI / 2, 0, true) // 타원모형의 곡선에서 사용 > x , y , startAngle, endAngle, clockwise 를 인자로 받음
            .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 / 2, true)
            .absarc(-x, y, radius, Math.PI, Math.PI / 2, true);

        const geometry = new THREE.ShapeGeometry(shape);
        
        // shape의 material를 통해, 색깔 변경 및 뒷면 표시
        const material = new THREE.MeshStandardMaterial({color, side: THREE.DoubleSide}); // 기본값은 정면만 렌더링하므로, 양측 렌더링위해 변경
        
        
        // 값 합체
        const mesh = new THREE.Mesh(geometry, material);

        this.mesh = mesh;
    }
}

export default Card;

 

 

 

 

 

Extrude Geometry

 

- Shape Geometry 는 두께감이 없음

- Extrude Geometry는 경로 모양에서 돌출된 형상 즉, 두께감이 있는 Geometry 

 

const options = {
    depth: 0.01, // 두께감
    bbevelThickness: 0.1, // 경계
};
const geometry = new THREE.ExtrudeGeometry(shape, options);

 

 

 

 

Orbit Controls 카메라 설정

 

const controls = new OrbitControls(camera, renderer.domElement);
controls.autoRotate = true; // 자동 회전
controls.autoRotateSpeed = .75; // 회전 속도
controls.enableDamping = true; // 감쇠 관성
controls.enableZoom = false; // 줌 기능
controls.minPolarAngle = Math.PI / 2 - Math.PI / 3; // 수직 궤도 얼마나 돌 수 있는지 하한 - 0 ~ Math.PI
controls.maxPolarAngle = Math.PI / 2 + Math.PI / 3; // 수직 궤도 얼마나 돌 수 있는지 상한 - 0 ~ Math.PI

 

 

 

 

 

 

gsap 라이브러리를 사용한 애니메이션 효과 

 

 

참조: https://gsap.com/

 

 

 

1. 설치

yarn add gsap

 

2. import

import { gsap } from "gsap";

... 생략 ...

 

 

3. gsap 사용

 

    /* gsap -1 mesh.rotation */
    const gsapOptions1 = {
        y: -Math.PI * 4,
        duration: 2,
        ease: "back.out(4)",
    };
    gsap.to(card.mesh.rotation, gsapOptions1);