본문 바로가기
🎨 Front-end/React.js

React + GSAP + Three.js 활용해 살아움직이는 3D Web 만들어보기

by Jay Anderson 2025. 11. 9.

실로 오랜만의 포스팅이다.

이사 후 새로운 환경에 적응(이라 쓰고 만끽이라 읽음) 하느라...

그보다 애초에 주변 지인들에게 제공하고 함께 여러 정보를 공유하며

서로 스킬업, 성장할 목적으로 IT 포스팅을 시작하게 된건데, 지인들이 공부를 잘 안함...

지금 보고 있는 너! 반성해라 ㅋㅋㅋㅋㅋ 같이 반성하자... ㅠㅠ

 

하긴. 요즘 세상, 코딩 잘 할 필요 없다. 정확히 말 하면, 큰 틀에서의 개념만 잘 알고 있어도 되는 세상이긴 함.

그래도, 직접 해본다는 재미가 있으니까. 그리고 직접 할 줄 알아야 AI와의 협업에서 AI가 뻘짓탭댄스춰도 바로잡아줄수 있는거임.

인간은 AI가 있다고 손 놓고 쉴게 아니라, AI와 함께 나아가야 함. 그래야 AI 또한 자신의 창조주를 본받을 지니...

 

아무튼, 곧 대세는 3D Web이 될 것이다. 큰 정보 없는 소규모 기업홈페이지 같은것마저 3D효과로 만들어질정도로 3D 기술이 흔하고도 흔해질 것이다. Three.js는 내가 2020년부터 꾸준히 강조해 온 기술이다.

 

그러니, React환경에서 GSAP과 3D 더미파일 대충아무거나 넣어서 스크롤에 따라 움직이는 신박한 웹페이지 만들어보기 시작!

 

 

📁 프로젝트 구조(예)

/src
 ┣ /components
 ┃ ┣ Scene.jsx           ← Three.js 씬 + 모델 로드
 ┃ ┗ CameraScroll.jsx    ← 스크롤 따라 카메라 움직임 제어
 ┣ /models
 ┃ ┗ dummy.glb           ← 간단한 GLTF 모델 (예: 큐브, 사람 모형)
 ┣ App.jsx
 ┗ index.js

 

대략 이렇게 한번 해 볼까 함. 만들다가 중간에 바뀔수도 있는 점 양해좀.

dummy.glb라는건 3D모델 파일인데, 대충 아무거나 가져다 쓸거라 dummy라고 이름지었다.

3D모델링 툴 오픈한 뒤, 기본 오브젝트 그대로 glb로 저장해 가져다 쓸거임. 난 3D모델링은 못하니까...

 

 

📌 새 프로젝트 만들기

# 1. 새 프로젝트 생성
npx create-react-app three-scroll-demo
cd three-scroll-demo

# 2. Three.js, React Three Fiber, Drei, GSAP 설치
npm install three @react-three/fiber @react-three/drei gsap

 

React로 해보자. 이유는 간단하다.

Three.js 관련 레퍼런스가 많아 확장성이 충분히 용이하기 때문이다!

 

 

📌 App.jsx (예시)

import React from "react";
import { Canvas } from "@react-three/fiber";
import { ScrollControls, Scroll } from "@react-three/drei";
import Scene from "./components/Scene";
import CameraScroll from "./components/CameraScroll";

export default function App() {
  return (
    <Canvas camera={{ position: [0, 1, 5], fov: 50 }}>
      <ambientLight intensity={0.5} />
      <directionalLight position={[5, 5, 5]} intensity={1} />
      {/* ScrollControls: 전체 스크롤 가능한 영역 */}
      <ScrollControls pages={4} damping={0.2}>
        <Scene />
        <Scroll html>
          <div style={{ height: "400vh" }}>
            <section style={{ height: "100vh", textAlign: "center" }}>
              <h1>Company Story</h1>
            </section>
            <section style={{ height: "100vh", textAlign: "center" }}>
              <h1>History</h1>
            </section>
            <section style={{ height: "100vh", textAlign: "center" }}>
              <h1>Meet Our Team</h1>
            </section>
            <section style={{ height: "100vh", textAlign: "center" }}>
              <h1>Building Overview</h1>
            </section>
          </div>
        </Scroll>
        <CameraScroll />
      </ScrollControls>
    </Canvas>
  );
}

 

대충 이런 느낌으로 해보려고 한다.

구조를 보면 알 수 있듯, 우리가 작업할 3D 효과들은 <Canvas> 로 말아지게 될 것임.

스타일 컴포넌트 사용하여 체계적으로 꾸미시길 바람. 물론 난 함ㅋㅋ

 

 

 

📌 Scene.jsx (예시)

import React from "react";
import { useGLTF } from "@react-three/drei";

export default function Scene() {
  // 더미 모델 (간단한 GLB 파일)
  const { scene } = useGLTF("/models/dummy.glb");

  return (
    <primitive
      object={scene}
      position={[0, -1, 0]}
      scale={[1.2, 1.2, 1.2]}
    />
  );
}

 

 

 

 

📌 CameraScroll .jsx (예시)

import { useThree, useFrame } from "@react-three/fiber";
import { useScroll } from "@react-three/drei";
import { gsap } from "gsap";
import { useEffect } from "react";

export default function CameraScroll() {
  const { camera } = useThree();
  const scroll = useScroll();

  useEffect(() => {
    // 초기 위치
    camera.position.set(0, 1, 5);
  }, [camera]);

  useFrame(() => {
    const offset = scroll.offset; // 0~1 범위
    gsap.to(camera.position, {
      x: Math.sin(offset * Math.PI * 2) * 2,
      y: 1 + Math.sin(offset * Math.PI) * 1,
      z: 5 - offset * 5,
      duration: 0.5,
      ease: "power2.out",
    });
    camera.lookAt(0, 0, 0);
  });

  return null;
}

 

 

 

 

1️⃣ <Canvas> (from @react-three/fiber)

  • 역할: Three.js에서 3D 장면(Scene)을 그리는 공간.
  • 쉽게 말하면 3D 화면을 담는 그릇.
  • camera={{ position: [0, 1, 5], fov: 50 }}
    • position: 카메라가 3D 공간에서 어디에 있는지
    • fov: 시야각(Field of View), 넓게 볼수록 멀리까지 보임.

2️⃣ <ambientLight> & <directionalLight>

  • 조명(Light). 3D 모델을 보여주려면 빛이 필요하니까
    • ambientLight: 전체적으로 은은하게 모델을 비춰주는 빛
    • directionalLight: 태양빛처럼 특정 방향에서 비추는 빛
  • 3D에서 조명 없으면 모델이 까맣게 보임

3️⃣ <ScrollControls> (from @react-three/drei)

  • 스크롤과 3D를 연결해주는 역할
  • pages={4}: 총 4페이지 분량의 스크롤 영역 생성
  • damping={0.2}: 스크롤의 부드러움 조절 (감속 정도)
  • 안에 <Scene>이나 <Scroll html> 같은 요소를 넣어 스크롤과 3D 동기화 가능

4️⃣ <Scene>

  • 우리가 만든 3D 모델과 오브젝트가 들어가는 컴포넌트
  • 예) 더미 큐브나 GLTF 모델을 불러와 화면에 띄움

5️⃣ <Scroll html>

  • HTML 요소를 스크롤 영역에 넣고 3D 씬과 함께 움직이도록 만들어주는 컴포넌트
  • 여기서는 <div> 안에 <section> 여러 개를 넣어서, 스크롤할 때 텍스트 섹션들이 화면에 차례대로 나타나도록

6️⃣ <CameraScroll>

  • 카메라를 스크롤에 맞춰 이동시키는 기능을 담당
  • 예: 스크롤 내리면 카메라가 앞으로 이동하거나 위로 올라가는 느낌
  • 보통 useFrame, useRef를 활용해서 카메라 position을 바꾸는 로직이 들어있음

 

🔹 정리하면...

  1. Canvas → 3D 장면을 그리는 화면
  2. Lights → 모델이 안 어둡게 보이게 조명
  3. ScrollControls → 스크롤과 3D 씬 연결
  4. Scene → 실제 3D 모델과 오브젝트
  5. Scroll html → HTML 텍스트를 3D 씬과 같이 스크롤
  6. CameraScroll → 카메라 이동 / 시점 연출

 

 

3D모델인 glb는 정적 자산이므로 /public/models/ 폴더 안에 잘 넣어두려고 한다. 그렇다면 glb파일을 어떻게 만들 수 있을까?

 

 

📌 Blender 설치

https://www.blender.org/download/

 

여기서 다운받아 설치하고 실행하자.

 

 

이 상태 그대로, 상단 파일(File) > 내보내기(Export) > glTF 2.0 (.glb/.gltf) 를 선택.

경로는 우리가 만든 프로젝트 루트의 /public/models/ 안으로 저장하자.

파일명은 그냥 나처럼 dummy 로 하던가 하고싶은거 하자.

 

 

 

참고로, 특정 Section에서 스크롤 트리거에 의한 효과를 주고싶다면, Section을 컴포넌트화 하는것이 관리에 매우 유용함.

 

 

 

📌 결과... (Github)

https://yngcompany.github.io/3DWeb-prototype/

 

React App

 

yngcompany.github.io

 

 

 

 

 

 

이제, 3D 모델 데이터만 받쳐준다면

Web으로 엄청 재밌는 것들을 해 볼 수 있게 되었다.

아마 로그인이 필요없는 간단한 3D Web Game을 만드는 것도 가능할 것이다.

 

TOP

Designed by AndersonLab