본문 바로가기
개발일지

[2023.04.27 개발 일지] 리액트에서 three.js 사용하기

by Forsaken Developer 2023. 5. 1.
728x90
728x90

[2023.04.27 개발 일지] 리액트에서 three.js 사용하기

주요 업무 내용

  • 리액트에서 three.js 사용
  • 3D 모델 띄우기
  • 애니메이션 적용하기

sketchfab에 무료로 제공되고 있는 이 3D 모델을 메인 페이지에 three.js를 사용해서 띄우고 싶었다.

react에서 three.js 사용하기 위해서는 주로 React Three Fiber를 사용한다고 한다.

React Three Fiber는 컴포넌트 기반으로 간단하게 Three.js를 사용할 수 있으며 WebGL 기능을 최적화하여 렌더링속도를 높인다.

또한 React-three/drei라는 React Three Fiber의 확장 라이브러리를 통해서 React Three Fiber에서 사용할 수 있는 OrbitControls, Sky, Environment, Text, Effects 등과 같은 다양한 컴포넌트를 사용할 수 있다.

먼저 Three, @react-three/fiber, @react-three/drei를 설치한다.

npm install three @types/three @react-three/fiber @react-three/drei

sketchfab에서 3D 모델을 gltf 형식으로 받은 후에  폴더에서 cmd를 열어 다음 명령어를 입력한다.

npx gltfjsx scene.gltf

scene.js라는 파일이 생성되는데 gltf 파일을 React컴포넌트로 변환하여 gltf 모델을 렌더링 할 수 있게 한다.

scene.js 파일을 복사해서 Model.js라는 컴포넌트를 생성한다.

import React, { useRef,useEffect } from 'react'
import { useGLTF, useAnimations } from '@react-three/drei'

export default function Model(props) {
  const group = useRef()
  const { nodes, materials, animations } = useGLTF('/scene.gltf')
  const { actions } = useAnimations(animations, group);

  useEffect(()=>{
    actions.Dance.play();
  })
  return (
    <group ref={group} {...props} dispose={null}>
      <group name="Sketchfab_Scene">
        <group name="Sketchfab_model" position={[-1, -10, -20]} rotation={[-Math.PI / 2, 0, 0]}>
          <group name="root">
            <group name="GLTF_SceneRootNode" rotation={[Math.PI / 2, 0, 0]}>
              <group name="Pikachu_49" rotation={[Math.PI / 2, 0, 0]} scale={0.2}>
                <group name="GLTF_created_0">
                  <primitive object={nodes.GLTF_created_0_rootJoint} />
                  <group name="PikachuM_48" />
                  <skinnedMesh name="Object_7" geometry={nodes.Object_7.geometry} material={materials.Material_160} skeleton={nodes.Object_7.skeleton} />
                  <skinnedMesh name="Object_8" geometry={nodes.Object_8.geometry} material={materials['Material.001']} skeleton={nodes.Object_8.skeleton} />
                  <skinnedMesh name="Object_9" geometry={nodes.Object_9.geometry} material={materials['Material.003']} skeleton={nodes.Object_9.skeleton} />
                  <skinnedMesh name="Object_10" geometry={nodes.Object_10.geometry} material={materials['Material.002']} skeleton={nodes.Object_10.skeleton} />
                </group>
              </group>
            </group>
          </group>
        </group>
      </group>
    </group>
  )
}

useGLTF.preload('/scene.gltf')

3D 모델에 기본적인 Walking, Dance, Jump, Idle과 같은 애니메이션이 포함되어 있어서 단순히 Dance 애니메이션을 실행하려고 했다.

 drei의 useAnimations hook을 통해서 애니메이션을 쉽게 실행할 수 있다.

기본적으로 배경을 제공해주긴 하지만 퀄리티가 좋지 않아서 보다 포켓몬에 어울리는 배경을 찾던중에 OPEN3DLAB에서 마침 포켓몬 센터 hdr 파일이 있어서 사용하였다.

drei의 Environment 컴포넌트에 prop으로 파일의 경로만 전달하면 쉽게 배경을 변경할 수 있다.

import styled from "styled-components";
import { Canvas } from "@react-three/fiber";
import { Suspense } from "react";
import { Environment, OrbitControls, Html } from "@react-three/drei";
import Model from "../components/Poke/Model";
import GifProgress from "../components/UI/GifProgress";
import pikachuGif from "../assets/pikachu-progress.gif";

const StyledMain = styled.main`
  width : 100vw;
  height: 100vh;
`;

const HomePage = () => {
  return (
    <StyledMain className="main">
      <Canvas>
        <Suspense
          fallback={
            <Html center>
                <GifProgress
                  width="15rem"
                  src={pikachuGif}
                  text="Loading..."
                  fontSize="1.5rem"
                />
            </Html>
          }
        >
          <Model />
          <OrbitControls />
          <Environment files="/pokemon-center.hdr" background />
        </Suspense>
      </Canvas>
    </StyledMain>
  );
};

export default HomePage;

fiber에서 Canvas를 import 하고 Model 컴포넌트를 하위 컴포넌트로 사용하기만 하면 모델을 띄울 수 있다.

lazy loading을 배우기만 하고 평소에 사용해보지 않았는데 fiber에서 제공하는 기본 예제에서 Suspense와 fallback을 사용하여 최적화 한다.

최종적으로 배경과 모델을 띄우고 애니메이션을 재생하는데에 성공했다.

이번에는 단순히 모델을 띄우고 애니메이션을 실행하기만 했지만 키보드 이벤트로 모델을 움직이고 다른 모델과의 물리적인 상호작용도 가능하기때문에 더욱 흥미가 생긴다.

기회가 되면 three.js의 기본부터 렌더링 관련 개념도 학습해보고 싶어졌다.

728x90
반응형

댓글