glTF 모델을 Three.js에 올리는 방식: 로더, 씬 그래프, 렌더 타이밍

Three.js에서 glTF를 로딩해 씬에 붙이는 기본 흐름과, 로딩 완료 시점에 '언제 렌더해야 하는지(render on demand)'까지 연결해서 설명한다.

Seobway · · 15분

왜 glTF가 기준 포맷인가

웹에서 3D 모델을 전달할 때 glTF는 사실상 표준에 가깝다.
Three.js도 공식 매뉴얼에서 glTF 로딩을 별도 글로 다룬다.[1]


로딩 전체 흐름

%% desc: GLTFLoader 비동기 로딩 파이프라인
flowchart TD
  Load["loader.load(url, onLoad, onProgress, onError)"]
  Net["네트워크 다운로드\n(.gltf / .glb / 텍스처)"]
  Parse["파싱 + GPU 업로드\n(메시·머티리얼·텍스처·애니메이션)"]
  Scene["gltf.scene\n(Object3D 트리)"]
  Add["scene.add(gltf.scene)"]
  Render["render() 호출\n(render on demand 구조라면 여기서 명시적으로)"]

  Load --> Net --> Parse --> Scene --> Add --> Render

  style Load   fill:#1e3a5f,color:#7dd3fc,stroke:#334155
  style Net    fill:#1c3a2b,color:#6ee7b7,stroke:#334155
  style Parse  fill:#3b1f5e,color:#c4b5fd,stroke:#334155
  style Scene  fill:#1e3a5f,color:#7dd3fc,stroke:#334155
  style Add    fill:#1c3a2b,color:#6ee7b7,stroke:#334155
  style Render fill:#4a1f1f,color:#fca5a5,stroke:#334155

1) 로딩의 결과는 "Mesh 하나"가 아니라 "Scene 그래프"다

glTF는 한 파일 안에 다음이 같이 들어갈 수 있다.

그래서 GLTFLoader가 주는 결과에서 실제로 많이 쓰는 건 gltf.scene이다.[1]


2) 기본 코드 패턴(load / loadAsync)

매뉴얼 기준 패턴은 다음과 같다.[1]

import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";

const loader = new GLTFLoader();

// 콜백 방식: load(url, onLoad, onProgress, onError)
loader.load(
  "path/to/model.gltf",
  (gltf) => {
    scene.add(gltf.scene);
    render(); // render on demand라면 명시적으로 한 번 호출
  },
  (xhr) => {
    console.log(`${((xhr.loaded / xhr.total) * 100).toFixed(1)}% loaded`);
  },
  (error) => {
    console.error("GLTFLoader error:", error);
  },
);

또는 loadAsync()를 쓰면 async/await로 정리할 수 있다.[1]

async function loadModel(url) {
  try {
    const gltf = await loader.loadAsync(url);
    scene.add(gltf.scene);
    render();
  } catch (err) {
    console.error("모델 로딩 실패:", err);
  }
}

3) Draco 압축 모델 사용 시

실무에서는 파일 크기를 줄이기 위해 Draco 압축을 쓰는 경우가 많다.
이때는 DRACOLoaderGLTFLoader에 연결해야 한다.

import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
import { DRACOLoader } from "three/addons/loaders/DRACOLoader.js";

const dracoLoader = new DRACOLoader();
// Draco 디코더 WASM을 제공하는 경로 (three.js examples/jsm/libs/draco/)
dracoLoader.setDecoderPath(
  "https://cdn.jsdelivr.net/npm/three@0.169.0/examples/jsm/libs/draco/",
);

const loader = new GLTFLoader();
loader.setDRACOLoader(dracoLoader);

4) "모델을 올렸는데 화면이 안 바뀌는" 이유

Three.js는 "렌더 함수가 호출되었을 때"만 화면이 갱신된다.

즉 모델 로딩이 끝나서 scene.add()를 해도,

이건 Three.js 매뉴얼의 "Rendering on Demand"가 말하는 핵심이다.[2]


5) 실전 최적화 연결 포인트

모델 로딩이 큰 프로젝트에서 "초반 버벅임/흰 화면"은 보통 다음과 연결된다.

그래서 "로딩 완료 → 첫 렌더 → 필요할 때만 렌더" 패턴이 UI 친화적이다.


참고

[1] Loading a .GLTF File — Three.js Manual

[2] Rendering on Demand — Three.js Manual


관련 글