티스토리 뷰
three.js 기초: Claude로 배우는 장면·카메라·렌더러 [교량 BIM 바이브코딩 2편]
마구자바 2026. 10. 6. 21:51
지난 1편에서는 Claude에게 말로 설명해서 three.js 교량 모델을 한 번에 띄워봤습니다. 결과는 나왔지만, 코드가 80줄 가까이 되다 보니 "이게 어떻게 돌아가는 거지?" 하는 부분이 많았을 겁니다.
AI가 코드를 써준다고 해도, 기본 구조를 알고 있어야 원하는 걸 정확히 요청하고, 틀린 부분을 고칠 수 있습니다. 구조계산 프로그램을 쓸 때도 입력 구조를 알아야 결과를 검토할 수 있는 것과 같습니다.
그래서 2편에서는 교량을 잠시 내려놓고, 박스 하나를 화면에 띄우는 가장 작은 예제로 three.js의 뼈대를 하나씩 뜯어보겠습니다. 이 글을 다 읽고 나면 1편 코드의 대부분을 읽을 수 있게 됩니다.
(자바스크립트와 three.js를 왜 배워야 하는지가 궁금하다면 토목 엔지니어가 자바스크립트와 Three.js를 배워야 하는 이유를 먼저 읽어보세요.)
이번 편에서 만들 것
▲ 실제로 동작하는 데모입니다. 마우스로 드래그하면 회전, 휠로 확대·축소, 오른쪽 버튼으로 이동할 수 있습니다.
가로 2, 높이 1, 깊이 1짜리 박스가 천천히 회전하고, 빨강·초록·파랑 선으로 X·Y·Z 좌표축이 표시되는 화면입니다. 단순해 보이지만, three.js로 만드는 모든 3D 화면은 이 구조를 그대로 확장한 것입니다.
three.js의 3요소: 장면, 카메라, 렌더러
three.js로 화면에 무언가를 보여주려면 반드시 세 가지가 필요합니다. 사진 촬영에 비유하면 이해가 쉽습니다.

| 요소 | 사진 촬영 비유 | 구조해석 프로그램 비유 | 코드 |
|---|---|---|---|
| 장면 (Scene) | 피사체를 올려놓는 무대 | 절점·부재가 들어 있는 모델 공간 | new THREE.Scene() |
| 카메라 (Camera) | 어디서 어떤 렌즈로 찍을지 | 뷰 방향, 줌, 투시/평행 투영 설정 | new THREE.PerspectiveCamera() |
| 렌더러 (Renderer) | 찍은 사진을 인화하는 장치 | 모델을 모니터에 그려주는 그래픽 엔진 | new THREE.WebGLRenderer() |
마지막에 renderer.render(scene, camera) 한 줄이 "이 장면을, 이 카메라로 찍어서, 화면에 그려라"라는 명령입니다. 움직이는 화면은 이 명령을 1초에 수십 번 반복하는 것입니다.
전체 코드
먼저 전체 코드를 보고, 아래에서 번호(①~⑧)별로 설명하겠습니다. 1편과 마찬가지로 메모장에 붙여넣고 box.html로 저장한 뒤 더블클릭하면 브라우저에서 바로 실행됩니다.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>three.js 박스 하나 띄우기</title>
<style>
body { margin: 0; overflow: hidden; }
</style>
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.186.1/build/three.module.js"
}
}
</script>
</head>
<body>
<script type="module">
import * as THREE from 'three';
// ① 장면(Scene): 물체를 올려놓는 무대
const scene = new THREE.Scene();
scene.background = new THREE.Color(0xf0f3f6);
// ② 카메라(Camera): 무대를 바라보는 눈
const camera = new THREE.PerspectiveCamera(
50, // 시야각(도)
window.innerWidth / window.innerHeight, // 화면 가로세로 비율
0.1, // 이보다 가까운 것은 안 그림
100 // 이보다 먼 것은 안 그림
);
camera.position.set(2.5, 2, 4); // 카메라 위치 (x, y, z)
camera.lookAt(0, 0, 0); // 원점을 바라보기
// ③ 렌더러(Renderer): 카메라에 보이는 장면을 화면에 그려주는 장치
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// ④ 물체(Mesh) = 형상(Geometry) + 재질(Material)
const geometry = new THREE.BoxGeometry(2, 1, 1); // 가로 2, 높이 1, 깊이 1
const material = new THREE.MeshStandardMaterial({ color: 0x3f6e9e });
const box = new THREE.Mesh(geometry, material);
scene.add(box);
// ⑤ 조명: MeshStandardMaterial은 빛이 있어야 보인다
scene.add(new THREE.AmbientLight(0xffffff, 0.6)); // 전체를 은은하게
const light = new THREE.DirectionalLight(0xffffff, 2); // 햇빛처럼 한 방향
light.position.set(5, 8, 4);
scene.add(light);
// ⑥ 좌표축 표시 (빨강 X, 초록 Y, 파랑 Z)
const axes = new THREE.AxesHelper(2);
axes.setColors(0xff0000, 0x00aa00, 0x0000ff);
scene.add(axes);
// ⑦ 매 프레임마다 조금씩 돌리면서 다시 그리기
function animate() {
box.rotation.y += 0.01;
renderer.render(scene, camera);
}
renderer.setAnimationLoop(animate);
// ⑧ 창 크기가 바뀌면 비율 다시 맞추기
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
</script>
</body>
</html>
코드 한 줄씩 읽기
준비: three.js 불러오기 (importmap)
코드 위쪽의 <script type="importmap"> 부분은 "three라는 이름을 쓰면 이 인터넷 주소에서 가져와라"라는 약속입니다. 그래서 아래에서 import * as THREE from 'three' 한 줄로 three.js 전체를 THREE라는 이름으로 쓸 수 있게 됩니다. 버전(0.186.1)을 주소에 고정해 두면, 나중에 three.js가 업데이트되어도 이 코드는 그대로 동작합니다.
① 장면 (Scene)
빈 무대를 하나 만드는 줄입니다. scene.background로 배경색을 정합니다. 색은 0xf0f3f6처럼 16진수로 쓰는데, CSS의 #f0f3f6과 같은 색입니다.
② 카메라 (Camera)
three.js에서 가장 많이 쓰는 카메라는 원근감이 있는 PerspectiveCamera입니다. 괄호 안의 네 숫자가 각각 의미가 있습니다.
| 순서 | 값 | 의미 | 잘못 넣으면 |
|---|---|---|---|
| 1 | 50 | 시야각(FOV, 도). 렌즈의 화각 | 너무 크면 물체가 찌그러져 보임 |
| 2 | 가로/세로 | 화면 비율 | 물체가 옆으로 늘어나거나 눌려 보임 |
| 3 | 0.1 | near: 이보다 가까운 것은 안 그림 | 카메라 가까운 물체가 잘려 보임 |
| 4 | 100 | far: 이보다 먼 것은 안 그림 | 큰 교량 모델의 먼 쪽이 사라짐 |
시야각에 따라 같은 물체도 이렇게 다르게 보입니다. 세 장 모두 박스가 비슷한 크기로 보이도록 카메라 거리를 조정했습니다.

교량처럼 긴 구조물을 볼 때는 시야각을 너무 크게 잡으면 앞쪽 경간이 과장되어 보입니다. 보통 40~60도 정도가 자연스럽습니다.
그다음 camera.position.set(2.5, 2, 4)로 카메라를 놓고, camera.lookAt(0, 0, 0)으로 원점을 바라보게 합니다. 카메라의 위치와 바라보는 점, 이 두 가지만 정하면 시점이 결정됩니다.
③ 렌더러 (Renderer)
WebGLRenderer는 그래픽카드를 이용해 3D를 그려주는 장치입니다. antialias: true는 모서리의 계단 현상을 부드럽게 해주는 옵션입니다. setSize로 그림 크기를 브라우저 창 크기에 맞추고, appendChild로 그 그림판(canvas)을 웹 페이지에 붙입니다.
④ 물체 (Mesh) = 형상 + 재질
three.js에서 눈에 보이는 물체는 Mesh이고, Mesh는 항상 형상(Geometry)과 재질(Material)의 조합입니다. 구조 모델로 치면 "단면 형상"과 "재료 물성"을 따로 정의한 뒤 부재에 할당하는 것과 같은 구조입니다.
| 자주 쓰는 형상 | 만드는 법 | 교량 모델에서 쓰임 |
|---|---|---|
| BoxGeometry | 가로, 높이, 깊이 | 바닥판, 코핑, 직사각형 교각 |
| CylinderGeometry | 윗면 반지름, 아랫면 반지름, 높이 | 원형 교각, 말뚝 |
| ExtrudeGeometry | 2D 단면을 그려서 길이 방향으로 밀기 | I형 거더, 박스 거더 (5편에서 다룸) |
⑤ 조명
여기서 처음 하는 분들이 가장 많이 막힙니다. 재질 종류에 따라 조명이 없으면 물체가 아예 안 보일 수 있습니다.

| 재질 | 조명 필요 | 특징 |
|---|---|---|
| MeshBasicMaterial | 필요 없음 | 단색으로 칠해짐. 면 구분이 안 돼서 입체감이 없음 |
| MeshStandardMaterial | 필요함 | 빛을 받는 방향에 따라 밝기가 달라져 입체감이 있음. 금속감·거칠기 표현 가능 |
예제에서는 두 종류의 조명을 썼습니다. AmbientLight는 모든 면을 고르게 밝혀서 그림자 쪽이 새까맣게 되는 것을 막고, DirectionalLight는 햇빛처럼 한 방향에서 비춰서 면마다 밝기 차이를 만듭니다. 두 개를 같이 쓰는 것이 가장 무난한 조합입니다.
⑥ 좌표축과 three.js 좌표계
AxesHelper는 원점에 X(빨강), Y(초록), Z(파랑) 축을 그려주는 도우미입니다. 개발할 때 켜두면 방향을 헷갈리지 않습니다.
여기서 구조 엔지니어가 꼭 알아야 할 차이가 있습니다.

three.js는 Y축이 위쪽입니다. 반면 MIDAS 같은 구조해석 프로그램은 대부분 Z축이 위쪽이죠. 해석 모델의 절점 좌표를 그대로 가져와 그리면 교량이 옆으로 누워 버립니다. 좌표를 가져올 때는 (x, y, z) → (x, z, -y)처럼 바꿔주거나, 모델 전체를 X축 기준으로 -90도 회전시켜야 합니다. 이 부분은 나중에 해석 결과를 3D로 띄울 때 다시 다루겠습니다.
단위는 three.js에 따로 정해진 것이 없습니다. 1을 1m로 볼지 1mm로 볼지는 만드는 사람이 정하면 됩니다. 이 연재에서는 1 = 1m로 통일하겠습니다.
⑦ 애니메이션 루프
renderer.setAnimationLoop(animate)는 "화면을 새로 그릴 때마다 animate 함수를 실행하라"는 뜻입니다. 보통 1초에 60번 정도 실행됩니다. animate 안에서 box.rotation.y += 0.01로 박스를 Y축(위쪽 축) 기준으로 조금씩 돌리고, 다시 그립니다. 회전 단위는 도가 아니라 라디안이라서, 0.01은 약 0.57도입니다.
⑧ 창 크기 대응
브라우저 창 크기를 바꿨을 때 화면 비율이 틀어지지 않도록 카메라 비율과 렌더러 크기를 다시 맞춰주는 부분입니다. 비율을 바꾼 뒤에는 꼭 camera.updateProjectionMatrix()를 호출해야 적용됩니다.
숫자를 바꿔보며 실험하기
코드를 이해하는 가장 빠른 방법은 직접 숫자를 바꿔보는 것입니다. 하나씩 바꾸고 저장한 뒤 새로고침해 보세요.
| 바꿀 곳 | 바꿔볼 값 | 일어나는 일 |
|---|---|---|
BoxGeometry(2, 1, 1) |
(10, 0.3, 2) |
길고 얇은 판 모양. 바닥판처럼 보임 (화면 밖으로 나가면 카메라를 멀리) |
camera.position.set(2.5, 2, 4) |
(0, 6, 0.01) |
위에서 내려다보는 평면도 시점 |
PerspectiveCamera(50, ...) |
20 또는 100 |
줌인 / 광각 왜곡 |
color: 0x3f6e9e |
0xb8bcc2 |
콘크리트 같은 회색 |
rotation.y += 0.01 |
rotation.x += 0.01 |
앞으로 구르듯 회전 |
DirectionalLight(0xffffff, 2) |
이 줄과 아래 두 줄 삭제 | 입체감이 사라지고 면 구분이 안 됨 |
화면이 안 나올 때 체크리스트
| 증상 | 원인 | 해결 |
|---|---|---|
| 화면이 하얗기만 함 | 코드 오류로 실행이 멈춤 | F12 → Console 탭의 빨간 오류 메시지를 확인하고, 그대로 복사해서 Claude에게 붙여넣기 |
| 물체가 새까맣게 보임 | 조명 없이 StandardMaterial 사용 | ⑤ 조명 코드 확인 |
| 배경만 보이고 물체가 없음 | 카메라가 물체 안에 있거나 다른 곳을 바라봄 | camera.position을 멀리, lookAt을 물체 위치로 |
| 한글이 깨짐 | 파일 인코딩 문제 | 메모장 저장 시 인코딩을 UTF-8로 |
| "Failed to resolve module" 오류 | 인터넷 연결 끊김 또는 importmap 오타 | 인터넷 연결과 importmap 주소 확인 |
Claude에게 이렇게 물어보세요
코드를 읽다가 모르는 부분이 나오면, 그 부분만 복사해서 이렇게 질문하면 됩니다.
아래 three.js 코드를 구조 엔지니어가 이해하기 쉽게 한 줄씩 설명해줘. 구조해석 프로그램에 비유할 수 있는 부분은 비유해서 설명해줘.
(코드 붙여넣기)
"구조 엔지니어에게 설명하듯"처럼 내 배경을 알려주면 설명의 수준과 비유가 확 달라집니다. 이런 프롬프트 요령은 4편에서 따로 정리하겠습니다.
정리
- three.js 화면은 장면 + 카메라 + 렌더러 세 가지로 이루어진다.
- 보이는 물체는 Mesh = 형상(Geometry) + 재질(Material).
- StandardMaterial은 조명이 없으면 안 보인다.
- three.js는 Y축이 위. 구조해석 프로그램(Z-up)과 다르니 좌표 변환에 주의.
- 단위는 정하기 나름. 이 연재는 1 = 1m.
다음 편 예고
지금은 박스가 혼자 돌기만 하고 마우스로 움직일 수 없습니다. 3편에서는 OrbitControls로 마우스 회전·확대·이동을 붙이고, 조명 종류와 그림자를 다뤄서 1편의 교량을 훨씬 보기 좋게 만들어 보겠습니다.
따라 하다가 막히는 부분은 댓글로 남겨주세요.
관련 글
→ [교량 BIM 바이브코딩 1편] three.js 입문: Claude 바이브코딩으로 3D 교량 만들기
→ [교량 BIM 바이브코딩 3편] OrbitControls·조명·그림자
→ [교량 BIM 바이브코딩 4편] AI 코딩 프롬프트 작성법: Claude에게 3D 모델 정확히 요청하기
→ [교량 BIM 바이브코딩 5편] three.js ExtrudeGeometry: I형 거더 단면 3D 모델링
→ [교량 BIM 바이브코딩 6편] three.js 파라메트릭 모델링: 슬라이더로 바뀌는 교량
→ [교량 BIM 바이브코딩 7편] three.js 교량 BIM 모델: 클릭하면 속성이 나오는 부재 조립
→ [교량 BIM 바이브코딩 8편] three.js 곡선교 모델링: 곡선 반경 R과 편경사로 휘는 교량
'엔지니어링 코딩 > three.js·AI 코딩' 카테고리의 다른 글
| AI 코딩 프롬프트 작성법: Claude에게 3D 모델 정확히 요청하기 [교량 BIM 바이브코딩 4편] (0) | 2026.10.07 |
|---|---|
| three.js ExtrudeGeometry: I형 거더 단면 3D 모델링 [교량 BIM 바이브코딩 5편] (0) | 2026.10.07 |
| three.js OrbitControls·조명·그림자: 마우스로 돌려보는 교량 모델 [교량 BIM 바이브코딩 3편] (0) | 2026.10.07 |
| 토목 엔지니어가 자바스크립트와 Three.js를 배워야 하는 이유 (0) | 2026.10.05 |
| three.js 입문: Claude 바이브코딩으로 3D 교량 만들기 [교량 BIM 바이브코딩 1편] (0) | 2026.10.05 |
