
서론
그 간 유니티를 통해서 콘텐츠를 개발하는 것은 나에게 익숙한 영역이었다. 필요에 따라서 안드로이드를 타겟으로 빌드를 하기도 하고, VR의 HMD 실행 환경에 따라 Standalone 환경에서 개발을 진행했고, 웹으로 결과물을 공유해야 할 땐 Unity WebGL 빌드가 당연한 선택지였다. 특히 최근 Unity 6가 출시되면서 웹 지원은 'WebGL'을 넘어 'Unity Web'이라는 강력한 플랫폼으로 격상되었다. 이전의 단점들이었던 2GB -> 4GB 메모리 지원, 모바일 웹 공식 지원, 웹 어셈블리 멀티스레딩을 통한 성능 향상 등 이전과 비교가 불가할 정도로 웹 환경이 강력해졌다.
하지만 종종 면접을 보거나 업계에서 요구하는 기술들이 무엇이 있는지 확인차 구직 사이트를 보다보면 종종 요구되는 기술중에 'Three.js'를 마주할 수 있었다. Unity Web의 발전에도 불구하고 업계에서 Three.js 역량을 요구하는 이유와 그 질문에 답을 찾고 싶었고, 이게 뭔지, 왜 필요한지 몰랐지만, 다양한 기술 스택을 쌓고 완벽한 전문성을 갖추진 못하더라도 구성과 개념을 알고 사용 방법을 알고 있는 것과, 전혀 그렇지 못한 것과는 분명한 차이가 있을 것이라는 생각에 유튜브 강의와 Gemini의 도움을 받아 챕터별로 기초부터 독학을 해보기로 했다.
Unity Web(WebGL) vs Three.js
| 구분 | Unity Web(WebGL) | Three.js |
| 정체성 | 3D 게임엔진 | 웹 3D 렌더링 라이브러리 |
| 성능 | 런타임 성능 우수 : 로딩 후 복잡한 물리 연산, 다수 객체, 고사양 셰이더 처리 등 최적화된 엔진 코어가 무거운 작업을 효율적으로 처리 | 초기 로딩 속도 우수 : 필수 기능만 포함하는 경량 라이브러리이므로 초기 진입 속도가 매우 빠르고 거의 즉시 콘텐츠 경험 가능 |
| 효율성 | 개발 효율성 : 에디터, 물리엔진, 애니메이션 시스템 등 모든 도구가 통합된 환경을 제공해 복잡한 3D 앱을 빠르게 개발 가능 | 웹 통합 효율성 : HTML, CSS, JS와 완벽한 통합으로 웹 생태계와의 유기적인 연동이 매우 효율적 |
| 파일 크기 | 큼 : 엔진 전체가 포함되므로 용량이 크고 초기 로딩 시간이 길어지는 주 원인이 됨 | 작음 : 필요한 모듈만 가져다 쓰는 방식으로 매우 가볍고 웹사이트의 일부 요소로 부담 없이 추가 가능 |
| 개발 방향성 | 콘텐츠 중심 : 고품질 3D 게임 등 독립적으로 실행되는 하나의 완성된 3D 애플리케이션을 웹에 배포하는 것을 목표 | 웹 경험 중심 : 웹사이트의 인터랙션, 광고, 데이터 시각화 등 기존 웹페이지를 풍부하게 만드는 3D 요소를 구현하는 것을 목표 |
| 생태계 확장 | 에셋스토어 : 3D 모델, 셰이더, 플러그인 활용 가능, C# 객체 지향 언어 사용 | NPM : React, Vue 등 다른 JS 프레임워크나 웹 라이브러리와 결합해 기능 확장 가능 |
| 최적화 관점 | 엔진 내부 최적화 : DrawCall 배칭, Oclusion Culling 등 엔진이 제공하는 고급 렌더링 최적화 기법에 의존 | 웹 환경 최적화 : 자원 로딩 시점, 렝더링 루프 제어 등 개발자가 직접 웹 환경에 맞춰 세말하게 튜닝 |
Unity Web(구 WebGL)
Unity WebGL 빌드는 본질적으로 하나의 거대한 애플리케이션을 웹페이지라는 액자에 넣어 실행하는 블랙박스와 같다. 고품질의 3D 게임이나 복잡한 시뮬레이션을 웹에 배포하기에는 효율적이나, 웹사이트의 다른 HTML 버튼, 텍스트, UI들과 유기적인 상호작용과 페이지의 일부로서 가볍게 로딩되는 데에는 구조적 한계를 가진다. 사용자 입장에서도 수백 MB에 달하는 리소스를 모두 다운로드한 후에 콘텐츠를 경험할 수 있어 웹의 가장 큰 장점인 즉시성을 해치게 된다.
Three.js
웹의 표준 기술인 HTML, CSS, javaScript와 완벽하게 통합되는 것을 전제로 탄생한 라이브러리이다. Three.js로 만든 3D 요소는 웹페이지의 다른 <div> 태그나 이미지 처럼 DOM(문서 객체 모델)의 일부로 취급 가능해 CSS로 스타일 적용, JavaScript로 실시간 상호작용하는 것에 매우 자유롭다. 일부 회사 웹사이트에서 사용자가 원하는 색상으로 판매 제품을 바꿔보는 설정도구를 만드는 등 '웹 페이지의 일부로 동작하는' 3D 경험에 최적화 되어있다.
관련 업계가 원하는 것은 고립된 3D 앱을 웹이 띄우는 것을 넘어 기존 웹사이트와 완벽하게 조화되고 빠르게 로딩 돼 사용자 이탈 최소화를 원하는 통합된 웹 경험의 모든 종류에 대응 가능한 개발자가 아닐까 싶다.
Three.js 기본 구성
Unity 프로젝트가 Assets, ProjectSettings 등의 폴더 구조를 가지듯이 Three.js도 기본적인 파일ㄴㄴ 구성이 존재한다.
- index.html : 웹페이지의 뼈대 역할을 한다. 3D 그래픽이 그려질 <canvas> 라는 도화지를 배치하고 필요한 스크립트 파일을 불러온다.
- style.css : 웹페이지의 디자인을 담당한다. 도화지를 화면에 꽉채우거나 다른 UI 요소들을 배치하는 역할을 한다.
- main.js : Unity C# 스크립트 같은 핵심 파일이고, Three.js의 모든 로직이 작성되는 곳이다.
importmap : 브라우저에게 Three.js의 위치 전달
Three.js 코드는 import 구문을 사용해 필요한 모듈을 불러온다. 하지만 일반 브라우저 환경에서는 'three' 라는 이름만 보고 파일의 경로를 알 수 없다.
이때 importmap을 index.html에 추가하면 브라우저에게 모듈의 실제 주소를 알려주는 역할을 하게된다.
<head>
<script type="importmap">
{
"imports": {
"three": "https://unpkg.com/three@0.138.0/build/three.module.js",
"three/addons/": "https://unpkg.com/three@0.138.0/examples/jsm/"
}
}
</script>
</head>
위 태그를 통해 three라는 이름은 three.module.js 파일, three/addons/ 경로는 examples/jsm 폴더를 가리키는 것으로 브라우저에 전달한다.
Three.js 주요 3요소 : Scene, Camera, Renderer
main.js에서 먼저 할 일은 3D 공간을 만들고 그 공간을 비추는 카메라를 설치해 카메라에 보이는 것을 화면에 그려주는 렌더러를 준비하는 것이다.
// 1. Scene: 모든 오브젝트가 담길 가상의 3D 공간 (월드)
// Unity에서 새 씬(New Scene)을 만드는 것과 같다.
const scene = new THREE.Scene();
// 2. Camera: 씬을 바라보는 시점 (눈)
// Unity의 Camera 오브젝트와 동일. 원근감을 표현하는 PerspectiveCamera를 사용
const sizes = { width: window.innerWidth, height: window.innerHeight };
const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height);
camera.position.z = 5; // 큐브를 보기 위해 카메라를 뒤로 5만큼 이동
scene.add(camera);
// 3. Renderer: 카메라에 찍힌 장면을 실제로 그려주는 역할 (화가)
// Unity의 렌더링 파이프라인 같다. 결과물은 HTML의 canvas 요소에 그려진다다.
const canvas = document.querySelector('.testCanvas');
const renderer = new THREE.WebGLRenderer({
canvas: canvas,
antialias: true // 오브젝트 경계를 부드럽게 표현 (Anti aliasing)
});
renderer.setSize(sizes.width, sizes.height);
화면에 큐브 띄우기 : Mesh = Geometry + Material
Unity에서 GameObject가 Transform, MeshFilter, MeshRenderer 등의 컴포넌트로 구성되듯이 Three.js의 3D 객체(Mesh)는 모양(Geometry)과 재질(Material)의 조합으로 만들어진다.
// 모양(Geometry): 정육면체 모양 정의
// Unity의 MeshFilter가 가지는 Mesh 정보(Cube, Sphere 등)와 같다.
const geometry = new THREE.BoxGeometry(1, 1, 1);
// 재질(Material): 물체의 표면 정의
// MeshBasicMaterial은 빛의 영향을 받지 않는 가장 단순한 재질. (Unity의 Unlit 셰이더)
const material = new THREE.MeshBasicMaterial({ color: 0x6699FF });
// Mesh: 모양과 재질을 합쳐 완전한 3D 오브젝트를 생성
// Unity의 GameObject와 가장 유사한 개념
const cube = new THREE.Mesh(geometry, material);
scene.add(cube); // 생성된 큐브를 씬에 추가
애니메이션 루프와 인터랙션
오브젝트를 움직이게 하려면 매 프레임마다 코드를 실행하는 반복문이 필요하다. Unity의 Update() 함수와 같은 역할을 requestAnimationFrame이 대신한다. 또, OrbitControl이라는 애드온을 사용하면 마우스로 씬을 쉽게 조작 가능하다.
// OrbitControls: 마우스로 카메라 시점을 조작 (회전, 줌, 이동)
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
const controls = new OrbitControls(camera, canvas);
controls.enableDamping = true; // 부드러운 관성 효과
// 애니메이션 루프 (Unity의 Update 함수)
function animate() {
// 다음 프레임에 animate 함수를 다시 호출하도록 예약
requestAnimationFrame(animate);
// OrbitControls 업데이트 (관성 효과 적용을 위해 필요)
controls.update();
// 큐브를 매 프레임마다 회전
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
// 최종 렌더링
renderer.render(scene, camera);
}
animate(); // 루프 시작
결과물
다음 챕터에서는 씬과 오브젝트에 조명, 그림자를 추가하는 내용을 다룰 예정이다.
전체 코드 GitHub 링크
https://github.com/sgho0915/threejs-learn/tree/master/01-basic-scene
threejs-learn/01-basic-scene at master · sgho0915/threejs-learn
This repository is for learning Three.js from basic to advanced concepts. It includes examples for 3D environment setup, lighting, materials, and handling user interactions. - sgho0915/threejs-learn
github.com
'개발 > Three.js' 카테고리의 다른 글
| [Three.js] 03) 3D 모델 불러오기 (GLTF Loader) (0) | 2025.09.02 |
|---|---|
| [Three.js] 02) 조명, 그림자, 인터랙티브 UI (2) | 2025.09.01 |