📌 프로젝트 초기 세팅 (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`에서 Canvas는 Three.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 씬을 회전, 확대/축소할 수 있게 해주는 컨트롤러이다.
- <Canvas camera={{ position: [0, 2, 5] }}>: Canvas는 `react-three/fiber`에서 사용하는 컨테이너로, 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
다음 주 주말에 오픈그래프도 추가해야지...
'웹 프로젝트 > 😺Just Meow It: 고양이의 조언' 카테고리의 다른 글
[😺Just Meow It: 고양이의 조언] Three.js + Next.js / vercel 배포 및 구글/네이버 검색어 등록, 구글 애드센스 광고 추가 (0) | 2025.04.05 |
---|