본문 바로가기
2D&3D/ThreeJS

react-three/drei

by curious week 2025. 6. 9.

 

1단계: 기초 유틸리티 익히기 (씬 구성 편의성)


🎯 목표

기본적인 씬을 구성할 수 있는 drei 유틸리티를 익혀서
OrbitControls, 카메라 설정, 배경, 로딩, 카메라 프레이밍 등을 손쉽게 구현하는 것이 목표입니다.


① OrbitControls – 마우스로 카메라 회전, 줌, 이동 제어

개념:
OrbitControls는 사용자의 마우스 입력에 따라 카메라를 움직이도록 만들어줍니다.

실습 목표:

  • 캔버스를 마우스로 드래그하면 회전
  • 휠로 확대/축소 가능
import { OrbitControls } from '@react-three/drei';

<Canvas>
  {/* ... */}
  <OrbitControls />
</Canvas>

② PerspectiveCamera, OrthographicCamera – 카메라 설정

개념:

  • PerspectiveCamera: 일반 3D 카메라 (멀리 있는 건 작게 보임)
  • OrthographicCamera: 평면 UI나 건축도면처럼 원근이 없음

실습 목표:

  • 두 카메라를 비교해서 각각 어떤 느낌인지 체험해보기
import { PerspectiveCamera, OrthographicCamera } from '@react-three/drei';

<Canvas>
  <PerspectiveCamera makeDefault position={[0, 0, 5]} fov={75} />
  {/* 또는 */}
  {/* <OrthographicCamera makeDefault position={[0, 0, 5]} zoom={100} /> */}
  <OrbitControls />
  <mesh>
    <boxGeometry />
    <meshStandardMaterial />
  </mesh>
</Canvas>

③ Environment – HDRI 기반 조명 환경 설정

개념:
Environment는 현실감 있는 조명과 반사를 위해 HDRI를 사용한 환경을 설정합니다.

실습 목표:

  • 씬에 현실적인 광원 반사 효과 추가
import { Environment } from '@react-three/drei';

<Canvas>
  <Environment preset="sunset" background /> {/* 'city', 'sunset', 'night' 등 */}
  <mesh>
    <sphereGeometry />
    <meshStandardMaterial metalness={1} roughness={0.1} />
  </mesh>
</Canvas>

④ Sky, Stars – 자연 배경 효과

개념:

  • Sky: 태양, 공기 산란 기반의 하늘
  • Stars: 밤하늘 별 표현

실습 목표:

  • 태양 위치나 별의 밀도 등을 조절해 시각적 효과 비교
import { Sky, Stars } from '@react-three/drei';

<Canvas>
  <Sky sunPosition={[100, 20, 100]} />
  {/* 또는 */}
  {/* <Stars radius={100} depth={50} count={5000} factor={4} fade /> */}
</Canvas>

⑤ useProgress, Html – 로딩 UI 표시

개념:

  • useProgress: 현재 로딩 상태 정보 (퍼센트 등) 제공
  • Html: 일반 HTML을 Canvas 위에 렌더링 (예: 로딩 텍스트)

실습 목표:

  • GLTF 로딩 시 퍼센트 표시되는 UI 만들기
import { Html, useProgress } from '@react-three/drei';

function Loader() {
  const { progress } = useProgress();
  return (
    <Html center>
      <div style={{ color: 'white' }}>Loading... {progress.toFixed(0)}%</div>
    </Html>
  );
}

// 사용 위치
<Canvas>
  <Suspense fallback={<Loader />}>
    <YourGLTFScene />
  </Suspense>
</Canvas>

⑥ Bounds – 자동 카메라 프레이밍

개념:
Bounds는 자동으로 카메라 위치와 줌을 조절해 모든 오브젝트가 보이게 해줍니다.

실습 목표:

  • 다양한 위치에 있는 Mesh들을 포함하도록 자동으로 카메라 조절
import { Bounds, OrbitControls } from '@react-three/drei';

<Canvas>
  <Bounds fit clip observe margin={1.2}>
    <OrbitControls />
    <mesh position={[-2, 0, 0]}>
      <boxGeometry />
      <meshStandardMaterial />
    </mesh>
    <mesh position={[2, 0, 0]}>
      <sphereGeometry />
      <meshStandardMaterial />
    </mesh>
  </Bounds>
</Canvas>

 

OrbitControls 마우스 기반 카메라 제어 기본 회전/줌
PerspectiveCamera, OrthographicCamera 카메라 유형 비교 시야각, 줌 이해
Environment HDR 조명 환경 preset 테스트
Sky, Stars 자연 배경 효과 태양 위치 / 별 표현
useProgress, Html 로딩 상태 표시 Suspense와 함께 사용
Bounds 자동 카메라 프레이밍 오브젝트 자동 보기 맞춤

 

2단계: 3D UI와 애니메이션 연동

목표: 상호작용 가능한 UI와 3D 오브젝트에 애니메이션을 연동하여, 몰입감 있는 인터페이스를 구현


1. Text – 3D 텍스트 생성

import { Text } from '@react-three/drei';

<Text
  font="/fonts/Inter-Bold.woff"
  fontSize={1}
  color="white"
  anchorX="center"
  anchorY="middle"
  position={[0, 2, 0]}>
  Hello World!
</Text>

설명:

  • font: WebFont (.woff, .ttf) 경로
  • fontSize: 글자 크기 (world unit)
  • anchorX/Y: 기준점 (중앙 정렬 등)
  • 3D 공간 내에 위치하는 텍스트로써 HUD와 다름

2. useCursor – 마우스 상태에 따른 커서 변경

import { useCursor } from '@react-three/drei';
import { useState } from 'react';

const MyMesh = () => {
  const [hovered, setHovered] = useState(false);
  useCursor(hovered);

  return (
    <mesh
      onPointerOver={() => setHovered(true)}
      onPointerOut={() => setHovered(false)}>
      <boxGeometry />
      <meshStandardMaterial />
    </mesh>
  );
};

설명:

  • 마우스가 오브젝트 위에 올라가면 cursor: pointer 적용
  • hovered 상태만 관리해주면 됨

3. useGLTF, Gltf – GLTF 모델 불러오기

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

const Model = () => {
  const { scene } = useGLTF('/models/character.glb');
  return <primitive object={scene} />;
};
import { Gltf } from '@react-three/drei';

<Gltf src="/models/character.glb" scale={2} position={[0, 0, 0]} />;

설명:

  • useGLTF: 로우 레벨 방식, scene, animations 등 세부 데이터 제어 가능
  • Gltf: 고수준 컴포넌트, props로 간단히 배치 가능

4. useAnimations – glTF 내장 애니메이션 제어

import { useGLTF, useAnimations } from '@react-three/drei';

const AnimatedModel = () => {
  const { scene, animations } = useGLTF('/models/walking.glb');
  const { actions } = useAnimations(animations, scene);

  useEffect(() => {
    actions['Walk']?.play();
  }, [actions]);

  return <primitive object={scene} />;
};

설명:

  • glTF에 포함된 애니메이션 이름을 알아야 사용 가능
  • actions[name].play()로 재생

5. Float – 오브젝트 부드러운 부유 애니메이션

import { Float } from '@react-three/drei';

<Float floatIntensity={1} speed={2}>
  <mesh>
    <sphereGeometry />
    <meshStandardMaterial color="hotpink" />
  </mesh>
</Float>

설명:

  • 상하좌우로 천천히 움직이는 float 효과 부여
  • UI 강조나 오브젝트의 “생동감” 표현에 좋음

6. PresentationControls – 오브젝트를 제한된 범위로 회전 가능하게

import { PresentationControls } from '@react-three/drei';

<PresentationControls
  global
  rotation={[0, 0.3, 0]}
  polar={[-0.5, 0.5]}
  azimuth={[-1, 1]}
  config={{ mass: 2, tension: 400 }}
  snap>
  <MyModel />
</PresentationControls>

설명:

  • 사용자가 마우스로 오브젝트를 회전해서 볼 수 있게 함
  • snap을 켜면 마우스 놓았을 때 위치 고정

7. Stage – 빠른 배치 + 조명 + 환경 설정 프리셋

import { Stage } from '@react-three/drei';

<Stage environment="city" intensity={1}>
  <MyModel />
</Stage>

설명:

  • 기본 조명, 바닥 그림자, HDRI 조명 등을 자동 설정
  • 빠르게 제품처럼 “쇼룸” 느낌을 줄 수 있음

 


 

3단계: 포스트 프로세싱 및 머티리얼 응용

목표: 시각적으로 완성도 높은 씬 구성과 커스텀 머티리얼 연출 능력 배양


3.1 특수 머티리얼 사용

핵심 목적: 반사, 왜곡, 레이어 표현 등을 통한 시각적 깊이 표현

  • [<MeshReflectorMaterial />]
    • 수면, 거울 같은 반사 구현
    • mirror, blur, mixBlur, depthScale 등의 속성 이해
  • [<MeshDistortMaterial />]
    • 메시 표면 왜곡 효과
    • distort, speed로 애니메이션 주기
  • [<LayerMaterial /> + <Depth />, <Fresnel />]
    • 레이어 기반 머티리얼 합성
    • 레이마칭 느낌의 표현 가능 (예: 유리/플라즈마 효과)

3.2 고급 렌더링 소스 활용

핵심 목적: 셰이더 및 후처리에 사용할 렌더링 정보를 확보

  • [useFBO()]
    • Framebuffer Object 사용
    • 화면을 오프스크린으로 렌더링하여 재사용 (ex: 반사, 피킹)
  • [useDepthBuffer()]
    • 씬의 깊이 버퍼 정보 접근
    • 그림자나 포스트 이펙트 연산에 활용
  • [useNormalTexture()]
    • 노멀 맵을 실시간으로 생성하거나 적용
    • 라이트와의 상호작용 강화

3.3 사용자 정의 셰이더

핵심 목적: 완전한 표현력 확보 및 자신만의 머티리얼 제작

  • [shaderMaterial()] + extend()
    • Drei에서 쉽게 GLSL 셰이더 정의 및 사용
    • vertexShader, fragmentShader, uniforms 직접 제어
  • [onBeforeCompile 방식과 비교 학습]
    • 기존 머티리얼 커스터마이징 vs 완전 셰이더 작성

3.4 그림자 최적화와 연출

핵심 목적: 퍼포먼스와 리얼리즘의 균형 있는 그림자 처리

  • [<BakeShadows />]
    • 씬 렌더 후 그림자를 Bake(굽기)해서 고정
    • 정적 씬에서 퍼포먼스 향상
  • [<ContactShadows />]
    • 바닥과 오브젝트 접점에만 그림자 생성 (AO 느낌)
    • lightweight + 자연스러운 효과
  • [<AccumulativeShadows /> + <RandomizedLight />]
    • 시간 누적 기반 부드러운 글로벌 그림자
    • soft shadow, ambient occlusion 효과 비슷

3단계 항목별로 시각적 결과를 상상할 수 있게 샘플 코드 + 설명


1. MeshReflectorMaterial: 반사 재질

import { MeshReflectorMaterial } from '@react-three/drei'

<mesh rotation={[-Math.PI / 2, 0, 0]} position={[0, -1, 0]}>
  <planeGeometry args={[10, 10]} />
  <MeshReflectorMaterial
    blur={[300, 100]} // [blur width, blur height]
    resolution={1024}
    mixBlur={1}       // 반사 블러 강도
    mixStrength={2}   // 반사 세기
    roughness={1}
    depthScale={1}
    minDepthThreshold={0.9}
    maxDepthThreshold={1}
    color="#333"
    metalness={0.5}
  />
</mesh>

결과 느낌:
카메라 아래 깔린 바닥에서 반사된 오브젝트 실루엣이 보임. 스튜디오 조명 바닥 느낌.


2. MeshDistortMaterial: 부드럽게 왜곡된 표면

import { MeshDistortMaterial } from '@react-three/drei'

<mesh>
  <sphereGeometry args={[1, 64, 64]} />
  <MeshDistortMaterial color="hotpink" distort={0.3} speed={2} />
</mesh>

결과 느낌:
물방울처럼 펄럭이고 일렁이는 구체. 조명과 함께 생동감 있는 시각 효과.


3. LayerMaterial: 계층별 머티리얼 효과

import { LayerMaterial, Depth, Noise } from 'lamina'

<mesh>
  <sphereGeometry args={[1, 64, 64]} />
  <LayerMaterial lighting="physical">
    <Depth colorA="skyblue" colorB="blue" alpha={1} mode="normal" near={0} far={2} origin={[1, 1, 1]} />
    <Noise mapping="local" type="simplex" scale={100} colorA="white" colorB="black" mode="softlight" alpha={0.5} />
  </LayerMaterial>
</mesh>

결과 느낌:
빛이 깊이에 따라 바뀌는 구체 위에 노이즈 텍스처가 겹침. 추상적이고 미래지향적 분위기.


4. useFBO: 프레임버퍼 오브젝트로 오프스크린 렌더링

import { useFBO } from '@react-three/drei'
import { useFrame, useThree } from '@react-three/fiber'
import { useRef } from 'react'

function FBOExample() {
  const fbo = useFBO()
  const { gl, scene, camera } = useThree()
  const meshRef = useRef()

  useFrame(() => {
    gl.setRenderTarget(fbo)
    gl.render(scene, camera)
    gl.setRenderTarget(null)
  })

  return (
    <mesh ref={meshRef}>
      <planeGeometry args={[2, 2]} />
      <meshBasicMaterial map={fbo.texture} />
    </mesh>
  )
}

결과 느낌:
화면에 렌더된 이미지를 텍스처로 활용 → 반사, 미러, 미니맵, 모니터 화면 등에 사용.


5. shaderMaterial: 직접 GLSL 셰이더 작성

import { shaderMaterial } from '@react-three/drei'
import glsl from 'babel-plugin-glsl/macro'

const MyMaterial = shaderMaterial(
  { uTime: 0 },
  glsl`void main() { gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); }`,
  glsl`uniform float uTime;
        void main() {
          gl_FragColor = vec4(abs(sin(uTime)), 0.2, 0.4, 1.0);
        }`
)

extend({ MyMaterial })

function CustomShader() {
  const ref = useRef()
  useFrame((_, delta) => {
    ref.current.uTime += delta
  })

  return (
    <mesh>
      <planeGeometry args={[2, 2]} />
      <myMaterial ref={ref} />
    </mesh>
  )
}

결과 느낌:
시간에 따라 색이 변화하는 평면, 완전히 사용자 정의된 머티리얼.


6. 그림자 최적화

6-1. BakeShadows

<BakeShadows />

결과 느낌:
정적인 그림자를 미리 계산하여 성능 향상. 애니메이션 없는 배경에서 유용.

6-2. ContactShadows

<ContactShadows
  position={[0, -1, 0]}
  opacity={0.5}
  scale={10}
  blur={1.5}
  far={10}
/>

결과 느낌:
오브젝트 밑에 부드러운 접촉 그림자, 현실감 증가.

6-3. AccumulativeShadows

<AccumulativeShadows temporal frames={100} color="purple" colorBlend={0.5}>
  <RandomizedLight amount={8} radius={4} ambient={0.5} position={[5, 5, 5]} />
</AccumulativeShadows>

결과 느낌:
여러 빛의 누적 효과로 실제 조명에 가까운 그림자. 부드럽고 생생함.


 

 

4단계: 포탈, 모듈화, 퍼포먼스 최적화

  • 복잡한 씬을 포탈처럼 분기 렌더링
  • UI/카메라 분리 구조 구현
  • 수천 개의 객체를 렌더링할 수 있도록 인스턴싱
  • GPU 사양에 따라 렌더링 품질 자동 조절

주요 컴포넌트 및 훅


1. <MeshPortalMaterial>

기능: 씬 내 일부 메시에서 다른 뷰(서브 씬)를 렌더링하는 포탈 시스템
활용 예:

  • 액자 안에서 다른 씬 보여주기
  • VR/AR의 창처럼 뷰 전환

핵심 학습 포인트

  • ref.blend를 이용한 부드러운 전환
  • events 속성으로 포인터 이벤트 전달 여부 제어

2. <View> & <RenderTexture>

기능: 하나의 캔버스에서 멀티 카메라, 멀티 씬 구성
활용 예:

  • 미니맵, CCTV 화면
  • HUD (Heads Up Display)
  • 보조 화면 (멀티 렌더링)

핵심 학습 포인트

  • <RenderTexture>로 별도 씬과 카메라를 정의
  • <View>를 특정 <div>에 연결하여 UI 내 분할 렌더링

3. <Instances> / <Merged> / <InstancedRigidBodies>

기능: 동일한 지오메트리/머티리얼을 공유하여 수백~수천 개 객체를 GPU 하나의 draw call로 처리

활용 예

  • 수천 개의 별, 나무, 돌
  • 리듬 게임 노트, 파티클 시스템

핵심 학습 포인트

  • <Instances>는 내부에서 THREE.InstancedMesh를 생성
  • <Merged>는 여러 메시를 병합하여 일괄 렌더링
  • <InstancedRigidBodies>는 Rapier와 함께 사용 시 물리 기반 인스턴싱 가능

4. <Preload> & useDetectGPU()

기능:

  • <Preload all />: Drei 내 비동기 리소스를 미리 로드
  • useDetectGPU(): 렌더링 전에 사용자의 GPU 성능을 평가

활용 예:

  • 고성능 GPU에는 반사 재질, 그림자 활성화
  • 저성능에서는 최적화된 경량 씬 로딩

핵심 학습 포인트

  • GPU 분류: 'high-performance', 'medium-performance', 'low-performance'
  • 조건부 구성 렌더링 (if (gpu.tier > 2) { ... })

실전 예제

  1. 포탈 갤러리 만들기
    • MeshPortalMaterial + Text + onDoubleClick으로 씬 전환
  2. RenderTexture 기반 CCTV
    • 메인 카메라로 렌더되지만 별도 <RenderTexture>로 미니뷰 구성
  3. Instanced Particles
    • <Instances>로 별이나 입자 수천 개 렌더링
  4. GPU 감지 후 조건 분기
    • useDetectGPU()로 저사양에서 그림자 비활성화

 

 

추가 기능: 시야 최적화 및 UI 보강

1. useAspect – 뷰포트 비율에 따라 오브젝트 크기 자동 조절

import { useAspect } from '@react-three/drei';

const scale = useAspect(1280, 720, 1); // width, height, scale factor
<mesh scale={scale}>
  <planeGeometry />
  <meshBasicMaterial color="white" />
</mesh>
  • 언제 사용?: 화면 크기에 따라 평면 UI 또는 배경 크기를 자동 조절할 때

2. useBounds – 자동으로 카메라 위치와 줌 조절

import { useBounds } from '@react-three/drei';

const bounds = useBounds();
return (
  <mesh
    onClick={(e) => {
      e.stopPropagation();
      bounds.refresh(e.object).fit(); // 카메라가 클릭된 오브젝트에 맞게 이동
    }}
  />
);
  • 언제 사용?: 특정 오브젝트 클릭 시 자동으로 카메라가 프레이밍되게 할 때

3. Center – 중앙 정렬

import { Center } from '@react-three/drei';

<Center>
  <Text fontSize={0.5}>Centered Text</Text>
</Center>
  • 언제 사용?: 씬의 중앙에 정확히 위치시키고 싶을 때 (폰트나 복잡한 메시 포함)

4. Billboard – 항상 카메라를 바라보게

import { Billboard } from '@react-three/drei';

<Billboard>
  <Text fontSize={0.2}>Always Facing Camera</Text>
</Billboard>
  • 언제 사용?: UI 텍스트, 안내 아이콘 등 카메라 시점과 항상 정렬해야 할 때

5. Html – DOM 요소와 Three.js 위치 동기화

import { Html } from '@react-three/drei';

<Html position={[0, 1.5, 0]}>
  <div style={{ background: 'white', padding: '0.5em' }}>설명 박스</div>
</Html>
  • 언제 사용?: 3D 씬 위에 HTML 툴팁, 버튼, 정보창을 띄우고 싶을 때

6. Backdrop + ContactShadows – 고급 배경 & 그림자 효과

import { Backdrop, ContactShadows } from '@react-three/drei';

<Backdrop floor={1.5} segments={20}>
  <meshStandardMaterial color="#f0f0f0" />
</Backdrop>

<ContactShadows position={[0, -1.5, 0]} opacity={0.4} blur={2.5} />
  • 언제 사용?: 부드러운 배경과 그림자를 통해 실감 나는 조명 연출을 할 때

'2D&3D > ThreeJS' 카테고리의 다른 글

Three.js Journey 03  (1) 2025.07.21
maath  (0) 2025.06.09
무료로 R3F 아바타 생성하기  (1) 2025.05.26
R3F(React Three Fiber)의 기본 요소와 기본 문법  (4) 2025.03.06
Three js 시작하기  (0) 2025.02.28