Three.js 튜토리얼: 2026년 시작하기
Three.js로 첫 번째 3D 웹 경험 구축하기
Hypereal로 구축 시작하기
단일 API를 통해 Kling, Flux, Sora, Veo 등에 액세스하세요. 무료 크레딧으로 시작하고 수백만으로 확장하세요.
신용카드 불필요 • 10만 명 이상의 개발자 • 엔터프라이즈 지원
Three.js 튜토리얼: 2026년 시작하기
Three.js는 웹에서 3D 그래픽을 제작하기 위해 가장 널리 사용되는 JavaScript 라이브러리입니다. WebGL의 복잡함을 접근하기 쉬운 API로 추상화하여, 브라우저에서 직접 인터랙티브한 3D 씬, 제품 컨피규레이터, 데이터 시각화, 게임 및 몰입형 경험을 구축할 수 있게 해줍니다.
이 튜토리얼에서는 조명, 재질, 애니메이션 및 사용자 상호작용이 포함된 작동하는 3D 씬을 기초부터 제작해 봅니다. 사전 3D 프로그래밍 경험은 필요하지 않습니다.
제작할 내용
이 튜토리얼을 마칠 때쯤이면 다음과 같은 기능이 포함된 3D 씬을 갖게 됩니다:
- 텍스처가 입혀진 회전하는 큐브
- 주변광(Ambient) 및 직광(Directional) 조명
- 씬을 궤도 주행하는 카메라 컨트롤
- 창 크기에 맞춰 조절되는 반응형 캔버스
사전 요구 사항
| 요구 사항 | 버전 |
|---|---|
| Node.js | 18+ |
| npm 또는 yarn | 최신 버전 |
| 현대적인 브라우저 | Chrome, Firefox, Safari, 또는 Edge |
| 코드 에디터 | VS Code 권장 |
기본적인 JavaScript 지식이 필요합니다. ES 모듈(import/export)에 익숙하면 도움이 됩니다.
1단계: 프로젝트 설정
Hot Module Replacement를 지원하는 빠른 개발 서버인 Vite를 사용하여 새 프로젝트를 생성합니다:
npm create vite@latest threejs-tutorial -- --template vanilla
cd threejs-tutorial
npm install three
npm run dev
프로젝트 구조는 다음과 같아야 합니다:
threejs-tutorial/
index.html
main.js
style.css
package.json
style.css의 내용을 다음으로 교체합니다:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
overflow: hidden;
}
canvas {
display: block;
}
index.html을 최소한의 구조로 교체합니다:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Three.js Tutorial</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<script type="module" src="/main.js"></script>
</body>
</html>
2단계: 기본 씬(Scene) 생성
모든 Three.js 애플리케이션에는 Scene, Camera, Renderer라는 세 가지 요소가 필요합니다. main.js의 내용을 교체합니다:
import * as THREE from 'three';
// 1. Scene 생성
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x1a1a2e);
// 2. Camera 생성
const camera = new THREE.PerspectiveCamera(
75, // 시야각 (Degrees)
window.innerWidth / window.innerHeight, // 종횡비
0.1, // Near clipping plane
1000 // Far clipping plane
);
camera.position.z = 5;
// 3. Renderer 생성
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
document.body.appendChild(renderer.domElement);
// 4. Cube 추가
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({ color: 0x00ff88 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
// 5. 애니메이션 루프
function animate() {
requestAnimationFrame(animate);
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
}
animate();
브라우저를 열면 어두운 배경에서 녹색 큐브가 회전하는 것을 볼 수 있습니다. 이것이 당신의 첫 번째 Three.js 씬입니다.
핵심 개념 이해하기
| 개념 | 역할 |
|---|---|
| Scene | 모든 3D 객체, 조명, 카메라를 담는 컨테이너 |
| Camera | 관점을 정의함. PerspectiveCamera는 인간의 시야를 시뮬레이션 |
| Renderer | 3D 씬을 캔버스의 2D 픽셀로 변환 |
| Geometry | 객체의 형태 (박스, 구, 평면 등) |
| Material | 표면의 외관 (색상, 텍스처, 광택) |
| Mesh | Geometry + Material의 조합 = 시각화된 객체 |
3단계: 조명 추가하기
MeshBasicMaterial은 조명을 무시합니다. 객체가 빛에 반응하게 하려면 다른 재질을 사용해야 합니다:
// 재질을 교체하고 조명을 추가합니다.
// 기존의 material 라인을 지우고 다음으로 교체하세요:
const material = new THREE.MeshStandardMaterial({
color: 0x00ff88,
roughness: 0.4,
metalness: 0.3,
});
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
// Ambient light 추가 (부드럽고 전체적인 조명)
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);
// Directional light 추가 (태양광과 같음)
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(5, 5, 5);
scene.add(directionalLight);
// Point light 추가 (전구와 같음)
const pointLight = new THREE.PointLight(0xff6b6b, 1, 100);
pointLight.position.set(-3, 2, 4);
scene.add(pointLight);
조명 유형 비교
| 조명 유형 | 설명 | 성능 비용 |
|---|---|---|
| AmbientLight | 모든 방향에서 균일하게 비추는 빛 | 매우 낮음 |
| DirectionalLight | 평행 광선 (태양광과 같음) | 낮음 |
| PointLight | 한 점으로부터 모든 방향으로 방출 | 중간 |
| SpotLight | 원뿔 모양의 광선 | 중간-높음 |
| HemisphereLight | 하늘/지면 그라데이션 광원 | 낮음 |
| RectAreaLight | 사각형 면에서 나오는 빛 | 높음 |
4단계: 카메라 컨트롤 추가
사용자가 카메라를 회전, 확대/축소 및 이동할 수 있도록 OrbitControls를 설치합니다:
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// Renderer 생성 후:
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
controls.minDistance = 2;
controls.maxDistance = 20;
// 애니메이션 루프 업데이트:
function animate() {
requestAnimationFrame(animate);
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
controls.update(); // Damping(감쇠)이 활성화된 경우 필수
renderer.render(scene, camera);
}
이제 클릭 후 드래그하여 회전하고, 스크롤하여 확대/축소하며, 우클릭으로 이동할 수 있습니다.
5단계: 텍스처 추가
큐브에 이미지 텍스처를 입혀봅니다:
const textureLoader = new THREE.TextureLoader();
const texture = textureLoader.load('/textures/brick.jpg');
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
const material = new THREE.MeshStandardMaterial({
map: texture,
roughness: 0.7,
metalness: 0.1,
});
프로그래밍 방식으로 텍스처를 생성하거나 프로토타이핑을 위해 내장 텍스처를 사용할 수도 있습니다.
여러 텍스처 로드하기 (PBR 재질)
극사실적인 재질을 위해 PBR(Physically Based Rendering) 텍스처를 사용합니다:
const loader = new THREE.TextureLoader();
const material = new THREE.MeshStandardMaterial({
map: loader.load('/textures/albedo.jpg'), // 색상 (Albedo)
normalMap: loader.load('/textures/normal.jpg'), // 표면 디테일
roughnessMap: loader.load('/textures/roughness.jpg'), // 광택
metalnessMap: loader.load('/textures/metalness.jpg'), // 금속성 영역
aoMap: loader.load('/textures/ao.jpg'), // 주변 폐쇄 (Ambient Occlusion)
});
6단계: 더 많은 객체 추가하기
여러 객체가 포함된 씬을 만듭니다:
// 지면 평면
const planeGeometry = new THREE.PlaneGeometry(20, 20);
const planeMaterial = new THREE.MeshStandardMaterial({
color: 0x333344,
roughness: 0.8,
});
const plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.rotation.x = -Math.PI / 2;
plane.position.y = -1;
scene.add(plane);
// 구체
const sphereGeometry = new THREE.SphereGeometry(0.7, 32, 32);
const sphereMaterial = new THREE.MeshStandardMaterial({
color: 0xff6b6b,
roughness: 0.2,
metalness: 0.8,
});
const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
sphere.position.x = -2;
scene.add(sphere);
// 토러스 (도넛 모양)
const torusGeometry = new THREE.TorusGeometry(0.5, 0.2, 16, 100);
const torusMaterial = new THREE.MeshStandardMaterial({
color: 0x4ecdc4,
roughness: 0.3,
metalness: 0.6,
});
const torus = new THREE.Mesh(torusGeometry, torusMaterial);
torus.position.x = 2;
scene.add(torus);
7단계: 반응형 만들기
씬이 모든 화면 크기에 적응하도록 창 크기 조절(Resize)을 처리합니다:
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
});
8단계: 3D 모델 로드하기
대부분의 실제 프로젝트는 제작된 3D 모델을 사용합니다. GLTF 형식은 웹 3D의 표준입니다:
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
const gltfLoader = new GLTFLoader();
gltfLoader.load(
'/models/robot.glb',
(gltf) => {
const model = gltf.scene;
model.scale.set(0.5, 0.5, 0.5);
model.position.set(0, -1, 0);
scene.add(model);
},
(progress) => {
console.log(`Loading: ${(progress.loaded / progress.total * 100).toFixed(1)}%`);
},
(error) => {
console.error('모델 로드 실패:', error);
}
);
무료 3D 모델을 찾을 수 있는 곳
| 출처 | 형식 | 라이선스 |
|---|---|---|
| Sketchfab | GLTF, FBX, OBJ | 다양함 (많은 CC 라이선스) |
| poly.pizza | GLTF | CC0 |
| Kenney.nl | GLTF | CC0 |
| Three.js examples | GLTF | MIT |
| Quaternius | GLTF | CC0 |
9단계: 후처리(Post-Processing) 추가
밝은 영역 주위에 광환을 만드는 블룸(Bloom) 효과 같은 시각 효과를 추가합니다:
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';
const composer = new EffectComposer(renderer);
composer.addPass(new RenderPass(scene, camera));
const bloomPass = new UnrealBloomPass(
new THREE.Vector2(window.innerWidth, window.innerHeight),
0.5, // 강도 (Strength)
0.4, // 반경 (Radius)
0.85 // 임계값 (Threshold)
);
composer.addPass(bloomPass);
// 애니메이션 루프 내에서 renderer.render()를 다음으로 교체합니다:
function animate() {
requestAnimationFrame(animate);
controls.update();
composer.render(); // renderer 대신 composer 사용
}
전체 예제 코드
모든 것을 결합한 전체 main.js 코드입니다:
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// Scene
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x1a1a2e);
// Camera
const camera = new THREE.PerspectiveCamera(
75, window.innerWidth / window.innerHeight, 0.1, 1000
);
camera.position.set(3, 3, 5);
// Renderer
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.shadowMap.enabled = true;
document.body.appendChild(renderer.domElement);
// Controls
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
// Lights
scene.add(new THREE.AmbientLight(0xffffff, 0.5));
const dirLight = new THREE.DirectionalLight(0xffffff, 1);
dirLight.position.set(5, 5, 5);
dirLight.castShadow = true;
scene.add(dirLight);
// Objects
const cube = new THREE.Mesh(
new THREE.BoxGeometry(1, 1, 1),
new THREE.MeshStandardMaterial({ color: 0x00ff88, roughness: 0.4 })
);
cube.castShadow = true;
scene.add(cube);
const plane = new THREE.Mesh(
new THREE.PlaneGeometry(20, 20),
new THREE.MeshStandardMaterial({ color: 0x333344 })
);
plane.rotation.x = -Math.PI / 2;
plane.position.y = -1;
plane.receiveShadow = true;
scene.add(plane);
// Resize handler
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
// Animation
function animate() {
requestAnimationFrame(animate);
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
controls.update();
renderer.render(scene, camera);
}
animate();
성능 팁
| 팁 | 효과 |
|---|---|
| 필셀 비율(pixel ratio)을 2로 제한 | 고해상도(DPI) 화면에서 3배 이상의 렌더링 방지 |
| BufferGeometry 사용 (최신 Three.js 기본값) | 기존 Geometry보다 훨씬 빠름 |
| 사용하지 않는 텍스처와 지오메트리 해제(Dispose) | 메모리 누수 방지 |
| 반복되는 객체에 인스턴싱(Instancing) 사용 | 하나의 드로우 콜로 수천 개의 객체 렌더링 |
| Frustum culling 활성화 (기본 활성) | 카메라 시야 밖의 객체 렌더링 스킵 |
| 압축 텍스처(KTX2/Basis) 사용 | 파일 크기 감소 및 신속한 GPU 로드 |
마무리하며
Three.js는 단순한 시각화부터 복잡한 인터랙티브 경험까지 확장 가능한 친근한 API를 통해 3D 웹 개발의 세계를 열어줍니다. 이 튜토리얼에서 다룬 기본기를 시작으로 셰이더(Shaders), 물리 엔진, VR/AR 통합과 같은 고급 주제를 탐구해 보세요.
텍스처, 캐릭터 얼굴, 비디오 배경 등 AI 생성 콘텐츠를 포함하는 3D 경험을 구축하고 있다면, Hypereal AI가 제공하는 AI 이미지 생성, 비디오 제작 API 등을 사용하여 Three.js 파이프라인에 직접 연결할 수 있습니다.
