본문 바로가기
웹 프로젝트/😺Just Meow It: 고양이의 조언

[😺Just Meow It: 고양이의 조언] Three.js + Next.js / 3D 고양이 모델을 화면에 띄워보자

by 청량리 물냉면 2025. 3. 30.
반응형

📌 프로젝트 초기 세팅 (Next.js + TypeScript + Three.js)

# Next.js 프로젝트 생성
npx create-next-app@latest just-meow-it --typescript

# 필요한 패키지 설치
cd just-meow-it
yarn install
yarn add @react-three/fiber @react-three/drei three
  • `@react-three/fiber` === R3F → Three.js를 React에서 사용할 수 있도록 도와주는 라이브러리. 즉 Three.js의 React 버전
  • `@react-three/drei` → Three.js 유틸리티 (카메라, 조명, OrbitControls 등)
  • `three` → Three.js 라이브러리

 

📌 기본 코드 (고양이 모델 띄우기)

이제 기본적인 3D 고양이를 화면에 띄워보겠다.🐱💬

그 이전에 우선 Sketchfab 사이트에서 적절한 고양이 모델을 다운로드 받은 뒤, `public` 폴더 아래 넣어두었다.

 

1️⃣ 고양이 모델 컴포넌트 (`components/CatModel.tsx`)

"use client";

import { Canvas } from "@react-three/fiber";
import { OrbitControls, useGLTF } from "@react-three/drei";
import { Suspense } from "react";

const CatModel = () => {
    const { scene } = useGLTF("/cat_model/scene.gltf");  // public 폴더의 glTF 모델 로드
    return <primitive object={scene} scale={0.06} position={[0, -1, 0]} />;
};

const CatScene = () => {
    return (
        <Canvas camera={{ position: [0, 2, 5] }}>
            <ambientLight intensity={0.5} />
            <directionalLight position={[2, 2, 2]} />
            <Suspense fallback={null}>
                <CatModel />
            </Suspense>
            <OrbitControls />
        </Canvas>
    );
};

export default CatScene;

 

코드에 대한 자세한 설명은 아래에서....

 

 

2️⃣ 레이아웃 (app/layout.tsx)

import type { Metadata } from "next";
import "./globals.css";


export const metadata: Metadata = {
  title: "Just Meow It",
  description: "고민이 있을 때는 고양이의 조언을 들어보세요.",
};

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="ko">
      <head />
      <body className="bg-gray-100">
        <div className="container mx-auto">{children}</div>
      </body>
    </html>
  );
}

 

메인 페이지의 공통 레이아웃을 작성하는 파일이다. 필요한 메타데이터 코드도 미리 넣어주었다.

 

 

3️⃣메인 페이지 (app/page.tsx)

import CatModel from "@/components/CatModel";

export default function Home() {
  return (
    <main className="flex flex-col items-center justify-center h-screen gap-6">
      <h1 className="text-3xl font-bold">🐱 고양이의 가르침</h1>
      <CatModel />
    </main>
  );
}

 

루트 도메인에서 화면에 표시될 데이터를 불러온다.

간단하게 제목과 고양이 모델 컴포넌트 2개만 렌더링해보았다.

 

 

📌 실행해보기

yarn dev

귀여운 고양이 모델이 화면에 뜬다...!🦾

 

 

 

📌 catModel에 대한 상세한 설명

"use client";

import { Canvas } from "@react-three/fiber";
import { OrbitControls, useGLTF } from "@react-three/drei";
import { Suspense } from "react";

const CatModel = () => {
    const { scene } = useGLTF("/cat_model/scene.gltf");  // public 폴더의 glTF 모델 로드
    return <primitive object={scene} scale={0.06} position={[0, -1, 0]} />;
};

const CatScene = () => {
    return (
        <Canvas camera={{ position: [0, 2, 5] }}>
            <ambientLight intensity={0.5} />
            <directionalLight position={[2, 2, 2]} />
            <Suspense fallback={null}>
                <CatModel />
            </Suspense>
            <OrbitControls />
        </Canvas>
    );
};

export default CatScene;

위 코드는 `react-three/fiber`와 `@react-three/drei`를 사용해 3D 모델을 로드하고 렌더링하는 코드이다.

 

"use client";

가장 먼저, 컴포넌트가 클라이언트 사이드에서만 렌더링되도록 지정해 준다. 해당 키워드를 통해서버 사이드 렌더링(SSR)을 비활성화하고 컴포넌트를 클라이언트 전용으로 처리하게 만들 수 있다.

 

🤔 왜 클라이언트 사이드 렌더링 처리를 하는가?

Three.js는 3D 그래픽 렌더링을 위한 클라이언트 측 라이브러리로, 브라우저에서 실행되는 WebGL을 사용한다.

WebGL은 서버에서 실행되지 않고 클라이언트의 브라우저 환경에서만 실행된다. 따라서 Three.js를 사용할 때는 클라이언트 사이드에서만 렌더링되도록 해야 한다.

 

import { Canvas } from "@react-three/fiber";
import { OrbitControls, useGLTF } from "@react-three/drei";
import { Suspense } from "react";
  • `@react-three/fiber`에서 CanvasThree.js 씬을 그릴 캔버스이다. 3D 모델을 포함한 장면을 렌더링하는 역할을 한다.
  • `@react-three/drei`는 Three.js를 React에서 사용하기 위한 유용한 유틸리티와 컴포넌트들을 제공한다. 
    • `OrbitControls`: 카메라가 3D 모델 주위를 회전할 수 있게 도와주는 컨트롤러
    • `useGLTF`: GLTF (GL Transmission Format) 형식의 3D 모델을 로드하는 훅
  • Suspense는 React에서 비동기 컴포넌트를 처리할 때 로딩 상태를 관리하는 컴포넌트이다. 여기서는 모델 로딩 중에 대기 상태를 처리하기 위해 사용된다.

 

const CatModel = () => {
    const { scene } = useGLTF("/cat_model/scene.gltf");  // public 폴더의 glTF 모델 로드
    return <primitive object={scene} scale={0.06} position={[0, -1, 0]} />;
};
  • CatModel 컴포넌트는 `useGLTF` 훅을 사용하여 cat_model/scene.gltf 경로의 3D 모델을 로드한다.
    • useGLTF("/cat_model/scene.gltf"): public 폴더에 위치한 GLTF 모델 파일을 비동기적으로 로드한다. 로딩된 모델은 scene 객체로 반환된다.
    • <primitive object={scene} />: 로드된 GLTF 모델을 React 컴포넌트에서 렌더링하기 위해 `primitive`를 사용한다. primitive는 Three.js 객체를 React 컴포넌트로 변환할 때 사용된다.
    • scale={0.06}: 모델의 크기를 0.06배로 조정한다.
    • position={[0, -1, 0]}: 모델의 위치를 (x, y, z) 좌표로 설정한다.

 

const CatScene = () => {
    return (
        <Canvas camera={{ position: [0, 2, 5] }}>
            <ambientLight intensity={0.5} />
            <directionalLight position={[2, 2, 2]} />
            <Suspense fallback={null}>
                <CatModel />
            </Suspense>
            <OrbitControls />
        </Canvas>
    );
};
  • CatScene 컴포넌트는 3D 모델을 렌더링하는 장면을 구성한다.
    • <Canvas camera={{ position: [0, 2, 5] }}>: Canvas는 `react-three/fiber`에서 사용하는 컨테이너로, 3D 씬을 렌더링하는 역할을 한다.
      • `camera`: 카메라의 초기 위치를 설정하는 속성
      • `position: [0, 2, 5]`: 카메라가 3D 씬의 [0, 2, 5] 위치에 배치됨을 의미
    • <ambientLight intensity={0.5} />: Ambient light는 3D 씬에서 모든 객체를 균일하게 밝히는 조명이다. intensity로 밝기를 설정할 수 있다.
    • <directionalLight position={[2, 2, 2]} />: Directional light태양과 같은 강한 빛을 시뮬레이션한다. position 속성으로 빛의 위치를 지정한다.
    • <Suspense fallback={null}>: Suspense는 CatModel 컴포넌트가 로딩되는 동안의 로딩 상태를 처리하는데 사용된다. 현재는 `fallback={null}`로 설정해서, 로딩 중에 아무것도 표시되지 않고 있다.
    • <OrbitControls />: 사용자가 마우스를 이용해 3D 씬을 회전, 확대/축소할 수 있게 해주는 컨트롤러이다.

 

 

📌 참고한 문서

  • Three.js: Three.js의 공식 사이트
  • @react-three/fiber: React에서 Three.js를 사용할 수 있게 해주는 라이브러리, 공식 GitHub 레파지토리
  • @react-three/drei: Three.js와 React를 결합하는데 유용한 다양한 추가 컴포넌트를 제공하는 라이브러리, 공식 GitHub 레파지토리

 

 

배포한 사이트 링크

Just Meow It | 고양이의 조언으로 고민 해결하기

 

Just Meow It | 고양이의 조언으로 고민 해결하기

고양이의 지혜를 통해 고민을 해결해 보세요.

just-meow-it.timeqlife.com

다음 주 주말에 오픈그래프도 추가해야지...

반응형