Three.js 입문 가이드: 처음부터 멋진 예제까지

Three.js는 웹에서 3D 그래픽을 쉽게 구현할 수 있게 해주는 JavaScript 라이브러리입니다. 복잡한 WebGL을 추상화하여 개발자가 3D 그래픽에 집중할 수 있게 해줍니다. 이 포스팅에서는 Three.js를 처음 접하는 분들을 위해 기초부터 멋진 예제를 만들어가는 과정을 단계별로 설명하겠습니다.

1. Three.js 시작하기

기본 셋업

Three.js를 사용하기 위한 기본 HTML 구조부터 시작해봅시다:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>My First Three.js App</title>
    <style>
        body { margin: 0; overflow: hidden; }
        canvas { display: block; }
    </style>
</head>
<body>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
    <script>
        // Three.js 코드가 여기에 들어갑니다
    </script>
</body>
</html>

기본 구성요소 이해하기

Three.js로 무언가를 렌더링하기 위해 필요한 세 가지 핵심 요소가 있습니다:

  1. 장면(Scene): 모든 3D 객체가 배치되는 공간
  2. 카메라(Camera): 장면을 어떤 시점에서 볼지 결정
  3. 렌더러(Renderer): 장면과 카메라 정보를 받아 화면에 그려줌

다음은 이 세 요소를 설정하는 코드입니다:

// 장면 생성
const scene = new THREE.Scene();

// 카메라 생성 (시야각, 종횡비, 근거리 클리핑, 원거리 클리핑)
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5;

// 렌더러 생성 및 설정
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

2. 첫 번째 3D 객체 만들기

이제 간단한 큐브를 만들어 화면에 렌더링해 봅시다:

// 큐브 지오메트리와 재질 생성
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });

// 메시 생성 (지오메트리 + 재질)
const cube = new THREE.Mesh(geometry, material);
scene.add(cube); // 장면에 추가

// 애니메이션 루프 함수
function animate() {
    requestAnimationFrame(animate);
    
    // 큐브 회전
    cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;
    
    // 렌더링
    renderer.render(scene, camera);
}

animate();

이 코드는 초록색 큐브를 생성하고 지속적으로 회전시키는 애니메이션을 보여줍니다.

3. 재질과 조명 이해하기

앞서 만든 큐브는 MeshBasicMaterial을 사용했는데, 이 재질은 조명의 영향을 받지 않습니다. 조명을 추가하고 조명에 반응하는 재질을 사용해 봅시다:

// 기존 재질 대신 조명에 반응하는 재질 사용
const material = new THREE.MeshPhongMaterial({ color: 0x00ff00 });

// 조명 추가
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(5, 5, 5);
scene.add(light);

// 주변광 추가
const ambientLight = new THREE.AmbientLight(0x404040);
scene.add(ambientLight);

Three.js는 다양한 재질을 제공합니다:

  • MeshBasicMaterial: 조명에 반응하지 않는 단순 색상
  • MeshLambertMaterial: 비광택 표면에 적합
  • MeshPhongMaterial: 광택이 있는 표면에 적합
  • MeshStandardMaterial: 물리 기반 렌더링에 적합

4. 다양한 지오메트리 탐색하기

Three.js는 다양한 내장 지오메트리를 제공합니다:

// 구체
const sphereGeometry = new THREE.SphereGeometry(1, 32, 32);
const sphere = new THREE.Mesh(sphereGeometry, material);
sphere.position.x = -3;
scene.add(sphere);

// 원뿔
const coneGeometry = new THREE.ConeGeometry(1, 2, 32);
const cone = new THREE.Mesh(coneGeometry, material);
cone.position.x = 3;
scene.add(cone);

// 토러스(도넛)
const torusGeometry = new THREE.TorusGeometry(0.5, 0.2, 16, 100);
const torus = new THREE.Mesh(torusGeometry, material);
torus.position.y = 3;
scene.add(torus);

5. 텍스처 추가하기

단순한 색상 대신 텍스처를 사용하여 객체에 이미지를 입힐 수 있습니다:

// 텍스처 로더 생성
const textureLoader = new THREE.TextureLoader();

// 텍스처 로드 및 재질에 적용
const texture = textureLoader.load('https://example.com/texture.jpg');
const material = new THREE.MeshStandardMaterial({ map: texture });

// 텍스처가 적용된 큐브 생성
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

6. 사용자 상호작용 추가하기

OrbitControls를 사용하면 마우스로 카메라를 회전, 확대/축소할 수 있습니다:

<script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.js"></script>

그리고 JavaScript에서:

// 컨트롤 생성
const controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true; // 부드러운 애니메이션 효과
controls.dampingFactor = 0.05;

// 애니메이션 루프 함수 업데이트
function animate() {
    requestAnimationFrame(animate);
    
    // 컨트롤 업데이트
    controls.update();
    
    renderer.render(scene, camera);
}

7. 응답형 디자인 구현하기

브라우저 창 크기가 변경될 때 Three.js 캔버스도 조정되도록 합시다:

// 윈도우 크기 변경 이벤트 리스너
window.addEventListener('resize', () => {
    // 카메라 종횡비 업데이트
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    
    // 렌더러 크기 업데이트
    renderer.setSize(window.innerWidth, window.innerHeight);
});

8. 고급 예제: 인터랙티브 파티클 시스템

이제 좀 더 멋진 예제를 만들어 봅시다. 마우스 움직임에 반응하는 파티클 시스템을 구현해보겠습니다:

// 파티클 시스템 생성
const particlesGeometry = new THREE.BufferGeometry();
const particleCount = 5000;

// 파티클 위치 배열 생성
const positions = new Float32Array(particleCount * 3);
const colors = new Float32Array(particleCount * 3);

for (let i = 0; i < particleCount * 3; i++) {
    // 임의의 위치에 파티클 배치
    positions[i] = (Math.random() - 0.5) * 10;
    // 임의의 색상 설정
    colors[i] = Math.random();
}

particlesGeometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
particlesGeometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));

// 파티클 재질
const particlesMaterial = new THREE.PointsMaterial({
    size: 0.05,
    vertexColors: true,
    transparent: true,
    opacity: 0.8
});

// 파티클 메시 생성
const particles = new THREE.Points(particlesGeometry, particlesMaterial);
scene.add(particles);

// 마우스 움직임 추적
const mouse = new THREE.Vector2();
window.addEventListener('mousemove', (event) => {
    // 마우스 좌표를 정규화 (-1 ~ 1 범위)
    mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
    mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;
});

// 애니메이션 루프 업데이트
function animate() {
    requestAnimationFrame(animate);
    
    // 파티클 움직임 업데이트
    const positions = particlesGeometry.attributes.position.array;
    
    for (let i = 0; i < particleCount; i++) {
        const i3 = i * 3;
        
        // 마우스 위치에 따라 파티클 이동
        positions[i3] += (mouse.x * 0.02) + (Math.random() - 0.5) * 0.01;
        positions[i3 + 1] += (mouse.y * 0.02) + (Math.random() - 0.5) * 0.01;
        
        // 경계 체크
        if (positions[i3] > 5) positions[i3] = -5;
        if (positions[i3] < -5) positions[i3] = 5;
        if (positions[i3 + 1] > 5) positions[i3 + 1] = -5;
        if (positions[i3 + 1] < -5) positions[i3 + 1] = 5;
    }
    
    particlesGeometry.attributes.position.needsUpdate = true;
    
    // 파티클 전체 회전
    particles.rotation.x += 0.001;
    particles.rotation.y += 0.002;
    
    renderer.render(scene, camera);
}

9. 다음 단계: Three.js 마스터하기

Three.js의 기본 개념을 이해했다면, 다음 단계로 탐색해볼 수 있는 주제들입니다:

  1. 쉐이더 프로그래밍: GLSL을 사용하여 커스텀 비주얼 효과 만들기
  2. 물리 엔진 통합: Cannon.js나 Ammo.js 같은 물리 엔진과 Three.js 통합하기
  3. 후처리 효과: 블룸, 모션 블러, 깊이 효과 등 적용하기
  4. 3D 모델 불러오기: glTF, OBJ, FBX 등의 포맷으로 된 3D 모델 불러오기
  5. VR/AR 지원: WebXR API를 통한 가상 현실/증강 현실 구현하기

결론

Three.js는 강력하고 유연한 3D 라이브러리로, 웹에서 인상적인 3D 경험을 구현할 수 있게 해줍니다. 이 포스팅에서는 기본 개념부터 시작하여 점차 고급 기능으로 나아가며 Three.js의 기초를 다뤘습니다.

멋진 Three.js 예제들은 상상력의 한계만큼 다양하게 만들 수 있습니다. 공식 웹사이트(https://threejs.org/)의 예제를 참고하고, 다양한 속성과 기능을 실험해보면서 자신만의 멋진 3D 웹 경험을 만들어보세요!

여러분만의 Three.js 작품을 만들어 공유해주세요. 행운을 빕니다! 🚀

코멘트

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다