개발자일기/3D 웹 세상

Three.js의 기본 개념과 원리

뫙뭉 2024. 11. 6. 12:20
반응형
반응형

3D 그래픽을 웹에서 구현하는 데 가장 널리 사용되는 도구 중 하나가 Three.js다. Three.js는 복잡한 3D 그래픽을 쉽게 구현할 수 있도록 도와주는 JavaScript 라이브러리로, WebGL의 복잡한 코드를 더 간편하게 작성할 수 있게 해준다. 이번 글에서는 Three.js의 기본 개념과 원리를 이해하기 쉽게 설명해 보겠다.

 

이전 글

1. [개발자일기/3D 웹 세상] - 웹에서의 3D 그래픽

2. [개발자일기/3D 웹 세상] - GPU와 렌더링의 관계: GPU가 하는 일

 


 

Three.js란 무엇인가?

Three.js는 JavaScript 기반의 3D 그래픽 라이브러리로, 개발자가 WebGL의 복잡한 코드를 직접 작성하지 않고도 3D 그래픽을 구현할 수 있게 도와준다. WebGL을 직접 사용하려면 수많은 코드와 수학적 계산이 필요하지만, Three.js는 이를 간단하게 줄여 주어 3D 장면을 웹 브라우저에서 쉽게 렌더링할 수 있도록 해 준다.

Three.js를 사용하면 3D 객체의 생성과 배치, 애니메이션, 조명과 그림자 효과 등을 간단한 코드로 처리할 수 있어, 웹 개발자들이 3D 그래픽을 웹 페이지에 쉽게 통합할 수 있다.

 


 

Three.js 이전의 JavaScript 3D 그래픽 구현 방식과 Three.js의 강점

Three.js가 등장하기 전에도 JavaScript를 이용해 3D 그래픽을 웹에서 구현하려는 다양한 시도들이 있었다. 그러나 당시의 기술들은 복잡하고 성능이 낮아 실제로 3D 그래픽을 구현하는 데 어려움이 많았다. 아래에서는 Three.js가 나오기 전에 사용된 대표적인 기술과, Three.js가 가진 장점을 비교해 보겠다.

 

1) HTML5 캔버스(Canvas)와 SVG를 이용한 3D 구현

Three.js가 등장하기 전, HTML5 CanvasSVG(Scalable Vector Graphics)를 활용하여 3D 그래픽을 구현하려는 시도가 있었다. HTML5 Canvas는 JavaScript와 함께 사용하여 픽셀 단위로 그래픽을 그릴 수 있는 기능을 제공하고, SVG는 벡터 기반의 그래픽을 웹에서 표현할 수 있게 한다. 그러나 두 방식 모두 2D 그래픽에 최적화되어 있어, 실제 3D 그래픽을 표현하려면 매우 복잡한 수학적 계산이 필요했다.

  • HTML5 Canvas는 단순한 2D 드로잉 API를 제공하기 때문에, 실제 3D 그래픽을 구현하려면 수학적으로 좌표를 변환하고 투영하는 방식을 직접 코딩해야 한다.
  • SVG는 벡터 이미지를 표현할 수 있으나, 3D 객체의 회전이나 투영, 조명 효과를 표현하기에는 한계가 많았다. 3D 느낌을 구현하기 위해서는 수많은 요소를 수동으로 계산해야 했으며, 실시간 렌더링에는 부적합했다.

 

2) WebGL과 Three.js의 등장

이후 WebGL이 등장하면서 3D 그래픽을 웹에서 실시간으로 구현하는 것이 가능해졌다. WebGL은 GPU를 통해 3D 그래픽을 렌더링할 수 있는 기능을 제공하지만, WebGL을 직접 다루는 것은 여전히 어려운 작업이다. WebGL에서는 모든 객체와 애니메이션을 수동으로 정의하고, 복잡한 셰이더 프로그램을 작성해야 하기 때문에, JavaScript만으로 구현하기에는 진입 장벽이 높았다.

Three.js는 WebGL의 복잡한 API를 간소화하여, 직관적인 명령어로 3D 객체를 만들고 렌더링할 수 있게 만든 JavaScript 라이브러리이다. 이를 통해 JavaScript 개발자들은 WebGL을 직접 다루지 않아도, Three.js의 간편한 API를 이용해 손쉽게 3D 그래픽을 웹에서 구현할 수 있게 되었다.

 

3) Three.js의 강점과 특징

Three.js는 JavaScript로 3D 그래픽을 구현하기 위해 필요한 기능들을 패키지화하여 제공하며, 간단하고 직관적인 문법을 통해 개발자가 빠르게 3D 그래픽을 만들 수 있도록 돕는다. Three.js가 가진 주요 강점은 다음과 같다.

  • 복잡한 수학적 계산을 자동 처리: Three.js는 WebGL에서 필요한 복잡한 수학적 변환을 자동으로 수행하여, 개발자가 좌표 변환과 투영 계산에 신경 쓰지 않고 3D 객체를 배치하고 이동할 수 있게 해 준다.
  • 쉽게 사용할 수 있는 기본 객체와 재질 제공: 큐브, 구, 원통 등의 기본 기하체와 다양한 재질(Material)을 제공하여, 3D 모델을 빠르게 생성할 수 있다.
  • 조명과 카메라 기능 내장: Three.js는 조명 효과와 다양한 종류의 카메라를 내장하고 있어, 현실감 있는 장면을 쉽게 구성할 수 있다.
  • 호환성과 성능 최적화: Three.js는 WebGL을 기반으로 하고 있어 대부분의 최신 웹 브라우저에서 호환되며, GPU 가속을 활용해 성능이 최적화되어 있다. 이를 통해 높은 프레임 속도로 실시간 3D 그래픽을 구현할 수 있다.

이와 같은 장점 덕분에 Three.js는 현재 웹에서 3D 그래픽을 구현할 때 가장 널리 사용되는 라이브러리로 자리 잡았다. WebGL의 복잡한 부분을 추상화하고, 손쉬운 API로 3D 그래픽을 다룰 수 있게 만들어 주었기 때문에, Three.js는 초보 개발자부터 전문가까지 모두가 쉽게 사용할 수 있는 도구로 인정받고 있다.

 


 

Three.js의 주요 구성 요소

Three.js로 3D 그래픽을 구현하기 위해서는 기본적으로 장면(Scene), 카메라(Camera), 렌더러(Renderer)라는 세 가지 주요 구성 요소가 필요하다. 각 요소는 3D 그래픽을 화면에 표현하는 데 필수적이다.

 

1) 장면(Scene)

장면은 Three.js에서 3D 객체를 배치하고 관리하는 공간이다. 장면은 실제로 3D 객체가 배치되는 가상의 세계로, 각 객체의 위치와 상호작용을 지정하는 공간을 의미한다. 예를 들어, 장면에 큐브나 구 같은 3D 모델을 추가하고, 이를 위치나 회전, 크기를 조정하여 화면에 표시할 수 있다.

Three.js에서는 장면에 배치된 객체들의 정보를 저장하고, 렌더링을 통해 화면에 표시되도록 한다.

const scene = new THREE.Scene();

 

2) 카메라(Camera)

 

카메라는 장면을 특정 각도에서 바라보는 역할을 한다. 3D 그래픽에서 카메라는 관찰자의 위치와 각도를 지정하며, 어떤 객체가 어떻게 보일지 결정한다. Three.js에서는 여러 종류의 카메라가 있지만, 주로 원근 카메라(Perspective Camera)정사각형 카메라(Orthographic Camera)를 사용한다.

  • 원근 카메라: 인간의 시각처럼 가까운 객체는 크게, 먼 객체는 작게 보이도록 표현한다.
  • 정사각형 카메라: 모든 객체를 동일한 크기로 보이도록 한다. 주로 건축 설계 같은 정확한 3D 모델링에 사용된다.

카메라는 3D 장면에서 특정 위치에 배치되어, 장면을 보는 관점(view)을 제공하는 역할을 한다.

 

const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5;

 

3) 렌더러(Renderer)

 

렌더러는 Three.js 장면을 실제로 화면에 그리는 역할을 한다. 렌더러는 GPU를 사용하여 3D 객체를 2D 화면에 표시하며, 장면의 객체들이 사용자에게 보이도록 렌더링 과정을 수행한다. Three.js에서 주로 사용하는 렌더러는 WebGLRenderer로, WebGL을 기반으로 그래픽을 처리하여 브라우저에서 3D 그래픽을 부드럽게 표시할 수 있다.

렌더러는 매 프레임마다 장면을 렌더링하며, 애니메이션이 필요한 경우에도 렌더링 과정을 반복 수행하여 객체의 움직임을 표현한다.

const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

 

 


 

Three.js의 주요 객체와 속성

 

Three.js에서 3D 장면을 더욱 현실감 있게 만들기 위해 메시(Mesh), 재질(Material), 조명(Light) 등의 요소가 사용된다. 이러한 요소들은 장면(Scene)에 추가되어 객체들이 어떻게 보일지, 그리고 빛이 어떻게 반사되고 그림자가 생길지를 결정한다.

 

1) 메시(Mesh)

 

메시(Mesh)는 3D 객체의 형태와 재질을 포함한 객체로, 장면에 추가되어 화면에 표시되는 3D 모델을 의미한다. 메시 객체는 기하체(Geometry)재질(Material)로 구성되며, 예를 들어, 큐브 모양의 기하체와 색상 재질을 적용하면 빨간색 큐브가 화면에 표시된다.

const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial({ color: 0xff0000 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

 

2) 재질(Material)

 

재질(Material)은 객체의 표면에 적용되는 속성으로, 색상, 질감, 투명도 등을 정의한다. 재질에 따라 객체가 매끄럽게 보이거나, 빛을 반사하거나, 투명하게 보일 수 있다. Three.js에는 여러 종류의 재질이 있어, 각 객체의 특징에 맞게 다양한 표현을 할 수 있다.

  • MeshBasicMaterial: 빛의 영향을 받지 않는 기본 재질. 주로 단순한 색상을 표현할 때 사용된다.
  • MeshPhongMaterial: 빛 반사와 하이라이트가 적용된 재질로, 빛의 방향에 따라 반짝이는 효과를 낼 수 있다.
  • MeshStandardMaterial: 현실적인 조명 효과를 구현할 수 있는 재질로, 반사와 그림자를 표현할 수 있어 사실적인 장면에 적합하다.

 

3) 조명(Light)

 

조명은 3D 그래픽에서 빛의 역할을 한다. Three.js에서는 다양한 조명 옵션을 제공하여, 각기 다른 빛의 효과를 추가할 수 있다. 조명이 없으면 모든 객체가 어두워 보이기 때문에, 3D 장면에 조명을 추가하여 입체감과 사실감을 더할 수 있다.

  • Ambient Light: 장면 전체에 균일하게 빛을 비추는 조명.
  • Directional Light: 특정 방향으로 빛을 비추는 조명으로, 태양광과 비슷한 효과를 낸다.
  • Point Light: 특정 위치에서 사방으로 빛을 비추는 조명으로, 전구와 같은 점광원 효과를 낸다.
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(1, 1, 1).normalize();
scene.add(light);

 

Three.js의 렌더링 루프와 애니메이션

 

Three.js에서 애니메이션을 구현하기 위해서는 렌더링 루프를 설정해야 한다. 렌더링 루프는 매 프레임마다 장면을 업데이트하고, 변경된 장면을 화면에 다시 그리는 과정이다. Three.js에서는 requestAnimationFrame 함수를 통해 렌더링 루프를 구현할 수 있다.

예를 들어, 큐브가 계속 회전하도록 애니메이션을 설정할 수 있다.

function animate() {
  requestAnimationFrame(animate);
  cube.rotation.x += 0.01;
  cube.rotation.y += 0.01;
  renderer.render(scene, camera);
}

animate();

 

animate 함수는 매 프레임마다 requestAnimationFrame을 호출하여, 지속적으로 장면을 업데이트하고 렌더링하는 루프를 만든다. 이를 통해 3D 객체에 애니메이션 효과를 줄 수 있으며, 실시간으로 변화하는 장면을 표현할 수 있다.

 


 

프로젝트 코드: React에서 Three.js로 간단한 3D 큐브 렌더링

 

이 예제에서는 React의 useEffect 훅을 사용하여 컴포넌트가 처음 렌더링될 때 Three.js의 Scene, Camera, Renderer를 초기화하고, 애니메이션 루프를 통해 큐브를 회전시킨다.

 

1. 프로젝트에 필요한 패키지를 설치

npm install three

 

2. React의 App.jsx

// App.jsx
import React, { useRef, useEffect } from "react";
import * as THREE from "three";

const App = () => {
  const mountRef = useRef(null);

  useEffect(() => {
    // Scene, Camera, 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);
    mountRef.current.appendChild(renderer.domElement);

    // 큐브 생성
    const geometry = new THREE.BoxGeometry();
    const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
    const cube = new THREE.Mesh(geometry, material);
    scene.add(cube);

    // 애니메이션 함수
    const animate = () => {
      requestAnimationFrame(animate);
      cube.rotation.x += 0.01;
      cube.rotation.y += 0.01;
      renderer.render(scene, camera);
    };

    animate();

    // 클린업 함수로 DOM에서 렌더러 제거
    return () => {
      mountRef.current.removeChild(renderer.domElement);
    };
  }, []);

  return <div ref={mountRef} />;
};

export default App;

 

 

  • Scene, Camera, Renderer 생성: Three.js의 기본 요소인 장면(Scene), 카메라(Camera), 렌더러(Renderer)를 생성하여 초기화한다.
  • 큐브 생성: BoxGeometry와 MeshBasicMaterial을 사용해 초록색 큐브를 생성하고, 장면(Scene)에 추가한다.
  • 애니메이션 루프: requestAnimationFrame을 사용해 animate 함수를 반복 호출하여 큐브를 회전시키고 화면에 렌더링한다.
  • 클린업: useEffect의 클린업 함수에서 DOM에서 Three.js 렌더러를 제거한다.

 

실행하면 다음처럼 초록색 육면체가 돌고 있는 것을 확인할 수 있다.

 

 

애니메이션도 있지만 캡쳐화면으로 대신한다!

 


 

Three.js로 3D 그래픽을 쉽게 구현하는 이유

 

Three.js는 복잡한 WebGL 코드를 간단한 JavaScript 문법으로 작성할 수 있게 해준다. WebGL은 수학적 계산이 필요하고 코드가 복잡하지만, Three.js는 기본적인 구성 요소와 직관적인 API를 제공하여 3D 그래픽의 구현을 훨씬 간단하게 만들어 준다. 이러한 장점 덕분에 웹 개발자들은 Three.js를 사용하여 다양한 3D 그래픽 콘텐츠를 손쉽게 제작할 수 있다.

 


 

Three.js는 WebGL의 복잡한 부분을 간소화하면서, 웹에서도 고품질의 3D 그래픽을 쉽게 구현할 수 있도록 돕는 강력한 라이브러리다. Three.js를 활용해 웹에서 더욱 몰입감 있는 3D 그래픽을 경험할 수 있는 방법을 알아보자.

 
 
 
반응형