3D 웹의 로망을 가지고 시작하는 three.js 개념과 구조를 알아보자. 공식문서를 통해 공부하는 것도 좋다.
three.js는 자바스크립트 라이브러리이다. webGl을 기반으로 만들어 졌으며, 단순히 점, 선 등을 그리는 단순한 시스템이다. webGl로 3D를 구현하려면 매우 많은 코드를 작성해야 하는 불편함이 있다. 이를 위해 three.js가 등장한다.
three.js는 크게 Renderer, Scene, Camera로 구성된다.

렌더러는 3D 장면을 2D 화면에 그려주는 역할을 합니다. Three.js에서는 WebGLRenderer를 사용하여 웹 페이지의 canvas 요소에 3D 장면을 렌더링한다.
카메라는 장면을 보는 시점을 정의한다.
카메라 속성에는 fov, aspect, near, far의 속성이 존재한다.
fov (Field of View)
카메라의 수직 시야각으로 단위는 도(degree)입니다. 값이 클수록 더 넓은 시야를 가지며, 값이 작을수록 더 좁은 시야를 가집니다.
aspect (Aspect Ratio)
카메라의 종횡비(너비 대 높이 비율)를 정의합니다.
near (Near Clipping Plane)
카메라에서부터 이 거리보다 가까운 객체는 렌더링되지 않습니다.
far (Far Clipping Plane)
카메라에서부터 이 거리보다 먼 객체는 렌더링되지 않습니다.
Perspective Camera (원근 카메라)
원근 카메라는 절두체(피라미드를 수평으로 자른 형태) 모양이며, 인간의 눈과 비슷한 방식으로 물체를 렌더링합니다.

Orthographic Camera (정사영 카메라)
정사영 카메라는 직육면체 모양이며, 물체의 크기가 거리에 따라 달라지지 않습니다. 주로 2D 그래픽에 사용됩니다.

장면은 렌더링할 모든 객체를 포함하는 컨테이너입니다. 장면에는 메쉬, 조명, 카메라 등을 추가할 수 있습니다.
메쉬는 기하학적 형태(Geometry)와 재질(Material)을 결합한 객체입니다. 예를 들어, 구체 메쉬는 구체 기하학과 특정 재질을 결합하여 생성됩니다.
Geometry는 메쉬의 형태를 정의합니다. Three.js에서는 다양한 기본 기하학적 형태(원시 모델)를 제공합니다.
Geometry의 형태는 매우 다양하기 때문에 공식문서에서 확인하는 것이 좋다.
Material은 메쉬의 표면을 정의합니다. Three.js에서는 다양한 종류의 재질을 제공합니다.
텍스처는 메쉬의 표면을 덮는 이미지입니다. 텍스처를 사용하여 메쉬에 현실감 있는 외관을 부여할 수 있습니다.
조명은 장면의 메쉬가 어떻게 보이는지를 결정하는 데 중요한 요소입니다. 광원(Light)을 통해 장면이 더욱 생동감 있게 된다.
html의 script 태그의 module은 반드시 작성해줘야 하며, 뒤에 나오는 자바스크립트 코드를 script 태그로 연결해 주면 된다.
<body>
<canvas id="c"></canvas>
<script type="module" src="..."/>
</body>
PerspectiveCamera를 생성하고 속성을 지정한다.
const fov = 75;
const aspect = 2; // the canvas default
const near = 0.1;
const far = 5;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
큐브 모양의 메시를 만드려면 네모의 BoxGeometry와 MeshBasiceMaterial(색상, 질감, 재질 등)을 합쳐서 하나의 큐브 모양 Mesh를 만들게 된다.
//Geometry
const boxWidth = 1;
const boxHeight = 1;
const boxDepth = 1;
const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
//Material
const material = new THREE.MeshBasicMaterial({color: 0x44aa88});
//Mesh
const cube = new THREE.Mesh(geometry, material);
여러 메시 등을 그릴 수 있는 Scene에 앞서 생성한 큐브 모양 Mesh를 추가한 모습이다.
const scene = new THREE.Scene();
scene.add(cube);
canvas를 가져온 뒤, 렌더러를 생성한다. 렌더러에 장면과 카메라를 장착하면 Cube가 보이게 된다.
const canvas = document.querySelector('#c');
const renderer = new THREE.WebGLRenderer({antialias: true, canvas});
renderer.render(scene, camera);
import * as THREE from 'three';
function main() {
const canvas = document.querySelector( '#c' );
const renderer = new THREE.WebGLRenderer( { antialias: true, canvas } );
const fov = 75;
const aspect = 2; // the canvas default
const near = 0.1;
const far = 5;
const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
camera.position.z = 2;
const scene = new THREE.Scene();
const boxWidth = 1;
const boxHeight = 1;
const boxDepth = 1;
const geometry = new THREE.BoxGeometry( boxWidth, boxHeight, boxDepth );
const material = new THREE.MeshBasicMaterial( { color: 0x44aa88 } );
const cube = new THREE.Mesh( geometry, material );
scene.add( cube );
// 애니메이션 없어 그리기
renderer.render( scene, camera );
// 만약 회전하는 애니메이션을 적용하여 그리기
function render( time ) {
time *= 0.001; // convert time to seconds
cube.rotation.x = time;
cube.rotation.y = time;
renderer.render( scene, camera );
requestAnimationFrame( render );
}
requestAnimationFrame( render );
}
main();
다음과 같은 사항을 준수하면 three.js를 좀 더 올바르게 작동할 수 있다. 요약하자면, 최신 ES문법을 사용하자는 내용이다.
const someObject = {
width: 300,
height: 150,
};
for (const [key, value] of Object.entries(someObject)) {
console.log(key, value);
}
[1, 2, 3, 4].forEach((ele, idx) => {
console.log(ele, idx);
}
const dims = { width: 300, height: 150 }
const { width, height } = dims;
const width = 300;
const height = 150;
const obj = {
width,
height,
area() {
return this.width * this.height;
},
};
const position = [1, 2, 3];
mesh.position.set(...position);
리액트로 three.js를 사용할 수 있는 라이브러리도 존재한다. R3F로 줄여 말하기도 하며, R3F를 통해 리액트로 간편하게 구현이 가능하다.
R3F에서 더 나아가, 다양한 라이브러리들이 더 존재한다.
가장 유용하게 사용되는 라이브러리이며, R3F를 기반으로 매우 다양한 기능들을 제공한다. 예를 들어 코드 한 줄로 마우스를 사용해 카메라 움직이기, 키보드 또는 마우스 컨트롤러, 다양한 모양 제공 등 매우 유용한 기능들이 제공된다.
3D Model에 물리 엔진을 적용시켜주는 라이브러리이며, 중력, 충돌 등의 기능을 제공한다. 비슷한 라이브러리로 r3f-cannon이 있다.
이 라이브러리에서 마인크래프트 같은 캐릭터 이동에 대한 예제도 제공된다.