- 21. Environment Maps 부터 23. Loading Multiple Assets 까지.
Environment Maps
Environment Mapping: 미리 계산된 텍스쳐를 사용해서 빛을 반사하는(reflective) 표면을 묘사하는 이미지 기반 lighting 기술.
- MeshStandardMaterial이나 MeshPhysicalMaterial을 쓸 때 가장 좋은 결과물을 얻을 수 있다고 한다.
⇒ PBR (Physically Based Rendering) Materials - 정의를 종합해서 생각해보길, 주변 물체의 표면을 렌더링하는데 영향을 줄 환경을 설정하고, 그 환경이 물체 표면에 반사되어 보이는 것처럼 만드는 것을 의미하는 것 같다.
구현
import * as THREE from 'three';
const scene = new THREE.Scene();
const environmentTexture = new THREE.CubeTextureLoader().setPath('URL').load(['px.png', 'nx.png', 'py.png', 'ny.png', 'pz.png', 'nz.png']);
scene.environment = environmentTexture;
scene.background = environmentTexture;
- Scene.environment: Texture 객체로, Scene 내의 모든 Physical material에 적용되는 Environment map을 설정한다.
- 예제에서는 CubeTextureLoader를 통해 지정된 URL에서 이미지를 가져와 할당하고 있다.
- 이렇게 설정된 environment는 반사와 빛 계산에 사용된다.
- Light를 끄면 Environment map이 적용되지 않게 된다.
- RGBLoader: HDR 이미지를 로딩하는 가장 일반적인 방법.
- HDR 이미지는 일반적인 PNG, JPG에 비해 용량이 커 처리에 비효율적일 수 있다.
import * as THREE from 'three';
import { RGBELoader } from 'three/addons/loaders/RGBELoader.js';
let environmentTexture: THREE.DataTexture;
new RGBELoader().load('URL', (texture) => {
environmentTexture = texture;
environmentTexture.mapping = THREE.EquirectangularReflectionMapping;
scene.environment = environmentTexture;
scene.background = environmentTexture;
scene.environmentIntensity = 1; // added in Three r163
});
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.toneMapping = THREE.ACESFilmicToneMapping;
- RGBLoader에 URL에 있는 텍스쳐를 로딩하고, 로딩이 끝나면 2번째 인자로 받는 콜백을 실행하도록 한다.
- DataTexture : Texture를 확장한 클래스. Raw data로부터 텍스쳐를 만든다.
- Renderer.toneMappingExposure: 이미지의 노출값을 조정한다. 이 속성을 사용하기 위해서는 toneMapping이 설정되어있어야 한다.
- Renderer.toneMapping: ToneMapping 이란, 컬러 값을 HDR에서 LDR로 매핑하는 것을 의미한다. Three.js에서는 toneMapping에 대한 값을 상수로 제공하고 있다.
- 다양한 예제에서 많이 쓰이는 값은 ACESFilmicToneMapping 이라고.
+) 참고
HDR이미지나 모델을 얻을 수 있는 사이트: https://polyhaven.com/
Mesh Material의 속성
강의에서 소개한 몇 가지 속성들에 대해 간단히 메모해둔다.
MeshStandardMaterial
- envMapIntensity: Environment Map에 의한 효과를 조정한다.
- metalness: Material이 금속과 비슷한 정도를 나타낸다.
- roughtness가 낮고 metalness가 높으면 거울처럼 environment map을 비추게 된다.
- roughness: Material이 거칠어보이는 정도를 나타낸다.
MeshPhysicalMaterial
- clearcoat: 자동차 페인트와 같은 재질에서 나타나는, 투명하고 반사 재질의 표면층을 재현하는 속성.
- Iridescence: 보는 시각에 따라 색이 달라지는 효과를 구현하기 위한 속성(ex. 비눗방울, 곤충의 날개 등)
- transmission: 유리나 플라스틱 같은 투명한 재질을 구현할 수 있는 속성.
- thickness: 표면 아래의 부피의 두꺼움을 표현하는 속성.
- ior(Index of Refraction): 금속이 아닌 재질의 굴절률을 표현하는 속성.
Loading Assets
Loader
- 모든 Loader들은 Loader 클래스를 확장하고 있다.
- Loader 클래스는 내부적으로 LoadingManager 객체를 가지고 있으며, 이것을 통해 데이터 수신 상태를 관리한다.
- GLTFLoader로 예를 들면 아래와 같다.
new GLTFLoader().load(
'model.glb',
// onLoad: 에셋의 로딩이 완료되었을 경우 실행된다
(gltf) => {
scene.add(gltf.scene)
},
// onProgress: 에셋을 가져오는 동안 실행된다
(xhr) => {
console.log((xhr.loaded / xhr.total) * 100 + '% loaded')
},
// onError: 에셋을 가져오는 동안 에러가 생겼을 시 실행된다
(err) => {
console.error('Error : ' + err)
}
)
RGBELoader()
- DataTextureLoader 클래스를 확장하는 클래스.
- load 메서드를 통해 URL 문자열을 받아 이미지를 가져온다.
- 상세한 것은 뒤의 강의에서 다뤄볼 것이라고.
TextureLoader()
- 텍스쳐를 로딩하는 데 사용하는 클래스.
- 마찬가지로 load 메서드를 통해 텍스쳐로 사용할 이미지를 가져온다.
import * as THREE from 'three';
const material = new THREE.MeshStandardMaterial();
material.map = new THREE.TextureLoader().load(image);
material.map.colorSpace = THREE.SRGBColorSpace;
※ material.map의 colorSpace 속성을 설정하면 Material의 색상을 더 선명하게 만들 수 있다.
※ 위의 코드의 경우, SRGB 색 공간으로 colorSpace를 설정한다.
Asset을 가져오는 방법
1. URL을 이용하기
- 강의에서 처럼, URL을 통해 에셋을 가져오는 방법.
- 이 강의에서 사용하는 에셋은 강사분의 개인 홈페이지에 연결된 것들로, (당연하겠지만) 학습 이외의 용도의 사용을 추천하지 않고 있음.
2. CDN 사용하기
- CDN에 올려진 다양한 에셋들을 가져와서 사용하는 방법.
- Github 등에 올려진 에셋들도 사용할 수 있다.
- Github의 에셋은 직접 접근하려 할 시 접근이 불가능할 수 있는데, jsdelivr를 사용하여 이를 해결할 수 있다.
3. 로컬 에셋 사용하기
- public 폴더 등에 사용할 에셋들을 넣어두고 정적으로 불러와 사용하는 것.
- 사실상 가장 좋은 접근방식.
+) Vite에서 에셋 세팅 하기
- 로컬에서 에셋을 불러올 때, hdr이나 glb 같은 형식의 파일들에서 에러가 날 수 있다.
- 이를 해결하려면 vite.config.js에 아래와 같은 수정이 필요하다.
import { defineConfig } from 'vite';
export default defineConfig({
assetsInclude: ['**/*.hdr', '**/*.glb'],
});
여러 개의 에셋을 가져오기
- load는 비동기적으로 실행되기 때문에 실행 순서 또한 보장되지 않는다.
- 특정 물체에 의존적인 물체를 추가해야 할 경우(부모 자식 관계를 맺어야 하는 경우), 부모 물체의 onLoad 콜백 내부에서 자식 물체들을 load하는 것이 좋다.
import * as THREE from 'three';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
let parentObj: THREE.Object3D;
const loader = new GLTFLoader();
loader.load('PATH_TO_PARENT_OBJ', (gltf) => {
parentObj = gltf.scene;
// 자식 물체를 가져온다
loader.load('PATH_TO_CHILD_OBJ', (childGltf) => {
parentObj.add(childGltf.scene);
});
scene.add(parentObj);
});
- 동일한 에셋이 복수 개 필요한 경우, loader.load()를 여러 번 호출하면 맨 첫번째 요청이 캐싱되어 실제로는 복수 번 호출하지 않는다.
- load를 복수 번 호출할 필요 없이, 한 번 호출한 물체를 clone 메서드를 통해 복제하여 사용할 수 있다.
- clone(): Object3D의 메서드로, 현재 객체를 복제하여 반환한다.
import * as THREE from 'three';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
let parentObj: THREE.Object3D;
const loader = new GLTFLoader();
loader.load('PATH_TO_PARENT_OBJ', (gltf) => {
parentObj = gltf.scene;
// 자식 물체를 가져온 후, 필요한 만큼 복제한다
loader.load('PATH_TO_CHILD_OBJ', (childGltf) => {
const children = [childGltf.scene, childGltf.scene.clone(), childGltf.scene.clone(), childGltf.scene.clone()];
parentObj.add(...children);
});
scene.add(parentObj);
});
loadAsync
- 앞서 살핀 load 메서드와 동일한 동작을 하지만, Promise를 반환한다.
→ 즉, 이 함수의 실행이 끝난 후 나머지 동작들을 실행한다.
import * as THREE from 'three';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
let parentObj: THREE.Object3D;
const loader = new GLTFLoader();
await loader.loadSync('PATH_TO_PARENT_OBJ', (gltf) => {
parentObj = gltf.scene;
});
// 부모 물체의 로딩이 끝나면 자식 물체를 가져온다
loader.load('PATH_TO_CHILD_OBJ', (childGltf) => {
const children = [childGltf.scene, childGltf.scene.clone(), childGltf.scene.clone(), childGltf.scene.clone()];
parentObj.add(...children);
scene.add(parentObj);
});
- 이 외에도 loadAsync와 Promise.all을 사용해 여러 개의 에셋을 동시에 가져오는 등의 다양한 방법이 존재한다.
- 점점 강의 한 개의 시간이 길어지기도 하고, 강사분이 개념에 대해 설명을 하나하나 자세히 하시는 스타일이 아니셔서 내가 혼자 찾아보는 바람에 하루에 듣는 강의의 분량이 조금씩 줄어들고 있다ㅎㅎㅋㅋ
'공부 > etc' 카테고리의 다른 글
Three.js and TypeScript (9) (0) | 2024.11.22 |
---|---|
Three.js and TypeScript (8) (1) | 2024.11.21 |
Three.js and TypeScript (6) (0) | 2024.11.19 |
Three.js and TypeScript (5) (2) | 2024.11.18 |
Electron + Vite + React 환경 세팅 살펴보기 (2) | 2024.11.15 |