Scene Graph 작업하기
Aspose.3D FOSS for TypeScript의 모든 3D 콘텐츠는 a 내부에 존재합니다 Scene 객체는 트리 형태로 조직됩니다 Node 객체들. 이 계층 구조를 이해하는 것이 모든 3D 파일을 구축, 로드 및 처리하기 위한 기반입니다.
설치
이 가이드의 코드를 실행하기 전에 npm에서 패키지를 설치하세요:
npm install @aspose/3d확인하십시오 tsconfig.json 포함합니다 "module": "commonjs" 및 "moduleResolution": "node" 올바른 하위 경로 가져오기 해석을 위해.
Scene Graph 개념
Scene Graph는 세 단계로 구성됩니다:
| 계층 | 클래스 | 역할 |
|---|---|---|
| 씬 | Scene | 최상위 컨테이너. 보유합니다 rootNode, animationClips, 및 assetInfo. |
| 노드 | Node | 이름이 지정된 트리 노드. 자식 노드, 엔티티, 변환 및 재료를 가질 수 있습니다. |
| 엔티티 | Mesh, Camera, Light, … | 노드에 첨부된 콘텐츠. 노드는 최대 하나의 엔터티만 가집니다. |
주요 구성 요소들의 상속 체인은 다음과 같습니다:
A3DObject
└─ SceneObject
├─ Node (tree structure)
└─ Entity
└─ Geometry
└─ Mesh (polygon geometry)scene.rootNode 자동으로 생성됩니다. 수동으로 만들지 않으며, 그 아래에 자식 노드를 생성합니다.
단계 1: 씬 생성
import { Scene } from '@aspose/3d';
const scene = new Scene();
console.log(scene.rootNode.name); // '' (empty string — the root node is created with no name)
새로운 Scene 빈 루트 노드와 애니메이션 클립이 없는 상태에서 시작합니다. 자식 노드를 첨부하여 콘텐츠를 구축합니다.
단계 2: 자식 노드 추가
사용 createChildNode() 트리를 성장시키기 위해 사용합니다. 이 메서드는 새로운 Node, 따라서 어떤 레벨에서도 추가 호출을 체인할 수 있습니다:
import { Scene } from '@aspose/3d';
const scene = new Scene();
const parent = scene.rootNode.createChildNode('parent');
const child = parent.createChildNode('child');
console.log(scene.rootNode.childNodes.length); // 1 (parent)
console.log(parent.childNodes.length); // 1 (child)
노드 이름은 임의의 문자열이며, 고유할 필요는 없지만 의미 있는 이름을 사용하면 트래버스 코드를 디버깅하기가 더 쉽습니다.
단계 3: Mesh 생성 및 정점 설정
Mesh 은(는) 기본 기하학 클래스입니다. 정점 위치를 푸시하여 추가합니다 Vector4 값을 mesh.controlPoints, 그런 다음 호출합니다 createPolygon() 정점 인덱스로 면을 정의합니다:
import { Scene } from '@aspose/3d';
import { Mesh } from '@aspose/3d/entities';
import { Vector4 } from '@aspose/3d/utilities';
const scene = new Scene();
const child = scene.rootNode.createChildNode('parent').createChildNode('child');
const mesh = new Mesh('cube');
mesh.controlPoints.push(new Vector4(0, 0, 0, 1));
mesh.controlPoints.push(new Vector4(1, 0, 0, 1));
mesh.controlPoints.push(new Vector4(1, 1, 0, 1));
mesh.controlPoints.push(new Vector4(0, 1, 0, 1));
mesh.createPolygon(0, 1, 2, 3); // quad face using all four vertices
child.entity = mesh;
console.log(mesh.controlPoints.length); // 4
console.log(mesh.polygonCount); // 1
Vector4 는 동차 좌표를 사용합니다: 해당 w 구성 요소는 1 위치에 사용되고 0 방향 벡터에 사용됩니다.
단계 4: 노드 변환 설정
각 노드는 transform 속성을 가지고 있으며 translation, rotation, 그리고 scaling. 설정 translation 노드를 부모에 상대적으로 이동시키려면:
import { Scene } from '@aspose/3d';
import { Mesh } from '@aspose/3d/entities';
import { Vector4, Vector3 } from '@aspose/3d/utilities';
const scene = new Scene();
const parent = scene.rootNode.createChildNode('parent');
const child = parent.createChildNode('child');
const mesh = new Mesh('cube');
mesh.controlPoints.push(new Vector4(0, 0, 0, 1));
mesh.controlPoints.push(new Vector4(1, 0, 0, 1));
mesh.controlPoints.push(new Vector4(1, 1, 0, 1));
mesh.controlPoints.push(new Vector4(0, 1, 0, 1));
mesh.createPolygon(0, 1, 2, 3);
child.entity = mesh;
child.transform.translation = new Vector3(2.0, 0.0, 0.0);globalTransform 월드 스페이스 변환 행렬(읽기 전용)을 제공하며, 모든 상위 변환을 연결하여 계산됩니다.
Step 5: 트리를 순회
모든 노드를 방문하는 재귀 함수를 작성하십시오. 확인 node.entity 그리고 node.childNodes 각 레벨에서:
function traverse(node: any, depth = 0): void {
const indent = ' '.repeat(depth);
const entityType = node.entity ? node.entity.constructor.name : 'none';
console.log(`${indent}${node.name} [${entityType}]`);
for (const child of node.childNodes) {
traverse(child, depth + 1);
}
}
traverse(scene.rootNode);위에서 만든 계층 구조에 대한 출력은 다음과 같습니다:
[none]
parent [none]
child [Mesh]루트 노드 이름은 빈 문자열입니다, 왜냐하면 Scene 이름 인수 없이 생성합니다.
특정 타입으로 캐스팅하기 전에 항상 null 검사를 통해 엔티티 접근을 보호하세요. 모든 노드가 엔티티를 가지고 있는 것은 아닙니다.
Step 6: glTF 또는 GLB 저장
사용 GltfSaveOptions 출력 형식을 제어합니다. 설정 binaryMode = true 단일 자체 포함된 .glb 파일; 그대로 두세요 false JSON용 .gltf + .bin 사이드카 쌍:
import { Scene } from '@aspose/3d';
import { Mesh } from '@aspose/3d/entities';
import { Vector4, Vector3 } from '@aspose/3d/utilities';
import { GltfSaveOptions, GltfFormat } from '@aspose/3d/formats/gltf';
const scene = new Scene();
const parent = scene.rootNode.createChildNode('parent');
const child = parent.createChildNode('child');
const mesh = new Mesh('cube');
mesh.controlPoints.push(new Vector4(0, 0, 0, 1));
mesh.controlPoints.push(new Vector4(1, 0, 0, 1));
mesh.controlPoints.push(new Vector4(1, 1, 0, 1));
mesh.controlPoints.push(new Vector4(0, 1, 0, 1));
mesh.createPolygon(0, 1, 2, 3);
child.entity = mesh;
child.transform.translation = new Vector3(2.0, 0.0, 0.0);
const saveOpts = new GltfSaveOptions();
saveOpts.binaryMode = true; // write a single .glb file
scene.save('scene.glb', GltfFormat.getInstance(), saveOpts);
console.log('Scene saved to scene.glb');전달 GltfFormat.getInstance() 형식 인수로 전달하여 라이브러리가 파일 확장자와 관계없이 올바른 인코더를 사용하도록 합니다.
팁 및 모범 사례
- 사용
createChildNode()구성하는 대신Node직접:createChildNode()부모-자식 관계를 자동으로 연결하고 노드를 트리에 등록합니다. - 확인
node.entity엔터티 속성에 접근하기 전에: 많은 노드(그룹 노드, 본, 로케이터)는 엔티티를 가지고 있지 않습니다. 항상 null 체크 또는instanceof테스트. - 설정
translation자식 노드에 적용하고, 메시 정점에는 적용하지 마세요: 수정transform.translationis non-destructive and composable with parent transforms. : 부터 부모 변환과 결합 가능하며 비파괴적입니다. - Prefer : 선호
binaryMode = truefor GLB : GLB용: a single : 단일.glbfile is easier to distribute, load in browsers, and import into game engines than the split : 파일은 분할된 형식보다 배포, 브라우저 로드 및 게임 엔진으로의 임포트가 더 쉽습니다..gltf+.binformat. : 형식. - Traverse via : 다음으로 순회
for...ofover : 위에childNodes: avoid numeric indexing; use the iterable directly for forward compatibility. : 숫자 인덱싱을 피하고, 향후 호환성을 위해 iterable을 직접 사용하세요.
일반적인 문제
| Symptom : 증상 | Likely Cause : 가능한 원인 | Fix : 수정 |
|---|---|---|
child.entity = mesh has no effect on export : 내보내기에 영향을 주지 않습니다 | Entity assigned to wrong node level : 엔티티가 잘못된 노드 레벨에 할당됨 | Assign : 할당 entity 리프 노드에, 그룹 노드가 아니라 |
node.entity 항상 null | 오직 확인 중 rootNode 그 자체 | 재귀적으로 들어가기 node.childNodes; rootNode 일반적으로 엔터티가 없습니다 |
| 변환이 GLB 뷰어에 반영되지 않음 | globalTransform 업데이트되지 않음 | globalTransform 저장 시 계산됩니다; 설정 transform.translation 호출하기 전에 scene.save() |
GLB는 별도의 .bin 사이드카 | binaryMode 기본값은 false | 설정 saveOpts.binaryMode = true |
또 보기
- 기능 및 특성: 모든 기능 영역에 대한 전체 API 참조.
- 형식 지원: 지원되는 3D 형식, 읽기/쓰기 기능 및 형식 옵션.
- How to Build a 3D Mesh Programmatically