🎉Ultra 출시 · 50% 할인 · 기간 한정
웹 3D 디스플레이 성능 가이드 - Three.js vs Babylon.js 구현 전략
2025/08/09

웹 3D 디스플레이 성능 가이드 - Three.js vs Babylon.js 구현 전략

포괄적인 가이드로 웹 3D 뷰어 성능을 마스터하세요. Three.js와 Babylon.js 구현을 비교하고, 로딩 시간을 최적화하며, 투명 배경, 자동 회전, 조명을 위한 전문적인 기법을 배워보세요.

3D 웹 프레임워크 선택: 성능 우선

웹에서 3D 뷰어를 구현할 때, Three.js와 Babylon.js 간의 선택은 단순히 기능에 관한 것이 아닙니다—성능, 번들 크기, 사용자 경험에 관한 것입니다. 이 가이드는 코드 예제와 실제 벤치마크가 포함된 3D 디스플레이 성능 최적화를 위한 실전 검증된 전략을 제공합니다.

프레임워크 비교: 성능 관점

빠른 결정 매트릭스

측면Three.jsBabylon.js
번들 크기~130KB (코어)~2.5MB (630KB gzipped)
학습 곡선가파름완만함
내장 기능최소포괄적
성능 제어최대자동화
최적 용도맞춤형 솔루션빠른 개발

철학 차이

  • Three.js: 세밀한 제어를 제공하는 경량 렌더링 엔진
  • Babylon.js: 모든 것이 포함된 완전한 3D 엔진

최소 구현 예제

Three.js: 자동 회전이 있는 투명 배경

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

// 최소 Three.js 뷰어 설정
function initThreeViewer(canvas, modelUrl) {
  // 투명 배경이 있는 씬 설정
  const scene = new THREE.Scene();
  scene.background = null; // 투명

  // 카메라
  const camera = new THREE.PerspectiveCamera(
    75,
    canvas.width / canvas.height,
    0.1,
    1000
  );
  camera.position.z = 5;

  // 알파 채널이 있는 렌더러
  const renderer = new THREE.WebGLRenderer({
    canvas,
    alpha: true,
    antialias: true,
    powerPreference: "high-performance"
  });
  renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));

  // 최적화된 조명
  const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
  const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
  directionalLight.position.set(10, 10, 5);
  scene.add(ambientLight, directionalLight);

  // 자동 회전이 있는 GLB 로드
  const loader = new GLTFLoader();
  let model;

  loader.load(modelUrl, (gltf) => {
    model = gltf.scene;
    scene.add(model);

    // 모델 중심 맞춤 및 스케일 조정
    const box = new THREE.Box3().setFromObject(model);
    const center = box.getCenter(new THREE.Vector3());
    model.position.sub(center);

    const size = box.getSize(new THREE.Vector3());
    const maxDim = Math.max(size.x, size.y, size.z);
    model.scale.multiplyScalar(2 / maxDim);
  });

  // 자동 회전이 있는 애니메이션 루프
  function animate() {
    requestAnimationFrame(animate);

    if (model) {
      model.rotation.y += 0.01;
    }

    renderer.render(scene, camera);
  }
  animate();

  // 크기 조정 처리
  window.addEventListener('resize', () => {
    camera.aspect = canvas.width / canvas.height;
    camera.updateProjectionMatrix();
    renderer.setSize(canvas.width, canvas.height);
  });
}

Babylon.js: 그림자가 있는 완전한 뷰어

import * as BABYLON from '@babylonjs/core';
import '@babylonjs/loaders/glTF';

// 모든 기능이 포함된 Babylon.js 뷰어
function initBabylonViewer(canvas, modelUrl) {
  // 엔진 설정
  const engine = new BABYLON.Engine(canvas, true, {
    preserveDrawingBuffer: true,
    stencil: true,
    powerPreference: "high-performance"
  });

  // 투명 배경이 있는 씬
  const scene = new BABYLON.Scene(engine);
  scene.clearColor = new BABYLON.Color4(0, 0, 0, 0);

  // 자동 회전 카메라
  const camera = new BABYLON.ArcRotateCamera(
    "camera",
    BABYLON.Tools.ToRadians(45),
    BABYLON.Tools.ToRadians(60),
    10,
    BABYLON.Vector3.Zero(),
    scene
  );
  camera.attachControl(canvas, true);
  camera.wheelDeltaPercentage = 0.01;

  // 그림자가 있는 최적화된 조명
  const light = new BABYLON.DirectionalLight(
    "light",
    new BABYLON.Vector3(-1, -2, -1),
    scene
  );
  light.position = new BABYLON.Vector3(20, 40, 20);
  light.intensity = 0.7;

  const ambientLight = new BABYLON.HemisphericLight(
    "ambient",
    new BABYLON.Vector3(0, 1, 0),
    scene
  );
  ambientLight.intensity = 0.3;

  // 그림자 생성기
  const shadowGenerator = new BABYLON.ShadowGenerator(1024, light);
  shadowGenerator.useExponentialShadowMap = true;

  // 최적화가 포함된 모델 로드
  BABYLON.SceneLoader.LoadAssetContainer(
    "",
    modelUrl,
    scene,
    (container) => {
      container.addAllToScene();

      // 모든 메시에 그림자 적용
      container.meshes.forEach(mesh => {
        mesh.receiveShadows = true;
        shadowGenerator.addShadowCaster(mesh);
      });

      // 자동 회전
      scene.registerBeforeRender(() => {
        container.meshes[0].rotation.y += 0.01;
      });
    }
  );

  // 렌더 루프
  engine.runRenderLoop(() => {
    scene.render();
  });

  // 크기 조정 처리
  window.addEventListener('resize', () => {
    engine.resize();
  });
}

성능 최적화 전략

1. 모델 최적화

파일 크기 제어

// 압축 비교
const modelSizes = {
  uncompressed: "26MB",
  draco: "5MB (-80%)",
  meshopt: "4MB (-85%)",
  quantized: "8MB (-70%)"
};

텍스처 압축

// Three.js 텍스처 최적화
const textureLoader = new THREE.TextureLoader();
const texture = textureLoader.load('texture.jpg');
texture.minFilter = THREE.LinearMipmapLinearFilter;
texture.magFilter = THREE.LinearFilter;
texture.generateMipmaps = true;

// Basis Universal 압축 (50-75% 더 작음)
import { BasisTextureLoader } from 'three/examples/jsm/loaders/BasisTextureLoader';
const basisLoader = new BasisTextureLoader();
basisLoader.setTranscoderPath('basis/');
basisLoader.load('texture.basis', (texture) => {
  material.map = texture;
});

메시 단순화

// LOD (Level of Detail) 구현
const lod = new THREE.LOD();

// 고상세 (클로즈업)
const highDetail = await loadModel('model-300k.glb');
lod.addLevel(highDetail, 0);

// 중상세
const mediumDetail = await loadModel('model-60k.glb');
lod.addLevel(mediumDetail, 50);

// 저상세 (먼 거리)
const lowDetail = await loadModel('model-15k.glb');
lod.addLevel(lowDetail, 100);

scene.add(lod);

2. 지연 로딩 구현

// 플레이스홀더가 있는 점진적 로딩
class LazyModel {
  constructor(placeholderUrl, highQualityUrl) {
    this.placeholder = placeholderUrl;
    this.highQuality = highQualityUrl;
    this.loaded = false;
  }

  async load(scene, callback) {
    // 저해상도 플레이스홀더를 즉시 로드
    const placeholder = await this.loadGLB(this.placeholder);
    scene.add(placeholder);
    callback(placeholder);

    // 백그라운드에서 고해상도 로드
    const highQuality = await this.loadGLB(this.highQuality);

    // 부드러운 전환
    highQuality.visible = false;
    scene.add(highQuality);

    // 페이드 전환
    this.fadeTransition(placeholder, highQuality, () => {
      scene.remove(placeholder);
      this.loaded = true;
    });
  }

  fadeTransition(out, in, complete) {
    const duration = 500; // ms
    const start = performance.now();

    function animate() {
      const elapsed = performance.now() - start;
      const progress = Math.min(elapsed / duration, 1);

      out.material.opacity = 1 - progress;
      in.material.opacity = progress;

      if (progress < 1) {
        requestAnimationFrame(animate);
      } else {
        in.visible = true;
        complete();
      }
    }
    animate();
  }
}

3. 성능 모니터링

// FPS 카운터 및 성능 지표
class PerformanceMonitor {
  constructor(renderer) {
    this.renderer = renderer;
    this.fps = 0;
    this.frame = 0;
    this.lastTime = performance.now();

    // GPU 메모리 모니터링
    this.memory = {
      geometries: 0,
      textures: 0,
      programs: 0
    };
  }

  update() {
    this.frame++;
    const currentTime = performance.now();

    if (currentTime >= this.lastTime + 1000) {
      this.fps = (this.frame * 1000) / (currentTime - this.lastTime);
      this.frame = 0;
      this.lastTime = currentTime;

      // 메모리 통계 업데이트
      const info = this.renderer.info;
      this.memory = {
        geometries: info.memory.geometries,
        textures: info.memory.textures,
        programs: info.programs.length
      };

      console.log(`FPS: ${this.fps.toFixed(1)} | ` +
                  `Geometries: ${this.memory.geometries} | ` +
                  `Textures: ${this.memory.textures}`);
    }
  }
}

SEO 및 접근성 최적화

SEO를 위한 플레이스홀더 이미지

<div class="model-viewer-container">
  <!-- SEO 친화적 플레이스홀더 -->
  <img
    src="model-preview.jpg"
    alt="제품명의 3D 모델"
    loading="lazy"
    style="position: absolute; width: 100%; height: 100%;"
    id="placeholder"
  />

  <!-- 3D 캔버스 (초기에는 숨김) -->
  <canvas
    id="viewer-canvas"
    style="display: none;"
    aria-label="인터랙티브 3D 모델 뷰어"
  />

  <!-- 로딩 인디케이터 -->
  <div class="loading-spinner" style="display: none;">
    3D 모델 로딩 중...
  </div>
</div>

<script>
// 점진적 향상
if (WebGL2RenderingContext) {
  // 3D 뷰어 로드
  loadViewer().then(() => {
    document.getElementById('placeholder').style.display = 'none';
    document.getElementById('viewer-canvas').style.display = 'block';
  });
} else {
  // 정적 이미지로 폴백
  console.log('WebGL이 지원되지 않음');
}
</script>

3D 콘텐츠용 구조화된 데이터

<script type="application/ld+json">
{
  "@context": "https://schema.org/",
  "@type": "3DModel",
  "name": "제품명 3D 모델",
  "description": "제품명의 인터랙티브 3D 뷰",
  "image": "https://example.com/model-preview.jpg",
  "encoding": {
    "@type": "3DModelEncoding",
    "encodingFormat": "model/gltf-binary",
    "contentUrl": "https://example.com/model.glb"
  }
}
</script>

플랫폼별 최적화

모바일 성능

// 기기 기반 적응형 품질
function getQualitySettings() {
  const isMobile = /iPhone|iPad|Android/i.test(navigator.userAgent);
  const gpu = detectGPUTier();

  if (isMobile) {
    return {
      pixelRatio: Math.min(window.devicePixelRatio, 2),
      shadowMapSize: 512,
      textureSize: 1024,
      antialias: false,
      modelQuality: 'standard' // 30k 폴리곤
    };
  }

  // 데스크톱 설정
  return {
    pixelRatio: window.devicePixelRatio,
    shadowMapSize: 2048,
    textureSize: 2048,
    antialias: true,
    modelQuality: gpu.tier > 2 ? 'ultra' : 'pro'
  };
}

임베드 코드 생성기

// Modelfy 3D 모델용 원클릭 임베드 코드
function generateEmbedCode(modelId, options = {}) {
  const defaults = {
    width: '100%',
    height: '500px',
    autoRotate: true,
    background: 'transparent',
    controls: true,
    quality: 'auto'
  };

  const settings = { ...defaults, ...options };

  return `
<!-- Modelfy 3D Viewer -->
<iframe
  src="https://modelfy3d.com/embed/${modelId}"
  width="${settings.width}"
  height="${settings.height}"
  frameborder="0"
  allow="autoplay; fullscreen; xr-spatial-tracking"
  data-auto-rotate="${settings.autoRotate}"
  data-background="${settings.background}"
  data-controls="${settings.controls}"
  data-quality="${settings.quality}"
  loading="lazy"
></iframe>
  `.trim();
}

// 클립보드에 복사 기능
function copyEmbedCode() {
  const code = generateEmbedCode('your-model-id', {
    width: '800px',
    height: '600px'
  });

  navigator.clipboard.writeText(code).then(() => {
    alert('임베드 코드가 클립보드에 복사되었습니다!');
  });
}

성능 벤치마크

실제 로딩 시간

모델 품질파일 크기Three.js 로드Babylon.js 로드FPS (모바일)FPS (데스크톱)
Fast (15K)0.5MB0.8s1.2s6060
Standard (30K)1.2MB1.5s2.0s5560
Pro (60K)2.5MB2.8s3.5s4560
Ultra (300K)5MB5.2s6.8s2555

최적화 효과

// 최적화 전
const unoptimized = {
  fileSize: "26MB",
  loadTime: "18s",
  fps: "15 (모바일)",
  memory: "450MB"
};

// 최적화 후
const optimized = {
  fileSize: "2.5MB (-90%)",
  loadTime: "2.8s (-84%)",
  fps: "45 (모바일)",
  memory: "95MB (-79%)"
};

빠른 구현 체크리스트

3D 뷰어를 배포하기 전에:

  • Draco 또는 Meshopt로 모델 압축
  • 텍스처 최적화 (WebP/Basis)
  • 대형 모델에 LOD 구현
  • 모바일에서 픽셀 비율 제한
  • 더 나은 UX를 위한 지연 로딩
  • SEO 플레이스홀더 이미지 추가
  • 접근성 레이블 포함
  • 성능 모니터링 활성화
  • 임베드 코드 테스트

오늘부터 최적화 시작하기

고성능 3D 뷰어를 구현할 준비가 되셨나요? Modelfy 3D는 다음을 제공합니다:

  • 사전 최적화된 GLB 내보내기
  • LOD를 위한 다중 품질 계층
  • 임베드 코드 생성기
  • CDN 호스팅 뷰어 라이브러리

시작하기 →

개발자 자료

포괄적인 통합 가이드와 성능 모범 사례 문서를 준비하고 있습니다. Three.js 및 Babylon.js 통합에 대한 자세한 튜토리얼과 예제 구현을 기대해 주세요.

이러한 기법을 마스터하면 3D 콘텐츠가 더 빨리 로드되고, 더 부드럽게 실행되며, 모든 기기에서 뛰어난 경험을 제공할 것입니다. 웹 3D의 미래는 성능 우선입니다—당신의 구현이 따라잡을 수 있도록 하세요.

뉴스레터

커뮤니티에 합류하세요

최신 소식과 업데이트를 받아보세요