Ai

three.js — 기본 사용법이랑 AI 쪽에서 쓸만한 점

목차

three.js 를 한번 정리했다. AI 로 3D 데모 만드는 글에 거의 항상 나오는 라이브러리다. 버전은 0.186.1 (2026.9 릴리즈) 기준. 아래 예제는 전부 headless chromium 에서 직접 띄워봤다.

three.js 가 뭔가

브라우저에서 3D 를 그리는 자바스크립트 라이브러리. WebGL 을 직접 쓰면 셰이더, 버퍼를 하나하나 짜야 하는데 three.js 는 장면, 카메라, 물체 단위로 감싸준다. 몇십 줄이면 화면에 뭔가 뜬다. 최근 버전은 WebGPU 도 된다.

기본 구성은 아래 4개다.

  • Scene: 물체랑 조명을 담는 무대
  • Camera: 어디서 보는지. 보통 PerspectiveCamera
  • Renderer: 실제로 그리는 놈. WebGLRenderer 또는 WebGPURenderer
  • Mesh: 모양(Geometry) + 재질(Material)

html 파일 하나로 띄우기

빌드 도구 필요없다. importmap 으로 CDN 에서 바로 가져온다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<!doctype html>
<html>
<body style="margin:0">
<script type="importmap">
{ "imports": {
  "three": "https://cdn.jsdelivr.net/npm/three@0.186.1/build/three.module.js",
  "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.186.1/examples/jsm/"
}}
</script>
<script type="module">
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 0.1, 100);
camera.position.set(2, 2, 4);

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);

const box = new THREE.Mesh(
  new THREE.BoxGeometry(1, 1, 1),
  new THREE.MeshStandardMaterial({ color: 0x4f8cff })
);
scene.add(box);

scene.add(new THREE.AmbientLight(0xffffff, 0.4));
const light = new THREE.DirectionalLight(0xffffff, 1.5);
light.position.set(3, 5, 2);
scene.add(light);

const controls = new OrbitControls(camera, renderer.domElement);

renderer.setAnimationLoop(() => {
  box.rotation.y += 0.01;
  controls.update();
  renderer.render(scene, camera);
});
</script>
</body>
</html>

회전하는 상자

  • MeshStandardMaterial 은 빛이 있어야 보인다. 조명 빼면 그냥 까맣게 나온다
  • OrbitControls 붙이면 마우스로 돌리고 줌 된다
  • 창 크기 바뀔때는 camera.aspect 랑 renderer.setSize 를 다시 해줘야 한다

자주 쓰는 것

3D 모델 불러오기

블렌더에서 뽑은거나 3D 생성 AI 결과물이 보통 .glb 다. GLTFLoader 로 연다.

1
2
3
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';

new GLTFLoader().load('model.glb', (gltf) => scene.add(gltf.scene));

그 외

  • 점 수만개: Points. 같은 물체 수만개: InstancedMesh
  • 마우스로 물체 클릭: Raycaster
  • 블룸 같은 후처리: EffectComposer
  • WebGPU: import * as THREE from 'three/webgpu' 하고 WebGPURenderer 를 쓴다. 셰이더는 TSL 이라는 자바스크립트 문법으로 짠다
  • React 에서는 @react-three/fiber 로 컴포넌트처럼 쓴다

참고) https://threejs.org/docs/ , 예제는 https://threejs.org/examples/ 에 엄청 많다

AI 쪽에서 쓸때 좋은 점

AI 가 코드를 잘 짠다

10년 넘은 라이브러리라 예제랑 질문 답변이 엄청 많다. 그래서 LLM 이 three.js 코드는 꽤 정확하게 뽑는다. 결과물이 html 하나라 받아서 바로 열어보면 된다. “회전하는 지구본 만들어줘” 하면 바로 돌아가는 파일이 나오니까 AI 데모에 많이 쓰이는듯.

임베딩을 3D 로 보기

텍스트나 이미지 임베딩을 UMAP, PCA 로 3차원으로 줄여서 Points 로 찍으면 비슷한 것끼리 뭉치는게 보인다. 마우스로 돌려가면서 볼 수 있어서 2D 그래프보다 낫다.

아래는 가짜 데이터로 해본거. 클래스 5개, 클래스당 4000개, 총 2만개 점이다.

1
2
3
4
5
6
7
// pos: [x,y,z, x,y,z, ...]  col: [r,g,b, ...]  (Float32Array)
const geo = new THREE.BufferGeometry();
geo.setAttribute('position', new THREE.BufferAttribute(pos, 3));
geo.setAttribute('color', new THREE.BufferAttribute(col, 3));

const points = new THREE.Points(geo, new THREE.PointsMaterial({ size: 0.03, vertexColors: true }));
scene.add(points);

2만개 점구름

GPU 없는 서버에서 소프트웨어 렌더링(swiftshader)으로 돌려도 2만개가 초당 34프레임 나왔다. 상자 하나는 60프레임. 실제 GPU 있는 PC 에선 훨씬 많이 찍어도 될꺼 같다. 몇개까지 되는지는 안해봤다.

3D 생성 모델 결과 띄우기

텍스트나 이미지로 3D 를 만드는 모델은 결과를 거의 glTF(.glb), PLY(점구름), 가우시안 스플래팅으로 준다. glb, ply 는 three.js 로더로 바로 열린다. 가우시안 스플래팅은 three.js 위에 올라가는 별도 라이브러리를 쓴다. 깊이 추정 모델이 만든 깊이맵을 평면 메쉬에 입히면 사진 한장으로 입체 효과도 낼 수 있다.

브라우저 안에서 모델이랑 붙이기

MediaPipe, TensorFlow.js, Transformers.js, ONNX Runtime Web 도 브라우저에서 돈다. 웹캠 손동작으로 3D 물체 돌리기, 얼굴 표정을 아바타에 입히기 같은걸 서버 없이 만들 수 있다. 링크만 보내면 누구나 열어본다.

장면을 JSON 으로 주고받기

장면 전체를 JSON 으로 뽑고 다시 읽을 수 있다. LLM 한테 장면 데이터를 만들게 하거나 고치게 할때 편하다.

1
2
const json = scene.toJSON();
const back = new THREE.ObjectLoader().parse(json);

상자 하나 넣은 장면을 해보면 2117 바이트짜리 JSON 이 나오고 다시 읽으면 Scene 안에 BoxGeometry 가 그대로 살아있다. 장면이 부모-자식 트리 구조라 “왼쪽 의자 빨간색으로” 같은 지시도 코드 몇줄로 바뀐다.

AI 가 짠 코드에서 자주 나는 에러

LLM 이 옛날 버전 코드를 섞어서 뽑는 경우가 많다. 에러 나면 아래부터 보자.

옛 코드지금
THREE.Geometry없어짐. BufferGeometry
examples/js/... 스크립트 태그examples/jsm/... 를 import
renderer.outputEncoding = THREE.sRGBEncodingrenderer.outputColorSpace = THREE.SRGBColorSpace
requestAnimationFrame 직접 돌리기renderer.setAnimationLoop()

0.186.1 에서 직접 확인해보면 아래처럼 나온다.

1
2
3
4
THREE.Geometry           -> undefined
new THREE.Geometry()     -> TypeError: THREE.Geometry is not a constructor
THREE.sRGBEncoding       -> undefined
THREE.SRGBColorSpace     -> 'srgb'

outputEncoding = THREE.sRGBEncoding 은 에러 없이 그냥 무시된다. 렌더러 기본값이 이미 sRGB 라 보통은 티가 안 난다. 문제는 같은 시절 코드에 같이 있는 texture.encoding = THREE.sRGBEncoding 이다. 이것도 무시돼서 텍스처 색이 허옇게 뜬다. 지금은 texture.colorSpace = THREE.SRGBColorSpace 로 써야 한다.

AI 한테 시킬때 “three.js 최신 버전, ES module, importmap 사용” 이라고 같이 적어주면 이런게 많이 줄어든다.

물리 엔진이나 에디터는 없다. 물리는 cannon-es 나 Rapier 를 붙여야 한다. 게임처럼 큰걸 만들거면 Babylon.js 가 더 편할 수도 있다.