본문 바로가기
Language/- JS & TS

Three.js 개념 및 기본 사용법 정리

by Yoojacha 2023. 8. 13.

Three.js

WebGL 기술을 사용하여 3D 랜더링 할 수 있는 라이브러리입니다.

개발 환경 구성

  • VS Code  에디터 사용
  • NVM으로 Node.js LTS 설치
  • Vite 빌드 도구

NVM 설치

가이드 링크

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.4/install.sh | bash
nvm ls : 설치된 node.js 버전 보임
nvm ls-remote : node.js 버전 출력
nvm ls-remote --lts : (LTS만 보기)
nvm install v16.13.2 (LTS 받기)
nvm use v16.13.2 (쓰고싶은 버전)
node -v : 버전 확인
sudo apt-get install sl (기차 나옴)

Vite 프로젝트 생성

npm create vite
npm i
npm i three
npm run dev

Three.js 주요 구성

Renderer

3D 씬을 그려주는 역할을 합니다. WebGL을 사용하여 하드웨어 가속 그래픽을 사용하여 브라우저에 그림을 표시합니다.

Scene

3D 장면을 구성하는 데 사용됩니다. 즉, 모든 3D 객체(메시, 조명 등)가 존재하는 공간입니다.

Camera

뷰 포인트를 정의하고 씬을 보는 시점을 결정합니다.

Light

조명은 씬 내부의 물체에 빛을 비추어 시각적인 효과를 생성하는 데 사용됩니다. 다양한 조명 유형(예: 주변광, 점광원, 방향성 광원)이 있습니다.

Mesh

지오메트리와 재질을 결합하여 실제로 렌더링되는 3D 모델을 나타냅니다. 메시는 씬에 추가되어 렌더링됩니다.

Geometry

3D 모델의 기하학적 모양(예: 정점, 면, 테두리)을 정의하는 데 사용됩니다. 지오메트리는 모델의 구조를 나타내며, 정점의 위치, 면의 정점 인덱스 등을 포함합니다.

Material

3D 모델의 외관을 결정하는 데 사용됩니다. 재질은 텍스처, 색상, 반사율 등을 정의하여 모델의 시각적 표현을 제어합니다.

Loader

외부 리소스(이미지, 모델 등)를 로드하여 애플리케이션에 통합할 수 있는 기능을 제공하는 클래스입니다.

클래스가 전달 되는 순서와 방향

 


Boilerplate Code / 시작 코드 예시

import * as THREE from 'three';

// 렌더러 생성
const renderer = new THREE.WebGLRenderer({
    antialias: true, // 계단현상 보완
});

renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement); // body 태그 안에 renderer 삽입

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

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

// 지오메트리 생성 (BoxGeometry)
const geometry = new THREE.BoxGeometry(1, 1, 1);

// 재질 생성 (MeshBasicMaterial)
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });

// 메시 생성 (지오메트리와 재질을 결합)
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

// 렌더링 함수 정의
function render() {
  requestAnimationFrame(render);

  // 큐브 회전
  cube.rotation.x += 0.01;
  cube.rotation.y += 0.01;

  // 씬과 카메라를 사용하여 렌더링
  renderer.render(scene, camera);
}

// 창 크기 변경 시 카메라 종횡비와 렌더러 크기 업데이트
function handleResize() {
  const newWidth = window.innerWidth;
  const newHeight = window.innerHeight;

  camera.aspect = newWidth / newHeight;
  camera.updateProjectionMatrix();

  renderer.setSize(newWidth, newHeight);
}

// 초기화 함수
function init() {
  render(); // 렌더링 시작
  window.addEventListener('resize', handleResize); // 창 크기 변경 이벤트 리스너 등록
}

// 초기화 함수 호출
init();

// // 바닐라 자바스크립트인 경우 초기화 함수 호출
// window.addEventListener('load', function () {
//  init();
// });

 


Three.js 편의 기능

Controls

사용자가 마우스나 터치 입력을 통해 카메라나 3D 객체를 회전, 이동, 확대/축소 등을 할 수 있게 도와주는 도구입니다.

EffectComposer

렌더링된 화면을 여러개의 패스(Pass)로 분리하고, 각각에 필터와 효과를 적용한 다음, 다시 합쳐서 후처리 효과를 적용합니다.

Helper

디버깅과 시각적인 가이드를 제공합니다. 씬 내에서 가이드 라인, 축, 경계 상자 등을 생성하여 개발자에게 도움을 줍니다.

Clock

애니메이션에 사용할 타임스탬프를 제공하고, 초단위 또는 프레임 단위의 경과 시간을 측정하는데 사용됩니다. (모니터 주사율에 따른 애니메이션 속도 차이 조절)

Math

3D 그래픽 작업에서 필요한 기하학적 계산과 변환 작업을 수행하기 위해 사용됩니다. 벡터, 행렬, 쿼터니언과 같은 수학적인 기능들을 제공하고 있습니다.


GUI 테스트 방법

https://npmtrends.com/dat.gui-vs-leva-vs-lil-gui

GUI 관련 라이브러리들을 찾아봤을 때, 나오는 3가지 라이브러리 입니다. dat.gui는 라이센스가 apache-2.0이며 업데이트가 된지 1년이 지났고, 사이즈가 1MB이기 때문에 lil-gui에 비해서 장점이 없었습니다. lil-gui는 MIT 라이센스, 2개월전 업데이트, 231KB 사이즈이며 다운로드 수도 dat.gui보다 5배 가량 차이가 났습니다.

 

leva는 React에서 컴포넌트에 넣어주는 props를 조절할 수 있는 기능이 있습니다. 이는 react-three-fiber 와 같이 three.js의 기능을 컴포넌트로 감싼 경우에 gui로 컨트롤이 가능해서 유용해보였습니다.

 

결론적으로 저는 커스터마이징이 가능하며 다운로드 수가 높은 lil-gui를 선택했습니다.

lil-gui docs

기본 사용 방법

import GUI from 'lil-gui'; 

const gui = new GUI();

const defaultValue = {
	myBoolean: true,
	myFunction: function() { ... },
	myString: 'lil-gui',
	strength: 1
};

gui.add( defaultValue, 'myBoolean' );  // Checkbox
gui.add( defaultValue, 'myFunction' ); // Button
gui.add( defaultValue, 'myString' );   // Text Field
gui.add( defaultValue, 'strength' );   // Number Field

// Default methods
gui.add( myObject, 'strength', 0, 3, 0.01 );
// Chainable methods
gui.add( defaultValue, 'strength' )
   .min(0)
   .max(3)
   .step(0.01);

컬러 컨트롤러 추가 방법

// Create color pickers for multiple color formats
const colorFormats = {
	string: '#ffffff',
	int: 0xffffff,
	object: { r: 1, g: 1, b: 1 },
	array: [ 1, 1, 1 ]
};
gui.addColor( colorFormats, 'string' );

많은 컨트롤러를 구분하기 위한 폴더 적용 방법

const folder = gui.addFolder('폴더명');

folder.add(position, 'x')
      .min(0)
      .max(10);
folder.add( position, 'y' )
      .min(0)
      .max(10);
folder.add( position, 'z' )
      .min(0)
      .max(10);

 

 

 

 

 

 

 

댓글