개요
Three.js Scene에 3D Text를 추가하는 방법을 알아봅니다. 3D Text는 단순히 정보를 보여주는 것을 넘어, 디버깅이나 인터랙티브한 경험을 만드는 데 매우 유용한 요소가 될 수 있습니다. 화면에 정보를 띄우는 디버그 UI의 3D 버전이라고 생각하면 쉽습니다.
TextureGeometry 사용법
3D 텍스트를 만들기 위해서는 먼저 폰트 파일을 로드하고, 이를 바탕으로 TextGeometry를 생성해야 합니다. Three.js는 자체적으로 폰트 파일을 가지고 있지 않기 때문에, 직접 폰트 파일을 프로젝트에 포함해야 합니다. Three.js에서 제공하는 기본 헬베티카(Helvetica) 폰트를 사용해 보겠습니다.
- /node_modules/three/examples/fonts/ 경로에서 helvetiker_regular.typeface.json 파일과 LICENSE 파일을 복사합니다.
- 프로젝트의 /static/fonts/ 폴더를 만들고 그 안에 붙여넣습니다.
이제 이 폰트 파일을 코드에서 로드해야 합니다. FontLoader를 사용하면 폰트를 쉽게 가져올 수 있습니다.
import * as THREE from "three";
import { FontLoader } from "three/examples/jsm/loaders/FontLoader.js";
import { TextGeometry } from "three/examples/jsm/geometries/TextGeometry.js";
const fontLoader = new FontLoader();
해당 코드는 Three.js 버전마다 다르니 확인해보시는 것을 권장합니다.
지오메트리, 머터리얼, 메시 생성하기
FontLoader의 load 메서드를 사용하여 폰트를 비동기적으로 로드합니다. 로드가 완료되면 콜백 함수 안에서 TextGeometry를 생성하고, 이를 이용해 메시(Mesh)를 만들어 Scene에 추가할 수 있습니다.
fontLoader.load("/fonts/helvetiker_regular.typeface.json", font => {
// 1. TextGeometry 생성
const textGeometry = new TextGeometry("Hello Three.js", {
font: font,
size: 0.5,
depth: 0.2, // Three.js 163+ 에서는 height 대신 depth 사용
curveSegments: 12,
bevelEnabled: true,
bevelThickness: 0.03,
bevelSize: 0.02,
bevelOffset: 0,
bevelSegments: 5,
});
// 2. Material 생성
const textMaterial = new THREE.MeshBasicMaterial();
// 3. Mesh 생성 및 Scene에 추가
const text = new THREE.Mesh(textGeometry, textMaterial);
scene.add(text);
});
이제 Scene의 (0, 0, 0) 좌표에서 "Hello Three.js:라는 3D Text가 나타나는 것을 확인할 수 있습니다.
최적화
wireframe을 활성화해서 보면 텍스트가 얼마나 많은 정점(vertex)으로 이루어져 있는지 알 수 있습니다.
textMaterial.wireframe = true;
정점이 많을수록 렌더링에 부담이 됩니다. curveSegments와 bevelSegments의 값을 줄이면 정점의 수를 줄여 성능을 최적화할 수 있습니다.
- curveSegments: 텍스트 곡선 부분을 얼마나 부드럽게 표현할지 결정
- bevelSegments: 텍스트의 모서리(bevel)를 얼마나 부드럽게 표현할지 결정
const textGeometry = new TextGeometry("Hello Three.js", {
// ... (이전 속성)
curveSegments: 6, // 값을 줄임
bevelSegments: 3, // 값을 줄임
});
값을 낮추면 디테일은 확실히 떨어지지만, 눈에 띄지 않는 수준이라면 성능을 위해 과감히 줄이는 것이 좋습니다.
중심점 맞추기
생성된 텍스트의 기준점(pivot)은 기본적으로 왼쪽 아래에 위치합니다. 이는 회전이나 위치 이동 같은 변형(transform)을 적용할 때 매우 불편합니다. 마치 사람의 몸을 발목을 기준으로 중심을 잡는 것처럼 말이죠. 애니메이션이나 쉐이딩 작업시 문제를 일으킬 수 있으므로, 객체의 중심으로 기준점을 옮기는 것이 좋습니다.
- Bounding Box를 이용한 방법(수동)
Bound Box는 지오메트리를 감싸는 보이지 않는 상자로, 객체의 공간 정보를 담고 있습니다. computeBoundigBox() 메서드를 호출하여 생성할 수 있습니다. 이 박스의 min과 max 좌표를 이용해 중심을 계산하고, translate() 메서드로 지오메토리 자체를 이동시킬 수 있습니다.
// Bounding Box 계산
textGeometry.computeBoundingBox();
// Bounding Box 정보를 이용해 중심으로 이동
textGeometry.translate(
-(textGeometry.boundingBox.max.x - textGeometry.boundingBox.min.x) * 0.5,
-(textGeometry.boundingBox.max.y - textGeometry.boundingBox.min.y) * 0.5,
-(textGeometry.boundingBox.max.z - textGeometry.boundingBox.min.z) * 0.5
);
- .center()
위처럼 복잡한 계산을 할 필요 없이 Three.js는 아주 편리한 메서드를 제공합니다.
// Bounding Box를 계산하고 중심으로 이동시키는 것을 한 번에!
textGeometry.center();
center() 메서드를 한 줄만 호출하면 지오메트ㅡ리가 정확히 자신의 중심에 위치하게 됩니다.
- 결과
스타일링 및 Scene 꾸미기
이제 텍스트에 멋진 재질을 입히고, 주변에 다른 객체들을 추가하여 Scene을 풍성하게 만들어 보겠습니다.
- Matcap Material 적용
Matcap (Material Capture) 머터리얼은 조명 없이도 객체의 질감을 효과적으로 표현할 수 있는 방법입니다. 마치 객체가 특정 재질의 구슬에 비친 것처럼 보이게 하죠.
const textureLoader = new THREE.TextureLoader();
const matcapTexture = textureLoader.load("/textures/matcaps/1.png");
matcapTexture.colorSpace = THREE.SRGBColorSpace;
const textMaterial = new THREE.MeshMatcapMaterial({ matcap: matcapTexture });
- Matcap Material 적용
Three.js를 보다보면 3D Text에 도넛(Torus)이 여러 개 배치된 Scene들이 존재합니다. 반복문을 사용해 무작위로 배치해 봅시다.
console.time("donuts"); // 성능 측정 시작
// Geometry와 Material은 반복문 밖에서 한 번만 생성 (성능 최적화!)
const donutGeometry = new THREE.TorusGeometry(0.3, 0.2, 20, 45);
const donutMaterial = new THREE.MeshMatcapMaterial({ matcap: matcapTexture });
for (let i = 0; i < 100; i++) {
const donut = new THREE.Mesh(donutGeometry, donutMaterial);
// 위치 랜덤화 (-5 ~ 5 사이)
donut.position.x = (Math.random() - 0.5) * 10;
donut.position.y = (Math.random() - 0.5) * 10;
donut.position.z = (Math.random() - 0.5) * 10;
// 회전 랜덤화
donut.rotation.x = Math.random() * Math.PI;
donut.rotation.y = Math.random() * Math.PI;
// 크기 랜덤화 (비율 유지)
const scale = Math.random();
donut.scale.set(scale, scale, scale);
scene.add(donut);
}
console.timeEnd("donuts"); // 성능 측정 종료
반복문 안에서 new THREE.TorusGeometry()와 new THREE.MeshMatcapMaterial()를 계속 호출하면 도넛 100개에 대해 100개의 지오메트리와 100개의 머터리얼이 생성됩니다. 이는 성능 저하의 주된 원인입니다. 위 코드처럼 지오메트리와 머터리얼은 반복문 밖에서 한 번만 생성하고, Mesh 만 새로 만들어 재사용하는 것이 훨씬 효율적입니다.
결론
이번 포스트에서는 Three.js를 사용하여 씬에 3D 텍스트를 추가하는 전반적인 과정을 살펴보았습니다.
FontLoader와 TextGeometry를 사용해 텍스트를 생성하는 기본 방법부터, curveSegments와 bevelSegments 값을 조절하여 렌더링 성능을 최적화하는 방법까지 알아보았습니다. 또한, .center() 메서드를 활용해 객체의 중심점을 손쉽게 맞춰 변형을 용이하게 만드는 실용적인 팁도 다루었습니다.
마지막으로 MatCap 머티리얼로 텍스트에 생동감을 불어넣고, 여러 개의 객체를 효율적으로 추가하기 위해 지오메트리와 머티리얼을 재사용하는 중요한 최적화 기법까지 확인했습니다.
3D 텍스트는 단순히 정보를 전달하는 수단을 넘어, 여러분의 프로젝트에 예술적인 감각과 개성을 더하는 강력한 도구입니다. 오늘 배운 내용을 바탕으로 자신만의 3D 씬을 더욱 풍부하고 인터랙티브하게 만들어 보시길 바랍니다.
'Three.js > Intro' 카테고리의 다른 글
[threejs-journey 1-11] Material (5) | 2025.06.27 |
---|---|
[threejs-journey 1-10] Texture (0) | 2025.06.25 |
[threejs-journey 1-9] Debug UI (0) | 2025.06.22 |
[threejs-journey 1-8] Geometries (0) | 2025.06.16 |
[threejs-journey 1-7] Resizing & FullScreen (0) | 2025.06.12 |