🤖

본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.

⚠️

본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.

이미지 로딩 중...

Three.js 모델 불러오기 완벽 가이드 - 슬라이드 1/8
A

AI Generated

2025. 12. 29. · 2 Views

Three.js 모델 불러오기 완벽 가이드

Blender에서 만든 3D 모델을 웹 브라우저로 불러오는 방법을 배웁니다. GLTFLoader 사용법부터 텍스처 처리, 성능 최적화까지 실무에서 바로 쓸 수 있는 완전한 가이드입니다.


목차

  1. GLTFLoader 설치 및 사용법
  2. Blender 모델 웹으로 로드하기
  3. 모델 위치, 크기, 회전 조정
  4. 텍스처가 포함된 모델 처리
  5. 로딩 상태 관리 및 진행률 표시
  6. 모델 최적화 및 성능 개선
  7. 여러 모델 동시 로드 관리

1. GLTFLoader 설치 및 사용법

신입 개발자 김개발 씨는 회사에서 3D 제품 쇼룸 웹사이트를 만들라는 미션을 받았습니다. Blender로 만든 멋진 3D 모델 파일을 받았지만, 이걸 어떻게 웹에 띄워야 할지 막막했습니다.

선배 박시니어 씨가 다가와 말합니다. "Three.js의 GLTFLoader를 쓰면 되는데, 설치부터 해볼까요?"

GLTFLoader는 Three.js에서 GLTF 형식의 3D 모델을 불러오는 핵심 도구입니다. GLTF는 웹에 최적화된 3D 모델 포맷으로, Blender나 다른 3D 툴에서 내보낸 모델을 그대로 웹에서 사용할 수 있게 해줍니다.

마치 이미지 파일을 img 태그로 불러오듯이, 3D 모델을 웹에 불러올 수 있는 것입니다.

다음 코드를 살펴봅시다.

// npm으로 Three.js 설치
npm install three

// GLTFLoader 임포트
import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';

// 로더 인스턴스 생성
const loader = new GLTFLoader();

// 모델 로드
loader.load('models/myModel.glb', (gltf) => {
  // 로드 성공: 씬에 모델 추가
  scene.add(gltf.scene);
  console.log('모델 로드 완료!');
});

김개발 씨는 프론트엔드 개발 경력 6개월차입니다. HTML, CSS, JavaScript는 어느 정도 다룰 수 있지만 3D 웹 개발은 처음이었습니다.

"선배님, 3D 모델을 웹에 띄우는 게 가능하긴 한가요?" 박시니어 씨가 웃으며 답합니다. "요즘은 Three.js 덕분에 아주 쉬워졌어요." Three.js는 웹에서 3D 그래픽을 구현하는 가장 인기 있는 JavaScript 라이브러리입니다.

복잡한 WebGL 코드를 직접 작성하지 않아도 3D 씬을 만들 수 있게 해줍니다. 그중에서도 GLTFLoader는 외부에서 만든 3D 모델을 불러오는 핵심 도구입니다.

GLTF가 뭘까요? 쉽게 비유하자면, GLTF는 3D 모델계의 JPEG 같은 존재입니다.

JPEG가 이미지를 웹에서 효율적으로 보여주는 표준 포맷이듯이, GLTF는 3D 모델을 웹에서 효율적으로 보여주는 표준 포맷입니다. 파일 크기도 작고, 로딩 속도도 빠르며, 텍스처와 애니메이션까지 모두 포함할 수 있습니다.

GLTFLoader가 없던 시절에는 어땠을까요? 개발자들은 3D 모델의 정점 데이터, 면 데이터, 재질 정보를 일일이 파싱해야 했습니다.

각 3D 소프트웨어마다 내보내는 포맷이 달라서 변환 작업도 복잡했습니다. 더 큰 문제는 텍스처 이미지를 따로 관리해야 한다는 점이었습니다.

프로젝트가 커질수록 파일 관리가 악몽이 되었습니다. 바로 이런 문제를 해결하기 위해 GLTFLoader가 등장했습니다.

GLTFLoader를 사용하면 단 몇 줄의 코드로 복잡한 3D 모델을 불러올 수 있습니다. Blender에서 만든 모델이든, Maya에서 만든 모델이든, GLTF 포맷으로 내보내기만 하면 됩니다.

모델의 형태, 재질, 텍스처, 심지어 애니메이션까지 한 번에 불러올 수 있습니다. 설치 과정을 살펴보겠습니다.

먼저 npm을 통해 Three.js를 설치합니다. 프로젝트 폴더에서 터미널을 열고 npm install three 명령어를 실행하면 됩니다.

설치가 완료되면 package.json에 Three.js가 추가된 것을 확인할 수 있습니다. 다음으로 GLTFLoader를 임포트합니다.

여기서 주의할 점이 있습니다. GLTFLoader는 Three.js 코어가 아니라 examples 폴더에 들어있습니다.

따라서 three/examples/jsm/loaders/GLTFLoader.js 경로에서 임포트해야 합니다. 위의 코드를 한 줄씩 살펴보겠습니다.

첫 번째 줄은 Three.js 메인 라이브러리를 임포트합니다. 씬, 카메라, 렌더러 등 기본적인 Three.js 기능을 사용하기 위해 필요합니다.

두 번째 줄에서 GLTFLoader를 임포트합니다. 중괄호로 감싸는 이유는 named export이기 때문입니다.

new GLTFLoader()로 로더 인스턴스를 생성합니다. 이 로더는 여러 번 재사용할 수 있으므로 한 번만 만들어두면 됩니다.

loader.load() 메서드가 핵심입니다. 첫 번째 인자는 모델 파일의 경로입니다.

두 번째 인자는 콜백 함수인데, 모델 로드가 완료되면 실행됩니다. 콜백 함수의 gltf 파라미터에 불러온 모델 정보가 담겨 있습니다.

실제 현업에서는 어떻게 활용할까요? 예를 들어 가구 쇼핑몰을 만든다고 가정해봅시다.

디자이너가 Blender로 의자 3D 모델을 만들어 GLB 파일로 내보냅니다. 개발자는 GLTFLoader로 이 파일을 불러와 웹페이지에 표시합니다.

고객은 마우스로 의자를 360도 회전시키며 구석구석 살펴볼 수 있습니다. 이케아, 나이키 같은 글로벌 기업들이 이런 방식으로 제품을 보여주고 있습니다.

하지만 주의할 점도 있습니다. 초보 개발자들이 흔히 하는 실수 중 하나는 잘못된 경로를 지정하는 것입니다.

파일 경로는 public 폴더 기준의 상대 경로여야 합니다. 또한 GLB 파일과 GLTF 파일의 차이도 알아야 합니다.

GLB는 모든 리소스가 하나의 바이너리 파일에 포함되어 있고, GLTF는 JSON과 이미지 파일들로 분리되어 있습니다. 웹에서는 GLB를 사용하는 것이 더 편리합니다.

다시 김개발 씨의 이야기로 돌아가 봅시다. 박시니어 씨의 설명을 들은 김개발 씨는 노트북을 열고 코드를 작성하기 시작했습니다.

"생각보다 간단하네요!" Three.js를 설치하고 GLTFLoader를 임포트하는 데 5분도 걸리지 않았습니다. GLTFLoader의 기본 사용법을 익히면 3D 웹 개발의 첫 걸음을 뗀 것입니다.

이제 실제 모델을 불러와서 화면에 띄워볼 차례입니다.

실전 팁

💡 - GLB 포맷을 사용하면 파일 관리가 훨씬 쉽습니다

  • 로더 인스턴스는 재사용할 수 있으니 한 번만 생성하세요
  • 파일 경로는 브라우저 개발자 도구 Network 탭에서 확인 가능합니다

2. Blender 모델 웹으로 로드하기

김개발 씨는 디자이너로부터 chair.blend 파일을 받았습니다. "이걸 웹에 올려주세요!" 하지만 .blend 파일은 웹 브라우저가 읽을 수 없는 포맷입니다.

박시니어 씨가 말합니다. "Blender에서 GLTF로 내보내기를 해야 해요.

그 다음이 진짜 시작이죠."

Blender 모델을 웹에서 사용하려면 GLTF 포맷으로 내보내기를 해야 합니다. 내보낸 GLB 파일을 프로젝트에 추가하고, Three.js 씬을 구성한 후, GLTFLoader로 모델을 로드하여 화면에 표시하는 전체 과정이 필요합니다.

이 과정은 마치 요리 레시피를 따라가는 것처럼 단계별로 진행됩니다.

다음 코드를 살펴봅시다.

import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';

// 씬, 카메라, 렌더러 설정
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// 조명 추가
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(5, 5, 5);
scene.add(light);

// 카메라 위치 설정
camera.position.z = 5;

// 모델 로드 및 씬에 추가
const loader = new GLTFLoader();
loader.load('models/chair.glb', (gltf) => {
  scene.add(gltf.scene);
  console.log('의자 모델 로드 완료!');
}, undefined, (error) => {
  console.error('모델 로드 실패:', error);
});

// 렌더링 루프
function animate() {
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
}
animate();

김개발 씨가 디자이너 최디자인 씨의 책상 앞에 갔습니다. "이 의자 모델, 어떻게 웹용으로 변환하나요?" 최디자인 씨가 Blender를 열며 말합니다.

"간단해요. File 메뉴에서 Export, 그다음 glTF 2.0을 선택하면 돼요." Blender는 강력한 무료 3D 모델링 소프트웨어입니다.

전문 디자이너들이 제품, 캐릭터, 건물 등 온갖 종류의 3D 모델을 만드는 데 사용합니다. 하지만 Blender의 기본 파일 포맷인 .blend는 웹 브라우저가 이해할 수 없습니다.

GLTF 내보내기가 왜 필요할까요? 쉽게 비유하자면, Blender 파일은 포토샵 PSD 파일 같은 것입니다.

모든 레이어, 편집 이력, 원본 데이터가 들어있어서 용량이 크고 복잡합니다. 웹에서는 이런 무거운 파일을 사용할 수 없습니다.

마치 웹사이트에 PSD 대신 JPG를 올리듯이, 3D 모델도 웹 최적화된 포맷으로 변환해야 합니다. 변환 과정은 생각보다 간단합니다.

Blender를 열고 완성된 모델을 불러옵니다. 메뉴에서 File → Export → glTF 2.0을 선택합니다.

여기서 중요한 옵션이 나타나는데, Format 항목을 **glTF Binary (.glb)**로 선택해야 합니다. 이렇게 하면 모델과 텍스처가 하나의 파일로 합쳐져 관리가 편해집니다.

내보낸 GLB 파일을 프로젝트의 public/models 폴더에 넣습니다. 이제 본격적인 코딩이 시작됩니다.

위의 코드를 단계별로 살펴보겠습니다. 먼저 Three.js의 세 가지 핵심 요소를 만듭니다.

Scene은 3D 세계 자체입니다. 모든 3D 객체가 이 씬 안에 배치됩니다.

Camera는 이 3D 세계를 보는 관점입니다. PerspectiveCamera는 사람 눈처럼 원근감을 표현합니다.

Renderer는 씬과 카메라 정보를 받아서 실제 화면에 그립니다. antialias: true 옵션은 계단 현상을 방지해 더 부드러운 이미지를 만듭니다.

renderer.setSize()로 캔버스 크기를 브라우저 창 크기에 맞춥니다. document.body.appendChild()로 캔버스를 HTML에 추가합니다.

조명이 없으면 모델이 보이지 않습니다. 이것은 초보자들이 가장 자주 겪는 문제입니다.

3D 세계도 현실처럼 빛이 있어야 물체가 보입니다. DirectionalLight는 태양광처럼 한 방향에서 비추는 조명입니다.

position.set(5, 5, 5)로 위치를 설정하고 scene.add()로 씬에 추가합니다. 카메라 위치도 중요합니다.

기본적으로 카메라는 원점(0, 0, 0)에 있는데, 모델도 원점에 로드되므로 카메라를 뒤로 빼야 모델이 보입니다. camera.position.z = 5로 카메라를 z축으로 5만큼 뒤로 이동시킵니다.

이제 모델을 로드합니다. loader.load()의 두 번째 파라미터는 성공 콜백입니다.

모델 로드가 완료되면 gltf 객체가 전달됩니다. gltf.scene에 실제 3D 모델이 들어있으며, 이것을 씬에 추가하면 됩니다.

세 번째 파라미터는 로딩 진행률 콜백인데 나중에 자세히 다룹니다. 네 번째 파라미터는 에러 콜백으로, 파일을 찾을 수 없거나 형식이 잘못됐을 때 실행됩니다.

렌더링 루프가 마지막 퍼즐 조각입니다. animate() 함수는 브라우저가 다시 그릴 준비가 될 때마다 자동으로 호출됩니다.

보통 초당 60번 호출되어 부드러운 애니메이션을 만듭니다. renderer.render(scene, camera)가 실제로 화면에 그리는 명령입니다.

실제 현업에서는 어떻게 활용할까요? 패션 브랜드 웹사이트를 만든다고 가정해봅시다.

디자이너가 Blender로 신발 모델을 만들고 GLB로 내보냅니다. 개발자는 위의 코드로 신발을 웹에 띄웁니다.

고객은 제품 페이지에서 3D 신발을 돌려가며 디테일을 확인할 수 있습니다. 이는 단순 이미지보다 훨씬 높은 구매 전환율을 보여줍니다.

하지만 주의할 점도 있습니다. 모델 파일 경로를 잘못 지정하면 콘솔에 404 에러가 뜹니다.

public 폴더에 파일이 있는지, 파일명 대소문자가 정확한지 확인해야 합니다. 또한 Blender에서 내보낼 때 스케일을 확인해야 합니다.

모델이 너무 크거나 작으면 카메라 시야에 제대로 들어오지 않을 수 있습니다. 김개발 씨가 코드를 실행했습니다.

브라우저 창에 3D 의자가 나타났습니다! "와, 진짜 됐어요!" 박시니어 씨가 웃으며 답합니다.

"이제 시작이에요. 이 의자를 회전시키고, 크기를 조절하고, 예쁘게 꾸며야죠." Blender 모델을 웹에 성공적으로 로드했다면, 이제 본격적으로 3D 웹 개발을 시작할 준비가 된 것입니다.

실전 팁

💡 - Blender에서 내보낼 때 glTF Binary 포맷을 선택하세요

  • 조명을 추가하지 않으면 모델이 검게 보이니 주의하세요
  • 에러 콜백을 꼭 작성해서 문제를 빠르게 파악하세요

3. 모델 위치, 크기, 회전 조정

모델을 불러오는 데는 성공했지만, 의자가 화면을 꽉 채우고 있었습니다. 너무 크고, 각도도 이상했습니다.

김개발 씨가 당황하자 박시니어 씨가 말합니다. "모델의 position, scale, rotation을 조정해야 해요.

Three.js에서 가장 기본적인 변형 작업이죠."

3D 모델의 위치(position), 크기(scale), **회전(rotation)**은 Three.js 객체의 기본 속성입니다. 이 세 가지를 조절하면 모델을 원하는 곳에, 원하는 크기로, 원하는 각도로 배치할 수 있습니다.

마치 무대 위에서 소품을 배치하듯이 3D 공간에서 모델을 자유롭게 다룰 수 있습니다.

다음 코드를 살펴봅시다.

loader.load('models/chair.glb', (gltf) => {
  const model = gltf.scene;

  // 위치 조정: x, y, z 좌표
  model.position.set(0, -1, 0);  // y축으로 1만큼 아래로 이동

  // 크기 조정: 균등 스케일링
  model.scale.set(0.5, 0.5, 0.5);  // 절반 크기로 축소

  // 회전 조정: 라디안 단위
  model.rotation.y = Math.PI / 4;  // y축 기준 45도 회전

  scene.add(model);

  // 모델의 경계 박스 확인
  const box = new THREE.Box3().setFromObject(model);
  console.log('모델 크기:', box.getSize(new THREE.Vector3()));
});

김개발 씨의 화면에 의자가 나타났지만 뭔가 이상했습니다. 의자가 너무 커서 등받이만 보였고, 옆으로 누워있는 것처럼 보였습니다.

"왜 이렇게 나오는 거죠?" 박시니어 씨가 설명합니다. "Blender와 Three.js의 좌표계가 다르고, 모델마다 기본 크기도 다르거든요." 3D 공간에는 세 개의 축이 있습니다.

x축은 좌우, y축은 상하, z축은 앞뒤를 나타냅니다. 쉽게 비유하자면, x축은 방의 너비, y축은 방의 높이, z축은 방의 깊이입니다.

모델을 움직이려면 이 세 축 중 하나 이상의 값을 바꾸면 됩니다. position이 가장 직관적인 속성입니다.

model.position.set(x, y, z) 형태로 사용합니다. 예를 들어 set(2, 0, 0)은 모델을 오른쪽으로 2만큼 이동시킵니다.

set(0, 3, 0)은 위로 3만큼 올립니다. set(0, 0, -5)는 카메라에서 멀어지게 합니다.

숫자는 Three.js의 기본 단위인 유닛을 나타내는데, 보통 1유닛을 1미터로 생각하면 됩니다. 많은 모델이 바닥에 걸쳐있는 문제가 있습니다.

Blender에서 모델을 만들 때 중심점이 바닥에 있는 경우가 많습니다. 이러면 Three.js에서 불러왔을 때 모델의 절반이 y = 0 평면 아래에 묻혀버립니다.

이럴 때는 position.y를 양수로 설정해서 모델을 들어올려야 합니다. scale은 모델의 크기를 조절합니다.

model.scale.set(x, y, z) 형태로 각 축마다 다른 배율을 적용할 수 있습니다. 하지만 대부분의 경우 set(0.5, 0.5, 0.5)처럼 세 값을 같게 해서 균등하게 축소하거나 확대합니다.

1보다 크면 확대, 1보다 작으면 축소입니다. 예를 들어 2는 두 배 크기, 0.5는 절반 크기입니다.

모델이 너무 크거나 작은 이유는 뭘까요? Blender에서 실제 크기로 모델링했을 수도 있습니다.

자동차 모델이라면 길이가 4유닛(4미터) 정도일 것입니다. 하지만 Three.js 씬의 카메라 거리는 보통 5~10유닛 정도이므로 자동차가 화면을 꽉 채울 수 있습니다.

이럴 때는 스케일을 0.1이나 0.2로 줄여야 합니다. rotation은 모델을 회전시킵니다.

model.rotation.x, .y, .z 각각이 해당 축을 기준으로 한 회전을 나타냅니다. 중요한 점은 라디안 단위를 사용한다는 것입니다.

360도가 2 * Math.PI 라디안이므로, 90도는 Math.PI / 2, 45도는 Math.PI / 4입니다. 실제 예를 들어보겠습니다.

의자가 옆으로 누워있다면 model.rotation.x = -Math.PI / 2로 x축 기준 -90도 회전시킵니다. 의자를 정면이 아닌 살짝 비스듬하게 보여주고 싶다면 model.rotation.y = Math.PI / 6 (30도)으로 설정합니다.

이렇게 하면 의자의 측면도 살짝 보여서 더 입체적으로 보입니다. Box3를 사용하면 모델의 실제 크기를 알 수 있습니다.

new THREE.Box3().setFromObject(model)은 모델을 완전히 감싸는 경계 박스를 계산합니다. getSize()를 호출하면 박스의 너비, 높이, 깊이를 Vector3 형태로 받을 수 있습니다.

이 정보로 모델이 얼마나 큰지 파악하고 적절한 스케일을 결정할 수 있습니다. 실제 현업에서는 어떻게 활용할까요?

전자제품 쇼핑몰을 개발한다고 가정해봅시다. 스마트폰, 노트북, 이어폰 등 크기가 제각각인 제품들을 3D로 보여줍니다.

각 제품마다 적절한 스케일과 회전을 적용해서 화면에 보기 좋게 배치합니다. 스마트폰은 정면에서 살짝 기울여서 보여주고, 이어폰은 크게 확대해서 디테일을 강조합니다.

주의할 점도 있습니다. rotation의 순서가 중요합니다.

model.rotation.x를 먼저 바꾸고 .y를 바꾸는 것과, 순서를 바꿔서 하는 것이 다른 결과를 만들 수 있습니다. 이를 짐벌 락(Gimbal Lock) 문제라고 하는데, 복잡한 회전이 필요하면 Quaternion을 사용하는 것이 좋습니다.

하지만 대부분의 경우 간단한 rotation 값으로 충분합니다. 김개발 씨가 코드를 수정했습니다.

스케일을 0.8로 줄이고, y 위치를 -0.5로 내리고, y축으로 살짝 회전시켰습니다. 이제 의자가 화면 중앙에 딱 맞게 나타났습니다!

"이제 제대로 보이네요!" 박시니어 씨가 고개를 끄덕입니다. "position, scale, rotation은 3D 개발의 기본 중의 기본이에요.

손에 익을 때까지 연습해보세요." 이 세 가지 변형 속성을 자유자재로 다룰 수 있게 되면, 어떤 모델이든 원하는 대로 배치할 수 있습니다.

실전 팁

💡 - 라디안 변환이 헷갈리면 THREE.MathUtils.degToRad(45) 함수를 사용하세요

  • 모델 크기를 모를 때는 Box3로 경계 박스를 확인하세요
  • 애니메이션으로 회전시키려면 animate 함수에서 rotation 값을 계속 증가시키면 됩니다

4. 텍스처가 포함된 모델 처리

다음날, 김개발 씨는 새로운 모델을 받았습니다. 로드는 성공했지만 모델이 하얗게만 보였습니다.

"텍스처가 안 보여요!" 박시니어 씨가 파일 구조를 확인하더니 말합니다. "텍스처 이미지 경로 문제네요.

GLB 파일은 텍스처를 포함하지만, 상대 경로가 꼬이면 이런 일이 생겨요."

텍스처는 3D 모델 표면에 입히는 이미지입니다. 나무 결, 천 재질, 금속 반사 등을 표현합니다.

GLB 파일은 텍스처를 내장하지만, 때로는 외부 이미지를 참조하기도 합니다. TextureLoader와 적절한 파일 구조로 텍스처가 제대로 로드되도록 해야 합니다.

다음 코드를 살펴봅시다.

import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';

const loader = new GLTFLoader();

loader.load('models/sofa.glb', (gltf) => {
  const model = gltf.scene;

  // 모델의 모든 메쉬를 순회하며 재질 확인
  model.traverse((child) => {
    if (child.isMesh) {
      // 재질이 있으면 텍스처 정보 출력
      console.log('메쉬:', child.name);
      console.log('재질:', child.material);

      // 텍스처가 있는 경우
      if (child.material.map) {
        console.log('텍스처 있음:', child.material.map);
        // 텍스처 필터링 설정으로 품질 향상
        child.material.map.anisotropy = renderer.capabilities.getMaxAnisotropy();
      }
    }
  });

  scene.add(model);
}, undefined, (error) => {
  console.error('로드 실패:', error);
});

김개발 씨가 새로운 소파 모델을 불러왔습니다. 3D 형태는 제대로 나타났지만, 천 재질의 질감이 전혀 보이지 않았습니다.

그냥 하얀 플라스틱 덩어리처럼 보였습니다. "이상한데요?

Blender에서는 천 질감이 보였는데..." 박시니어 씨가 코드를 살펴봅니다. "텍스처 파일이 제대로 로드됐는지 확인해봐야겠어요." 텍스처란 무엇일까요?

쉽게 비유하자면, 텍스처는 3D 모델에 입히는 포장지 같은 것입니다. 선물 상자의 모양은 3D 형태이고, 그 위에 붙이는 예쁜 포장지가 텍스처입니다.

나무 모델에는 나무 결 이미지를, 벽돌 모델에는 벽돌 패턴 이미지를 입혀서 사실적으로 만듭니다. 3D 모델에는 여러 종류의 텍스처가 있습니다.

Color Map(또는 Diffuse Map)은 기본 색상 정보를 담고 있습니다. Normal Map은 표면의 미세한 요철을 표현합니다.

Roughness Map은 표면이 얼마나 거친지를 나타냅니다. Metallic Map은 금속성을 표현합니다.

고품질 모델은 이런 텍스처들을 여러 장 사용합니다. GLB 파일과 GLTF 파일의 차이가 여기서 중요해집니다.

GLB는 바이너리 포맷으로 모든 텍스처 이미지를 파일 안에 포함합니다. 하나의 파일만 관리하면 되므로 편리합니다.

반면 GLTF는 JSON 파일과 별도의 이미지 파일들로 구성됩니다. 만약 이미지 파일 경로가 잘못되면 텍스처가 로드되지 않습니다.

위의 코드에서 traverse 메서드가 핵심입니다. GLTF 모델은 여러 개의 메쉬로 구성될 수 있습니다.

소파 모델이라면 쿠션, 다리, 프레임이 각각 다른 메쉬일 수 있습니다. traverse()는 모델의 모든 자식 객체를 하나씩 방문합니다.

child.isMesh로 메쉬인지 확인하고, 메쉬라면 재질 정보를 살펴봅니다. child.material에 재질 정보가 들어있습니다.

Three.js의 재질은 MeshStandardMaterial, MeshBasicMaterial 등 여러 종류가 있습니다. material.map이 Color Map 텍스처입니다.

이 값이 null이면 텍스처가 없는 것이고, 값이 있으면 Texture 객체가 들어있습니다. anisotropy는 텍스처 품질을 높이는 중요한 설정입니다.

텍스처를 비스듬한 각도에서 보면 뿌옇게 흐려질 수 있습니다. 이를 방지하는 것이 **이방성 필터링(Anisotropic Filtering)**입니다.

renderer.capabilities.getMaxAnisotropy()는 GPU가 지원하는 최대 값을 반환합니다. 보통 16 정도의 값이 나오는데, 이를 설정하면 텍스처가 훨씬 선명해집니다.

텍스처가 로드되지 않는 흔한 원인들이 있습니다. 첫째, 파일 경로 문제입니다.

GLTF 파일이 이미지를 상대 경로로 참조하는데, 이미지 파일이 그 위치에 없으면 404 에러가 발생합니다. 둘째, CORS 문제입니다.

로컬 파일 시스템에서 개발할 때는 문제없지만, 웹 서버를 거치면 CORS 에러가 날 수 있습니다. 셋째, Blender에서 내보낼 때 텍스처를 포함하지 않았을 수 있습니다.

Blender에서 제대로 내보내는 방법이 있습니다. Export 옵션에서 Include > Textures 체크박스를 켜야 합니다.

Format은 **glTF Binary (.glb)**를 선택하면 텍스처가 자동으로 포함됩니다. 또한 Compression을 활성화하면 파일 크기를 줄일 수 있습니다.

실제 현업에서는 어떻게 활용할까요? 인테리어 쇼핑몰에서 가구를 3D로 보여준다고 가정해봅시다.

소파의 천 재질, 나무 다리의 결, 금속 부품의 반짝임이 모두 텍스처로 표현됩니다. 고객은 실제 제품과 거의 비슷한 느낌을 웹에서 받을 수 있습니다.

이는 반품률을 크게 낮추고 고객 만족도를 높입니다. 주의할 점도 있습니다.

텍스처 이미지가 너무 크면 로딩이 느려집니다. 4K 텍스처(4096x4096)는 파일 크기가 수 MB에 달할 수 있습니다.

웹에서는 보통 1K나 2K 정도로 줄이는 것이 좋습니다. 또한 JPG로 압축하면 크기를 더 줄일 수 있지만, 투명도가 필요하면 PNG를 써야 합니다.

김개발 씨가 콘솔을 확인했습니다. "아, 여기 텍스처가 있네요!" material.map에 Texture 객체가 들어있었습니다.

anisotropy를 설정하자 소파의 천 질감이 훨씬 선명해졌습니다. "이제 진짜 소파 같아요!" 박시니어 씨가 미소 짓습니다.

"텍스처가 3D 모델에 생명을 불어넣죠." 텍스처를 제대로 다루면 단순한 3D 형태가 살아있는 듯한 사실적인 객체로 변합니다.

실전 팁

💡 - GLB 포맷을 사용하면 텍스처 관리가 훨씬 쉽습니다

  • anisotropy 설정으로 텍스처 품질을 크게 개선할 수 있습니다
  • 브라우저 개발자 도구 Network 탭에서 텍스처 파일 로딩을 확인하세요

5. 로딩 상태 관리 및 진행률 표시

김개발 씨가 10MB짜리 큰 모델을 로드했습니다. 화면이 몇 초간 멈춘 것처럼 보이다가 갑자기 모델이 나타났습니다.

"사용자가 기다리는 동안 로딩 표시를 보여줘야 할 것 같은데요?" 박시니어 씨가 답합니다. "GLTFLoader의 세 번째 콜백이 바로 그걸 위한 거예요."

큰 3D 모델은 로딩에 시간이 걸립니다. 로딩 진행률 콜백을 사용하면 몇 퍼센트 로드됐는지 알 수 있고, 사용자에게 프로그레스 바를 보여줄 수 있습니다.

이는 사용자 경험을 크게 개선하며, 사용자가 기다리는 동안 이탈하는 것을 방지합니다.

다음 코드를 살펴봅시다.

const loader = new GLTFLoader();

// 로딩 상태를 보여줄 HTML 요소 (미리 만들어둔다고 가정)
const loadingDiv = document.getElementById('loading');
const progressBar = document.getElementById('progress-bar');
const progressText = document.getElementById('progress-text');

loader.load(
  'models/large-model.glb',
  // 로드 완료 콜백
  (gltf) => {
    scene.add(gltf.scene);
    loadingDiv.style.display = 'none';  // 로딩 UI 숨김
    console.log('로드 완료!');
  },
  // 진행률 콜백
  (progress) => {
    const percentComplete = (progress.loaded / progress.total) * 100;
    progressBar.style.width = percentComplete + '%';
    progressText.textContent = Math.round(percentComplete) + '%';
    console.log(`로딩 중: ${percentComplete.toFixed(1)}%`);
  },
  // 에러 콜백
  (error) => {
    loadingDiv.innerHTML = '<p>모델 로드 실패</p>';
    console.error(error);
  }
);

김개발 씨의 회사는 고품질 3D 제품 카탈로그를 만들고 있었습니다. 디자이너가 만든 모델들은 디테일이 뛰어났지만, 파일 크기가 5MB에서 20MB에 달했습니다.

모바일 환경에서 테스트하니 로딩에 10초 이상 걸렸습니다. "사용자들이 기다리다 나가버릴 거예요." 박시니어 씨가 말합니다.

"진행률 표시를 추가해야 해요." 로딩 UI가 왜 중요할까요? 쉽게 비유하자면, 로딩 표시는 엘리베이터의 층수 표시와 같습니다.

엘리베이터를 탔는데 아무 표시도 없으면 불안합니다. 하지만 층수가 올라가는 게 보이면 안심하고 기다릴 수 있습니다.

웹사이트도 마찬가지입니다. 진행률을 보여주면 사용자가 인내심을 갖고 기다립니다.

연구 결과에 따르면 사용자는 3초 이상 기다리면 이탈하기 시작합니다. 하지만 로딩 표시가 있으면 10초도 기꺼이 기다립니다.

특히 진행률이 계속 올라가는 걸 보면 "곧 완료되겠구나"라고 느끼기 때문입니다. 이것이 UX 디자인의 중요한 원칙입니다.

GLTFLoader의 세 가지 콜백을 모두 활용해야 합니다. 첫 번째는 우리가 계속 사용해온 성공 콜백입니다.

두 번째는 진행률 콜백으로, 로딩 중에 반복적으로 호출됩니다. 세 번째는 에러 콜백으로, 실패 시 호출됩니다.

세 가지를 모두 처리해야 완전한 로딩 시스템이 됩니다. 진행률 콜백의 progress 객체를 살펴보겠습니다.

progress.loaded는 현재까지 다운로드한 바이트 수입니다. progress.total은 전체 파일 크기입니다.

두 값을 나누면 0에서 1 사이의 비율이 나옵니다. 100을 곱하면 퍼센트가 됩니다.

예를 들어 5MB 파일의 2.5MB를 다운로드했다면 50%입니다. 프로그레스 바는 CSS와 JavaScript로 간단히 만들 수 있습니다.

HTML에 <div id="progress-bar">를 만들고, CSS로 배경색과 높이를 설정합니다. JavaScript에서 style.width를 퍼센트로 설정하면 막대가 채워집니다.

예를 들어 30% 로드됐다면 progressBar.style.width = '30%'로 설정합니다. toFixed(1)은 소수점 첫째 자리까지 표시합니다.

percentComplete가 45.678이라면 toFixed(1)은 "45.7"을 반환합니다. 사용자에게는 정수 퍼센트만 보여주는 것이 일반적이므로 Math.round()를 사용하기도 합니다.

이러면 46%로 표시됩니다. 로드 완료 후 UI를 정리하는 것도 중요합니다.

모델 로드가 완료되면 loadingDiv.style.display = 'none'으로 로딩 UI를 숨깁니다. 또는 페이드 아웃 애니메이션을 추가해서 부드럽게 사라지게 할 수도 있습니다.

사용자는 로딩이 끝났음을 시각적으로 확인하고 3D 모델과 상호작용할 수 있습니다. 에러 처리도 빼먹으면 안 됩니다.

네트워크가 끊기거나, 파일이 없거나, 파일 형식이 잘못됐을 때 에러 콜백이 호출됩니다. 사용자에게 "모델을 불러올 수 없습니다"같은 친절한 메시지를 보여줘야 합니다.

개발자 콘솔에는 상세한 에러를 출력해서 디버깅할 수 있게 합니다. 실제 현업에서는 어떻게 활용할까요?

자동차 제조사 웹사이트를 만든다고 가정해봅시다. 신차 모델은 디테일이 매우 높아 파일 크기가 큽니다.

사용자가 모델을 선택하면 화면 중앙에 세련된 프로그레스 바가 나타납니다. "3D 모델 로딩 중...

78%"라는 메시지와 함께 막대가 채워집니다. 로드가 완료되면 멋진 페이드 인 효과와 함께 차가 등장합니다.

주의할 점도 있습니다. 브라우저 캐시에 파일이 이미 있으면 진행률 콜백이 호출되지 않을 수 있습니다.

순식간에 로드되기 때문입니다. 이럴 때는 로딩 UI가 잠깐 깜빡이는 것을 방지하기 위해 최소 표시 시간을 설정하기도 합니다.

또한 progress.total이 0인 경우도 있는데, 서버가 Content-Length 헤더를 보내지 않을 때 발생합니다. 김개발 씨가 코드를 추가했습니다.

프로그레스 바가 0%에서 시작해 천천히 100%까지 채워졌습니다. 모델이 나타나자 로딩 UI가 부드럽게 사라졌습니다.

"훨씬 전문적으로 보이네요!" 박시니어 씨가 엄지를 치켜세웁니다. "사용자 경험이 정말 중요해요." 로딩 상태를 제대로 관리하면 사용자는 기다리는 시간을 훨씬 긍정적으로 느낍니다.

실전 팁

💡 - 프로그레스 바에 퍼센트 숫자도 함께 표시하면 더 명확합니다

  • 로딩 중에 브랜드 로고나 팁 메시지를 보여주면 지루함을 덜 수 있습니다
  • 캐시된 파일은 즉시 로드되므로 최소 표시 시간을 고려하세요

6. 모델 최적화 및 성능 개선

모바일에서 테스트하던 김개발 씨가 당황했습니다. 프레임이 뚝뚝 끊기며 화면이 버벅거렸습니다.

개발자 도구를 보니 FPS가 15 정도밖에 나오지 않았습니다. "이 모델, 너무 무거운 것 같은데요..." 박시니어 씨가 모델을 분석하더니 말합니다.

"정점이 50만 개나 되네요. 최적화가 필요해요."

3D 모델 최적화는 정점 수 줄이기, 텍스처 압축, LOD(Level of Detail) 사용 등을 포함합니다. 불필요한 디테일을 제거하고, 효율적인 렌더링 설정을 적용하면 모바일에서도 부드러운 60 FPS를 달성할 수 있습니다.

성능은 3D 웹 개발의 핵심입니다.

다음 코드를 살펴봅시다.

import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';

// Draco 압축 해제 로더 설정
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath('https://www.gstatic.com/draco/v1/decoders/');

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

loader.load('models/optimized-model.glb', (gltf) => {
  const model = gltf.scene;

  model.traverse((child) => {
    if (child.isMesh) {
      // 그림자 최적화: 필요한 경우에만
      child.castShadow = true;
      child.receiveShadow = true;

      // Frustum Culling: 화면 밖 객체 렌더링 안 함 (기본 활성화)
      child.frustumCulled = true;

      // 재질 최적화
      if (child.material) {
        child.material.needsUpdate = true;
      }
    }
  });

  scene.add(model);
});

// 렌더러 최적화 설정
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));  // 최대 2배까지만
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;  // 부드러운 그림자

김개발 씨의 노트북에서는 모델이 부드럽게 돌아갔지만, 아이폰에서는 버벅거렸습니다. 회사 마케팅팀에서 불만을 제기했습니다.

"고객 대부분이 모바일로 접속하는데, 이렇게 느리면 안 돼요." 김개발 씨는 밤을 새워 성능 최적화를 공부하기 시작했습니다. 3D 성능의 핵심은 GPU가 처리해야 할 데이터를 줄이는 것입니다.

쉽게 비유하자면, GPU는 요리사이고 정점 데이터는 재료입니다. 재료가 너무 많으면 요리사가 아무리 빨라도 요리가 느려집니다.

정점 수를 줄이고, 텍스처 크기를 줄이고, 불필요한 연산을 제거하면 GPU가 훨씬 빠르게 일할 수 있습니다. Draco 압축이 첫 번째 무기입니다.

Draco는 Google이 만든 3D 메쉬 압축 라이브러리입니다. 정점 데이터를 압축해서 파일 크기를 70~80% 줄일 수 있습니다.

10MB 모델이 2~3MB로 줄어듭니다. Blender에서 GLTF를 내보낼 때 Draco 압축 옵션을 켜면 됩니다.

DRACOLoader를 설정하는 과정을 살펴보겠습니다. 먼저 new DRACOLoader()로 인스턴스를 만듭니다.

setDecoderPath()로 Draco 디코더 파일의 위치를 지정합니다. Google CDN을 사용하면 별도로 파일을 관리할 필요가 없습니다.

마지막으로 loader.setDRACOLoader(dracoLoader)로 GLTFLoader에 연결합니다. 정점 수를 줄이는 것도 중요합니다.

Blender에서 Decimate Modifier를 사용하면 정점 수를 줄일 수 있습니다. 예를 들어 Ratio를 0.5로 설정하면 정점이 절반으로 줄어듭니다.

멀리서 보는 객체는 디테일이 덜 필요하므로 과감하게 줄여도 됩니다. 50만 정점을 10만 정점으로 줄이면 렌더링 속도가 5배 빨라질 수 있습니다.

Frustum Culling은 Three.js가 자동으로 해줍니다. 카메라 시야에 보이지 않는 객체는 렌더링하지 않는 기술입니다.

frustumCulled는 기본적으로 true이지만, 명시적으로 설정해주면 안심입니다. 거대한 씬에서 수백 개의 객체가 있을 때 이 기능이 성능을 크게 좌우합니다.

그림자는 성능을 많이 잡아먹습니다. castShadowreceiveShadow를 켜면 사실적이지만 렌더링 부담이 큽니다.

모든 객체에 그림자를 적용하지 말고, 중요한 객체에만 적용하세요. 예를 들어 주요 제품에는 그림자를 켜지만, 배경 소품에는 끄는 식입니다.

픽셀 비율 설정이 의외로 중요합니다. Retina 디스플레이는 window.devicePixelRatio가 2나 3입니다.

이대로 렌더링하면 픽셀 수가 4배~9배 증가해 성능이 급격히 떨어집니다. Math.min(window.devicePixelRatio, 2)로 최대 2배까지만 허용하면 품질은 충분히 좋으면서 성능도 확보됩니다.

텍스처 크기도 줄여야 합니다. 4K 텍스처(4096x4096)는 모바일에서 과합니다.

1K나 2K로 줄이고, JPG로 압축하면 파일 크기가 크게 줄어듭니다. 또한 밉맵을 활용하면 멀리 있는 객체는 저해상도 텍스처를 사용해 성능을 높일 수 있습니다.

LOD(Level of Detail)는 고급 기술입니다. 멀리 있을 때는 저해상도 모델을, 가까이 있을 때는 고해상도 모델을 보여주는 방법입니다.

Three.js의 LOD 클래스를 사용하면 거리에 따라 자동으로 모델을 교체합니다. 예를 들어 나무를 100개 렌더링할 때, 가까운 나무는 1만 정점, 먼 나무는 100 정점으로 표현합니다.

실제 현업에서는 어떻게 활용할까요? 대규모 건축 시각화 웹사이트를 만든다고 가정해봅시다.

건물 외관은 고품질 모델을 사용하지만, 주변 나무와 자동차는 최적화된 저폴리곤 모델을 사용합니다. Draco 압축으로 전체 씬의 크기를 50MB에서 10MB로 줄입니다.

결과적으로 데스크톱에서 60 FPS, 모바일에서 30 FPS 이상을 달성합니다. 주의할 점도 있습니다.

과도한 최적화는 품질을 해칠 수 있습니다. 정점을 너무 줄이면 모델이 각져 보입니다.

텍스처를 너무 압축하면 흐릿해집니다. 품질과 성능 사이의 균형을 찾아야 합니다.

타겟 디바이스에서 테스트하며 적절한 지점을 찾으세요. 김개발 씨가 모든 최적화를 적용했습니다.

파일 크기는 15MB에서 4MB로 줄었고, 모바일에서 FPS가 45까지 올라갔습니다. "이제 훨씬 부드럽네요!" 마케팅팀도 만족했습니다.

박시니어 씨가 말합니다. "최적화는 한 번에 끝나는 게 아니에요.

계속 모니터링하고 개선해야 해요." 성능 최적화는 3D 웹 개발의 필수 스킬입니다. 사용자 대부분이 모바일을 사용하는 시대에 더욱 중요합니다.

실전 팁

💡 - Chrome DevTools의 Performance 탭으로 렌더링 병목을 찾으세요

  • Stats.js 라이브러리로 실시간 FPS를 모니터링하세요
  • Blender에서 내보낼 때 Draco 압축을 꼭 활성화하세요

7. 여러 모델 동시 로드 관리

김개발 씨는 제품 비교 페이지를 만들어야 했습니다. 세 개의 의자 모델을 동시에 화면에 띄워야 했습니다.

하나씩 로드하니 시간이 너무 오래 걸렸습니다. "병렬로 로드할 수 있을까요?" 박시니어 씨가 답합니다.

"LoadingManager와 Promise를 활용하면 돼요."

여러 모델을 동시에 로드하려면 LoadingManager로 전체 진행률을 추적하고, Promise.all로 모든 로드 완료를 기다립니다. 각 모델을 다른 위치에 배치하고, 전체 로딩이 끝나면 사용자에게 보여주는 방식으로 깔끔한 경험을 제공할 수 있습니다.

다음 코드를 살펴봅시다.

import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';

// LoadingManager로 전체 로딩 추적
const manager = new THREE.LoadingManager();

manager.onStart = (url, loaded, total) => {
  console.log(`로딩 시작: ${loaded}/${total}`);
};

manager.onProgress = (url, loaded, total) => {
  const progress = (loaded / total) * 100;
  console.log(`전체 진행률: ${progress.toFixed(1)}%`);
};

manager.onLoad = () => {
  console.log('모든 모델 로드 완료!');
  document.getElementById('loading').style.display = 'none';
};

const loader = new GLTFLoader(manager);

// 여러 모델을 Promise로 감싸기
function loadModel(url) {
  return new Promise((resolve, reject) => {
    loader.load(url, resolve, undefined, reject);
  });
}

// 병렬 로딩
Promise.all([
  loadModel('models/chair1.glb'),
  loadModel('models/chair2.glb'),
  loadModel('models/chair3.glb')
]).then(([gltf1, gltf2, gltf3]) => {
  // 각 모델을 다른 위치에 배치
  gltf1.scene.position.set(-3, 0, 0);
  gltf2.scene.position.set(0, 0, 0);
  gltf3.scene.position.set(3, 0, 0);

  scene.add(gltf1.scene, gltf2.scene, gltf3.scene);
  console.log('3개 의자 모두 배치 완료!');
}).catch((error) => {
  console.error('모델 로딩 실패:', error);
});

김개발 씨는 새로운 요구사항을 받았습니다. 제품 비교 페이지에서 세 개의 의자를 나란히 보여줘야 했습니다.

처음에는 하나씩 로드했는데, 첫 번째 의자가 나타나고, 몇 초 후 두 번째가, 또 몇 초 후 세 번째가 나타났습니다. "이건 좀 이상한데요..." 박시니어 씨가 말합니다.

"모든 모델을 로드한 다음 한 번에 보여주는 게 좋겠어요." LoadingManager는 Three.js의 중앙 집중식 로딩 관리자입니다. 쉽게 비유하자면, LoadingManager는 택배 집하장 같은 것입니다.

여러 곳에서 온 택배를 한곳에 모아서 전체 진행 상황을 파악합니다. 모든 택배가 도착하면 "배송 완료" 알림을 보냅니다.

마찬가지로 LoadingManager는 여러 모델의 로딩 상태를 추적하고, 모두 완료되면 알려줍니다. LoadingManager의 세 가지 콜백을 살펴보겠습니다.

onStart는 첫 번째 리소스 로딩이 시작될 때 호출됩니다. loaded는 현재까지 로드된 파일 수, total은 전체 파일 수입니다.

onProgress는 각 파일이 로드될 때마다 호출됩니다. onLoad는 모든 파일 로딩이 완료되면 호출되며, 이때 로딩 UI를 숨기면 됩니다.

Promise는 비동기 작업을 우아하게 다루는 JavaScript의 핵심 기능입니다. loader.load()는 콜백 방식인데, 이를 Promise로 감싸면 async/awaitPromise.all()을 사용할 수 있습니다.

loadModel() 헬퍼 함수는 loader.load를 Promise로 변환합니다. 성공하면 resolve(gltf)를 호출하고, 실패하면 reject(error)를 호출합니다.

Promise.all()이 병렬 로딩의 핵심입니다. Promise.all()은 배열로 받은 모든 Promise가 완료될 때까지 기다립니다.

중요한 점은 병렬로 실행된다는 것입니다. 세 개의 모델을 순차적으로 로드하면 3초 + 3초 + 3초 = 9초가 걸리지만, 병렬로 로드하면 max(3초, 3초, 3초) = 3초면 됩니다.

then()의 구조분해 할당을 이해해야 합니다. Promise.all()은 배열을 반환하는데, 구조분해 할당으로 [gltf1, gltf2, gltf3]로 받을 수 있습니다.

이제 각 모델에 개별적으로 접근할 수 있습니다. 첫 번째 의자는 왼쪽에, 두 번째는 중앙에, 세 번째는 오른쪽에 배치합니다.

position.set()으로 간격을 조절합니다. x축으로 3 유닛씩 떨어뜨려서 배치합니다.

-3, 0, 3으로 설정하면 균등한 간격이 생깁니다. 모델 크기에 따라 이 값을 조절해야 합니다.

작은 모델이라면 간격을 줄이고, 큰 모델이라면 늘립니다. scene.add()는 여러 객체를 한 번에 받을 수 있습니다.

scene.add(gltf1.scene, gltf2.scene, gltf3.scene) 이렇게 쉼표로 구분해서 여러 개를 추가할 수 있습니다. 이는 scene.add(gltf1.scene); scene.add(gltf2.scene); 이렇게 세 번 호출하는 것과 같지만 더 깔끔합니다.

에러 처리도 중요합니다. catch() 블록은 세 모델 중 하나라도 로드에 실패하면 실행됩니다.

예를 들어 chair2.glb 파일이 없다면 전체 로딩이 실패합니다. 실무에서는 일부가 실패해도 나머지를 보여주고 싶을 수 있습니다.

이럴 때는 Promise.allSettled()를 사용하면 됩니다. Promise.allSettled()는 더 관대한 방식입니다.

Promise.all()은 하나라도 실패하면 전체가 실패하지만, Promise.allSettled()는 성공한 것과 실패한 것을 모두 알려줍니다. 각 결과가 {status: 'fulfilled', value: gltf} 또는 {status: 'rejected', reason: error} 형태로 옵니다.

성공한 모델만 화면에 추가하고, 실패한 자리에는 "로드 실패" 메시지를 표시할 수 있습니다. 실제 현업에서는 어떻게 활용할까요?

온라인 전시회 플랫폼을 만든다고 가정해봅시다. 전시관에 수십 개의 작품이 있고, 각각이 3D 모델입니다.

LoadingManager로 전체 진행률을 표시하고, Promise.all()로 모든 작품을 병렬 로드합니다. 로딩이 완료되면 "전시회 입장" 버튼이 활성화되고, 사용자는 모든 작품을 끊김 없이 감상할 수 있습니다.

주의할 점도 있습니다. 너무 많은 파일을 동시에 로드하면 브라우저의 동시 연결 제한에 걸릴 수 있습니다.

보통 브라우저는 같은 도메인에 6~8개의 동시 연결만 허용합니다. 20개의 모델을 로드한다면 순차적으로 그룹을 나눠서 로드하는 것이 더 효율적일 수 있습니다.

김개발 씨가 코드를 실행했습니다. 로딩 바가 0%에서 100%까지 채워지고, 세 개의 의자가 동시에 나타났습니다!

"훨씬 자연스럽네요!" 박시니어 씨가 미소 짓습니다. "Promise와 LoadingManager는 복잡한 로딩 시나리오를 다룰 때 필수예요." 여러 모델을 효율적으로 관리하는 능력은 복잡한 3D 웹 애플리케이션을 만드는 기초입니다.

실전 팁

💡 - Promise.allSettled()를 사용하면 일부 실패에도 유연하게 대응할 수 있습니다

  • 너무 많은 모델은 그룹으로 나눠 로드하세요
  • LoadingManager의 onError 콜백도 설정하면 더 안전합니다

이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!

#Three.js#GLTFLoader#3D모델#Blender#웹3D#Three.js,Blender,3D웹개발

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.