- 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는 타입이 내부적으로 이미 정의되어있기 때문에 따로 types 설치가 필요 없다.
lil-gui 공식 문서에서 dat GUI로부터의 마이그레이션에 관한 가이드를 제공한다.
Lights
※ Light에 속하는 모든 클래스 또한 Object3D를 확장하는 클래스이다.
Ambient Light
- Scene의 모든 물체들을 비추는 빛이다.
- 빛이 Scene의 모든 방향에서 들어온다. 때문에 Shading(음영)을 제한할 수 없게 된다.
- color 속성으로 빛의 색상을 바꿀 수 있다.
- MeshBasicMaterial 이나 MeshNormalMaterial에는 영향을 미치지 않는다.
- 빛의 색상을 바꿔도 이 material들의 색상이나 그림자에 변화가 없다.
- 생성자를 통해 색상(color)과 강도(intensity)를 받는다.
- 강도의 기본값은 1, 최대값은 Math.PI 이다.
Directional Light
- Ambient light와 달리 방향이 존재하는 빛이다.
- Scene 전체를 비추지만 한 방향에서만 나온다.
- Directional Light의 position 값을 바꿈으로써 빛이 나오는 방향을 바꿀 수 있다.
- rotation이 아니다. 공식 문서에서도 이를 안내하고 있다.
- 햇빛 등을 표현하는데 가장 잘 쓰이는 빛이다.
- Ambient light만큼은 아니지만 연산이 꽤 빠른 빛이다.
Point Light
- 한 점에서 시작하여 모든 방향으로 뻗어나가는 빛을 의미한다.
- 일반적인 전구에서 나오는 빛과 비슷하다 생각하면 된다.
- distance (빛의 최대 거리)값이 0일 경우, 이는 ‘한계 없음’을 나타낸다.
- decay: 거리에 따라 빛이 어두워지는 정도를 의미한다.
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들에 대해서도 castShadow나 receiveShadow 둘 중 하나(혹은 양쪽)가 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일 경우, OrthographicCamera를 사용하여 그림자를 렌더링한다.
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 |