Three.js 및 glTF 웹 파이프라인은(는) 무엇을 하나요?
이 스킬은 Blender 또는 vcad 모델을 작은 .glb 파일로 변환하는 단계를 다룹니다. 파일은 빠르게 로드되어야 하며 Three.js에서 쉽게 애니메이션 처리될 수 있어야 합니다.
1. Blender 및 vcad 내보내기 체크리스트
노드 이름
- 각 움직이는 부품에 명확하고 안정적인 이름을 지정하세요:
Head,Visor,Eye_L,Eye_R,Torso_Door,Wheel_FL,Wheel_FR,Steering_Wheel. - 그러면 Three.js에서
model.getObjectByName("Torso_Door")로 부품을 찾습니다.
피벗
- 루트 원점을 모델 베이스의 중심에 배치하세요. Three.js에서 모델은
Y = 0인 지면에 놓입니다. - 각 관절 부품의 피벗을 회전축에 배치하세요. 예: 도어 힌지, 바퀴 중심, 목 베이스, 안테나 베이스.
변환
- 내보내기 전에 모든 변환을 적용하세요.
- 스케일은
1, 1, 1이어야 합니다. 회전은0, 0, 0으로 재설정되어야 합니다. - 이 규칙은 절차적 애니메이션 중 드리프트와 전단을 방지합니다.
지오메트리 예산
- 하나의 재질을 공유하는 정적 메시는 결합하세요. 이 단계는 드로우 콜을 줄입니다.
- 스크립트가 단독으로 애니메이션 처리하는 경우에만 메시를 분리하여 유지하세요. 소프트 변형에는 Armature와 함께
SkinnedMesh를 사용하세요. - 히어로 에셋당 수천 개의 삼각형을 목표로 하세요. 배경 소품의 경우 1,000개 미만의 삼각형을 목표로 하세요.
2. @gltf-transform/cli를 사용한 CLI 최적화
이 프로젝트는 Bun을 사용합니다. bunx로 도구를 실행하세요. Node.js가 있는 머신에서는 npx도 작동합니다.
# 메시, 텍스처, 애니메이션 표시
bunx @gltf-transform/cli inspect model.glb
# 웹용 전체 최적화: Meshopt + WebP + 정리
bunx @gltf-transform/cli optimize model.glb model-optimized.glb \
--compress meshopt \
--texture-compress webp \
--texture-size 2048
# 대안: Draco 지오메트리 압축
bunx @gltf-transform/cli draco model.glb model-draco.glb
Meshopt 또는 Draco
- Meshopt (
EXT_meshopt_compression) 디코딩이 매우 빠릅니다. 정점 순서를 유지하고 애니메이션 키프레임과 모프 타겟도 압축합니다. 애니메이션 에셋에 사용하세요. - Draco (
KHR_draco_mesh_compression) 는 밀집된 정적 메시에 대해 가장 작은 파일을 제공합니다. 예: 자동차 차체 및 스캔. 디코더는 시작 시 더 많은 시간이 소요됩니다.
기타 유용한 단계
# 중복 메시 및 사용되지 않는 데이터 제거
bunx @gltf-transform/cli dedup model.glb model.glb
# 텍스처를 KTX2(BasisU)로 변환
bunx @gltf-transform/cli etc1s model.glb model-ktx2.glb
각 단계 후에 파일을 확인하세요. 파일 크기, 삼각형 개수, 텍스처 크기를 확인하세요.
3. Three.js 통합
Draco 및 Meshopt를 지원하는 강력한 로더
import * as THREE from 'three';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';
import { MeshoptDecoder } from 'three/addons/libs/meshopt_decoder.module.js';
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath('https://www.gstatic.com/draco/versioned/decoders/1.5.7/');
const gltfLoader = new GLTFLoader();
gltfLoader.setDRACOLoader(dracoLoader);
gltfLoader.setMeshoptDecoder(MeshoptDecoder);
const gltf = await gltfLoader.loadAsync('/models/bender-optimized.glb');
const root = gltf.scene;
scene.add(root);
두 가지 애니메이션 방법
- 노드 변환을 사용한 절차적 애니메이션. 로봇, 차량 및 기타 강체 부품에 이 방법을 사용하세요. 예: 바퀴 회전, 도어 열기, 헤드 추적, 안테나 흔들기.
const head = root.getObjectByName('Head');
const door = root.getObjectByName('Torso_Door');
const antenna = root.getObjectByName('Antenna');
function animate(time) {
if (antenna) {
antenna.rotation.z = Math.sin(time * 0.005) * 0.15;
}
if (head) {
head.rotation.y = THREE.MathUtils.lerp(head.rotation.y, targetYaw, 0.1);
}
}
THREE.AnimationMixer를 사용한 베이크된 클립. Blender에서 가져온 복잡한 사이클(걷기, 춤, 얼굴 모프)에 이 방법을 사용하세요.
const mixer = new THREE.AnimationMixer(root);
const idleClip = THREE.AnimationClip.findByName(gltf.animations, 'Idle');
if (idleClip) {
mixer.clipAction(idleClip).play();
}
// 렌더 루프에서:
// mixer.update(clock.getDelta());
금속 부품을 위한 PBR 조명
금속 재질(metalness > 0.8)은 Three.js에서 주변에 아무것도 없을 때 검게 보입니다. 환경 맵을 설정하세요:
import { RoomEnvironment } from 'three/addons/environments/RoomEnvironment.js';
const pmremGenerator = new THREE.PMREMGenerator(renderer);
scene.environment = pmremGenerator.fromScene(new RoomEnvironment(), 0.04).texture;
scene.environmentIntensity를 사용하여 반사 강도를 조정하세요. 금속 에셋의 경우 톤 매핑을 THREE.ACESFilmicToneMapping으로 유지하세요.
성능 규칙
- 메시 그룹당 하나의 재질. 각 재질은 하나의 드로우 콜을 발생시킵니다.
- 텍스처를 재사용하세요. 작은 텍스처를 하나의 아틀라스로 압축하세요.
renderer.outputColorSpace = THREE.SRGBColorSpace로 설정하세요. glTF 로더가 텍스처 색상 공간을 설정합니다.- 하나의 에셋이 여러 번 나타날 때
THREE.InstancedMesh를 사용하세요. - 모델을 제거할 때 해제하세요: 씬을 순회한 다음
geometry.dispose()및material.dispose()를 호출하세요.