- 24. GLTF Loader : Part 1 부터 26. Raycaster 까지.
GLTF Loader
GLTF (GL Transmission Format)
- 3D Scene과 모델들의 효율적인 전송과 로딩을 위한 파일 형식.
- 3D 에셋의 크기 및 에셋들을 분석하는데 걸리는 시간을 최소화한다.
- 하나의 GLTF 파일은 하나 혹은 그 이상의 Scene, Meshes, Materials, Textures, Skeletons, Cameras, 기타 등등을 포함할 수 있다.
- 에셋은 JSON 형식(gltf) 혹은 이진 파일(glb)의 형태로 제공될 수 있다.
- 3D 모델링 툴인 블렌더(Blender)를 통해 gltf 파일을 내보낼 수 있다.
구성
- GLTFLoader로 gltf 파일을 불러온 후, 콘솔로 확인해보면 아래와 같은 각종 프로퍼티들을 확인할 수 있다.
- scene: Three.js의 Group 객체이며, Object3D를 확장한다.
- 객체 내부의 childeren에 gltf파일을 구성하는 각종 Mesh에 대한 정보를 알 수 있다.
Group: 복수의 물체를 묶어 하나로 취급할 수 있도록 만들어진 클래스이다.
Lensflare
- addons에서 사용할 수 있는 객체.
- 빛(Light)을 추적하는 lens flare 효과를 만든다.
import * as THREE from 'three';
import { Lensflare, LensflareElement } from 'three/addons/objects/Lensflare.js'
const light = new THREE.SpotLight(undefined, Math.PI * 1000);
const lensflare = new Lensflare();
lensflare.addElement(new LensflareElement(textureFlare0, 1000, 0));
light.add(lensflare);
- Scene에 이미 존재하는 Light에 add 메서드를 통해 lens flare를 추가한다.
Blender
- 3D 모델링 툴(링크).
- Blender에서 수정한 모델을 Three.js에서 적용할 수 있다. 이걸 활용해서 Blender에서 미리 위치를 잡거나, 광원을 설정하는 것이 가능하다.
- Three.js에서 Blender의 gltf파일을 import 시 각 속성들을 읽어 MeshStandardMaterial을 만든다.
- 기본적으로는 MeshStandardMaterial로 변환하지만, 어떤 속성이 존재하는지에 따라 그 속성을 갖는 다른 Material로 변환한다.
- Blender와 Three.js가 완벽하게 1대1로 매칭되진 않는다(Light 경우 제대로 export 되지 않는 듯).
- 그러나 애니메이션이나 Mesh, 일부 Material은 어느정도 export될 수 있는 것 같다.
Raycaster
- Scene 내에 3D 좌표를 생성하여, 이 좌표와 교차하는 물체를 감지할 수 있다.
- 아래와 같은 것들을 감지하는 것이 가능하다.
- Reycaster 위치와 교차 지점까지의 거리
- 3D Scene에서의 교차점의 좌표
- 교차된 물체의 면(face)
- 면(faces normal)의 방향
- 면 위 교차지점의 UV 좌표
- 교차한 물체 자체에 대한 참조
Raycaster()
- Raycaster를 생성하는 생성자. 아래와 같은 인자를 받을 수 있다.
- origin: Raycast의 좌표.
- direction: ray의 방향을 설정할 방향 벡터.
- near / far: Raycaster의 탐지 거리를 설정한다. near 보단 크고 far보단 작은 거리 내에서 감지한다. near는 음수가 될 수 없으며, far는 near보다 작을 수 없다.
메서드
- setFromCamera(): ray를 새로운 origin과 direction으로 업데이트 한다. 이 때 2개의 인자를 받는다.
- coords: 마우스의 2D 좌표를 정규화된 좌표(Normalized Device Coordinate)로 받는다.
- camera: ray가 비롯되는 카메라 객체를 가리킨다.
Normalized Device Coordinate(NDC): -1에서 1 사이의 값으로 표준화된 좌표계. 좌표 계산을 단순하게 하기 위해 사용한다는 듯 하다.
- intersectObjects(): ray와 인자로 주어지는 objects들 사이의 교차 정보를 반환한다.
- 여기서, objects로 넘긴 물체들에 대한 교차 정보’만’ 반환한다. 반대로 말하면 여기에 포함되지 않은 물체와의 교차 정보는 얻을 수 없다.
Raycaster를 사용해 마우스 커서에 닿는 물체들을 탐지하는 예시는 아래와 같다.
import * as THREE from 'three';
const renderer = new THREE.WebGLRenderer({ antialias: true });
const raycaster = new THREE.Raycaster();
const pickables: THREE.Mesh[] = [];
const mousePos = new THREE.Vector2();
renderer.domElement.addEventListener('mousemove', (e) => {
mousePos.set((e.clientX / renderer.domElement.clientWidth) * 2 - 1, -(e.clientY / renderer.domElement.clientHeight) * 2 + 1);
raycaster.setFromCamera(mousePos, camera);
const intersects = raycaster.intersectObjects(pickables, false);
if (intersects.length) {
console.log(intersects);
}
});
- Raycaster 생성자로 raycaster를 생성한다.
- mouse의 좌표를 기록할 mousePos를 선언한다.
- 교차 여부를 관찰할 물체들이 담길 pickables 배열을 선언한다.
- mousemove 이벤트에 대해 이벤트 리스너를 등록한다.
- 콜백 내에는 마우스의 좌표를 실시간으로 갱신한다. 이 때, 캔버스 크기를 사용하여 정규화한 좌표로 업데이트 한다.
- setFromCamera 를 통해 카메라와 origin(여기서는 마우스 좌표) 사이 거리를 계산하도록 한다.
- intersectObjects를 통해, raycaster와 교차하는 물체들의 목록을 받는다.
활용 예제
강의에서 실습하는 예제 코드에 대해 간략하게 기록한다.
- 아래 코드는 Raycaster를 통해, 마우스 커서와 맞닿은 물체의 한 면에 수직선을 긋는 예제이다.
- 전체 코드가 아닌 일부만 기록한다.
import * as THREE from 'three';
const renderer = new THREE.WebGLRenderer({ antialias: true });
const raycaster = new THREE.Raycaster();
const pickables: THREE.Mesh[] = [];
const mousePos = new THREE.Vector2();
const arrowHelper = new THREE.ArrowHelper();
arrowHelper.setLength(0.5);
scene.add(arrowHelper);
renderer.domElement.addEventListener('mousemove', (e) => {
mousePos.set((e.clientX / renderer.domElement.clientWidth) * 2 - 1, -(e.clientY / renderer.domElement.clientHeight) * 2 + 1);
raycaster.setFromCamera(mousePos, camera);
const intersects = raycaster.intersectObjects(pickables, false);
if (intersects.length) {
const n = new THREE.Vector3();
n.copy((intersects[0].face as THREE.Face).normal);
n.transformDirection(intersects[0].object.matrixWorld);
arrowHelper.setDirection(n);
arrowHelper.position.copy(intersects[0].point);
}
});
Z fighting
: 복수의 물체의 Z 좌표가 거의 비슷하거나 같아서, 깊이를 파악하기 어려워짐에 따라 물체들의 렌더링 순위가 바뀌는 것을 ‘싸움’에 빗댄 단어이다. 마치 화면이 깨지는 것처럼 깜빡이는 현상을 일컫는다.
'공부 > etc' 카테고리의 다른 글
Three.js and TypeScript (10) (0) | 2024.11.25 |
---|---|
Three.js and TypeScript (9) (0) | 2024.11.22 |
Three.js and TypeScript (7) (2) | 2024.11.20 |
Three.js and TypeScript (6) (0) | 2024.11.19 |
Three.js and TypeScript (5) (2) | 2024.11.18 |