본문 바로가기
공부/etc

Three.js and TypeScript (6)

by Piva 2024. 11. 19.
  • Udemy의 Three.js and TypeScript 강의를 듣고 정리한 내용을 기록한다.
    • 18. lil-gui 부터 20. Shadows 까지.

lil-gui

  • dat GUI의 대체재로 개발된 라이브러리.
  • dat GUI는 아직도 유용하고 잘 쓰이지만 유지보수가 되고있지 않고 있다(2022년 이후로 활동이 없는 상황).
  • Three.js 135 릴리즈 까지 공식 예제에서 사용되다, 이후로 lil-gui로 대체되었다.
원문에서는 ‘Drop-in replacement’ 인데, 찾아보길 ‘별다른 코드 변경이나 부정적인 영향 없이 하드웨어/소프트웨어 컴포넌트를 변경하는 것’을 의미한다고.

 

 

dat GUI → lil-gui 로의 전환

  • lil-gui와 dat GUI는 거의 똑같기 때문에, 일반적으로는 그냥 import 문을 dat GUI에서 lil-gui로 바꾸기만 하면 거의 완벽하게 똑같이 동작함.
  • Three.js에서 lil-gui를 import 하기 위해서는 아래와 같은 방법을 사용할 수 있음.

 

1. addons 사용하기

import { GUI } from 'three/addons/libs/lil-gui.module.min.js';

 

 

2. lil-gui를 직접 추가하기

npm install lil-gui
yarn add lil-gui

import { GUI } from 'lil-gui';

lil-gui를 추가한 모습

 

 

※ lil-gui는 타입이 내부적으로 이미 정의되어있기 때문에 따로 types 설치가 필요 없다.

lil-gui 공식 문서에서 dat GUI로부터의 마이그레이션에 관한 가이드를 제공한다.

 

 

 

Lights

※ Light에 속하는 모든 클래스 또한 Object3D를 확장하는 클래스이다.

 

Ambient Light

Ambient Light

  • Scene의 모든 물체들을 비추는 빛이다.
  • 빛이 Scene의 모든 방향에서 들어온다. 때문에 Shading(음영)을 제한할 수 없게 된다.
  • color 속성으로 빛의 색상을 바꿀 수 있다.
  • MeshBasicMaterial 이나 MeshNormalMaterial에는 영향을 미치지 않는다.
    • 빛의 색상을 바꿔도 이 material들의 색상이나 그림자에 변화가 없다.
  • 생성자를 통해 색상(color)과 강도(intensity)를 받는다.
    • 강도의 기본값은 1, 최대값은 Math.PI 이다.

 

 

 

Directional Light

Directional Light

  • Ambient light와 달리 방향이 존재하는 빛이다.
    • Scene 전체를 비추지만 한 방향에서만 나온다.
  • Directional Light의 position 값을 바꿈으로써 빛이 나오는 방향을 바꿀 수 있다.
    • rotation이 아니다. 공식 문서에서도 이를 안내하고 있다.
  • 햇빛 등을 표현하는데 가장 잘 쓰이는 빛이다.
  • Ambient light만큼은 아니지만 연산이 꽤 빠른 빛이다.

 

 

Point Light

Point Light

  • 한 점에서 시작하여 모든 방향으로 뻗어나가는 빛을 의미한다.
    • 일반적인 전구에서 나오는 빛과 비슷하다 생각하면 된다.
  • distance (빛의 최대 거리)값이 0일 경우, 이는 ‘한계 없음’을 나타낸다.
  • decay: 거리에 따라 빛이 어두워지는 정도를 의미한다.

 

 

Spot Light

Spot Light

  • Point light와 비슷하게 Scene 내부의 한 점에서 시작하여 뻗어나가는 빛.
    • 다른 점이 있다면 빛의 형태가 원뿔형이라는 것이다.
    • 모든 방향으로 뻗어나가는 것이 아닌, 한 방향으로만 뻗어나간다.
  • penumbra를 통해 spot light가 점점 희미해지는 정도를 조절할 수 있다.
  • Point light와 같이 distance, decay 값 등을 조절할 수 있다.

 

아래는 각각의 특징을 요약한 것.

이름 특징
AmbientLight Scene 전체를 모든 방향으로 비춤.
DirectionalLight Scene 전체를 한 가지 방향으로 비춤.
PointLight 모든 방향을 한 3D 좌표에서부터 비춤.
SpotLight 한 가지 방향을 한 3D 좌표에서부터 비춤.

 

 

Light helper

  • Light의 각도나 위치를 시각적으로 보여줌으로써 빛 설정을 도와주는 객체이다.
  • DirectionalLightHelper, PointLightHelper, SpotLightHelper 등이 있다.

 

 

Shadows

  • Light 강의에서 여러 가지 빛을 추가했을 때, 물체에 그림자가 자동으로 추가되지 않았다.
  • Three.js에서는 그림자를 직접 추가해야 한다.

 

그림자 추가하기

  • 그림자를 추가하기 위해서는 Renderer의 shadowMap 을 활성화해야한다.
  • 필요한 경우 shadowMap의 type을 할당할 수 있다.
    • 사용할 수 있는 타입에는 크게 4가지가 있다(Three.js에 상수로 존재한다).
타입 이름 설명
PCFShadowMap Percentage-Closer Filtering(PCF) 알고리즘으로 shadow map을 필터링한다. 디폴트 값.
PCFSoftShadowMap PCF알고리즘과 함께 저해상도 shadow map에 더 부드러운 그림자 효과를 제공한다.
VSMShadowMap Variance Shadow Map(VSM) 알고리즘으로 shadow map을 필터링한다.
BasicShadowMap 필터링되지 않은 shadow map으로, 가장 빠르지만 가장 퀄리티가 낮다.

 

import * as THREE from 'three';

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.shadowMap.enabled = true;

 

  • Light 또한 castShadow 속성이 true여야 한다.
import * as THREE from 'three';

const directionalLight = new THREE.DirectionalLight(0xffffff, Math.PI);
directionalLight.castShadow = true;

 

 

  • Scene 내부의 각종 mesh들에 대해서도 castShadowreceiveShadow 둘 중 하나(혹은 양쪽)가 true여야 그림자가 보인다.
    • castShadow: 물체가 Shadow map에 렌더링 될 것인지 아닌지를 나타낸다. (이 물체에 대한 그림자가 그려질지 아닐지를 결정한다는 것으로 보인다)
    • receiveShadow: 이 물체에 그림자가 그려질 것인지 아닌지를 나타낸다.
import * as THREE from 'three';

const plane = new THREE.Mesh(new THREE.PlaneGeometry(100, 100), new THREE.MeshStandardMaterial({ color: 0xffffff }));
plane.receiveShadow = true;
plane.castShadow = true;

 

MeshBasicMaterial 같이 빛에 영향을 받지 않는 머터리얼을 사용한 mesh라도, 그 mesh에 대한 그림자 자체는 그려질 수 있다.

 

 

 

Shadow camera

  • Three.js에서는 Shadow map의 렌더링에 카메라를 사용한다.
    • 현재 빛이 Directional Light일 경우, OrthographicCamera를 사용하여 그림자를 렌더링한다.
      → 그림자가 평행한 모습으로 그려진다.
    • 현재 빛이 Point Light/Spot light일 경우, PerspectiveCamera를 사용하여 그림자를 렌더링한다.
Directional Light의 그림자 PointLight의 그림자

 

그림자는 카메라 영역의 영향을 받는다. 영역이 넓어질 수록 그림자를 위해 고려해야하는 불필요한 영역의 크기가 늘어나, 그림자의 퀄리티 저하를 일으킬 수 있다.

 

 

 

Shadow map

  • Shadow map의 크기는 mapSize를 변경함으로써 설정할 수 있다.
    • 더 큰 값일 수록 더 좋은 퀄리티의 그림자를 그려낼 수 있으나, 연산 시간을 희생하야 한다.
    • 값은 무조건 2의 거듭제곱이어야 한다.
  • radius: 1보다 큰 값을 설정하면 그림자의 경계선을 부드럽게 만든다.
    • 단, shadowMap의 타입이 PCFSoftShadowMap / BasicShadowMap 으로 설정되어있으면 아무런 효과를 보이지 않는다.
import * as THREE from 'three';

const directionalLight = new THREE.DirectionalLight(data.lightColor, Math.PI);

directionalLight.shadow.radius

directionalLight.shadow.mapSize.width
directionalLight.shadow.mapSize.height

'공부 > etc' 카테고리의 다른 글

Three.js and TypeScript (8)  (1) 2024.11.21
Three.js and TypeScript (7)  (2) 2024.11.20
Three.js and TypeScript (5)  (2) 2024.11.18
Electron + Vite + React 환경 세팅 살펴보기  (2) 2024.11.15
Three.js and TypeScript (4)  (0) 2024.11.14