언어·프레임워크/Next.js

[Next.js] 동일한 GLTF 모델을 2번 이상 렌더링하기(react-three-fiber/drei/Three.js)

DandyNow 2023. 12. 28. 09:45
728x90
반응형

1. 한 페이지에 하나의 GLTF만 렌더링 되는 문제

페이지에 하나의 GLTF 파일을 이용해 여러 개의 모델을 렌더링 하고자 하였다. 이미지 태그를 이용하는 방식처럼 당연히 가능할 거라 생각했는데 현실은 [그림 2]와 같이 마지막 하나의 구성만 적용되었다. 여러 테스트 중에 GLTF의 복사본의 만들어 이름을 달리하여 로드했더니 원하는 결과를 얻을 수 있었다. 하지만 렌더링 모델의 개수만큼 동일한 내용을 담고 있는 GLTF 파일을 무수히 만들 수는 없는 일이었다.

 

[그림 1] 2개 모델 중 마지막 모델만 화면에 보이고 있음

 

2. Clone으로 문제 해결

react-three-fiber에서 Clone 컴포넌트를 제공하고 있었다. 이 기능을 이용하여 [그림 2]와 같이 하나의 GLTF를 통해 2개 이상의 모델을 화면에 렌더링 할 수 있었다.

 

[그림 2] Clone 이용해 2개 이상 모델 렌더링 성공

 

해당 코드는 아래와 같다.

// page.tsx
"use client";
import React from "react";
import CharacterViewer from "./CharacterViewer";

export default function Page() {
  const characterPath = "red_01.glb";

  return (
    <>
      <div>
        <CharacterViewer characterPath={characterPath} />
      </div>
      <div>
        <CharacterViewer characterPath={characterPath} />
      </div>
    </>
  );
}

 

// CharacterViewer.jsx
"use client";
import React, { Suspense } from "react";
import { Canvas, useFrame } from "@react-three/fiber";
import { Clone, OrbitControls, useGLTF } from "@react-three/drei";
import * as THREE from "three";

const Character = ({ characterPath, scale }) => {
  const { scene, animations } = useGLTF(characterPath);

  let mixer = null;

  // 애니메이션 재생
  if (animations.length !== 0) {
    mixer = new THREE.AnimationMixer(scene);
    void mixer.clipAction(animations[0]).play();

    // eslint-disable-next-line react-hooks/rules-of-hooks
    useFrame((state, delta) => {
      mixer.update(delta);
    });
  }

  return (
    <Clone object={scene} scale={scale} /> // 애니메이션 재생 안됨
    // <primitive object={scene} scale={scale} /> // 애니메이션 재생됨
  );
};

const CharacterViewer = ({ characterPath }) => {
  return (
    <div>
      // Canvas에 키를 주어야 렌더링 오작동을 예방할 수 있음
      <Canvas key={characterPath} camera={{ position: [20, 0, -8] }}>
        <OrbitControls />
        <ambientLight intensity={2} />
        <pointLight position={[10, 10, 10]} />
        <group {...characterPath} dispose={null} rotation-y={Math.PI / 2}>
          <Character scale={[15, 15, 15]} characterPath={characterPath} />
        </group>
        <Suspense fallback={null}></Suspense>
      </Canvas>
    </div>
  );
};

export default CharacterViewer;

 

3. 또 다른 문제

primitive 태그를 이용하면 모델의 애니메이션이 정상적으로 동작하지만, Clone 태그를 이용하면 재생되지 않는 문제가 있어 숙제가 생겼다.

 

참고 자료
https://stackoverflow.com/questions/68813736/use-the-same-gltf-model-twice-in-react-three-fiber-drei-three-js

 

728x90
반응형