Práce se scénovým grafem
Veškerý 3D obsah v Aspose.3D FOSS pro TypeScript se nachází uvnitř Scene objekt organizovaný jako strom Node objektů. Porozumění této hierarchii je základem pro vytváření, načítání a zpracování jakéhokoli 3D souboru.
Installation
Nainstalujte balíček z npm před spuštěním jakéhokoli kódu v tomto průvodci:
npm install @aspose/3dUjistěte se, že vaše tsconfig.json obsahuje "module": "commonjs" a "moduleResolution": "node" pro správné řešení importu podcesty.
Koncepty scénového grafu
Scénový graf má tři úrovně:
| Úroveň | Třída | Role |
|---|---|---|
| Scéna | Scene | Kontejner nejvyšší úrovně. Obsahuje rootNode, animationClips, a assetInfo. |
| Uzel | Node | Pojmenovaný uzel stromu. Může mít podřízené uzly, entitu, transformaci a materiály. |
| Entita | Mesh, Camera, Light, … | Obsah připojený k uzlu. Uzlu může nést nejvýše jednu entitu. |
Řetězec dědičnosti pro hlavní stavební bloky je:
A3DObject
└─ SceneObject
├─ Node (tree structure)
└─ Entity
└─ Geometry
└─ Mesh (polygon geometry)scene.rootNode je vytvořen automaticky. Nevytváříte jej ručně; vytváříte pod ním podřízené uzly.
Krok 1: Vytvořte scénu
import { Scene } from '@aspose/3d';
const scene = new Scene();
console.log(scene.rootNode.name); // '' (empty string — the root node is created with no name)
Nový Scene začíná s prázdným kořenovým uzlem a bez animačních klipů. Obsah vytváříte připojováním podřízených uzlů.
Krok 2: Přidat podřízené uzly
Použijte createChildNode() k růstu stromu. Metoda vrací nový Node, takže můžete řetězit další volání z libovolné úrovně:
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)
Názvy uzlů jsou libovolné řetězce. Názvy nemusí být jedinečné, ale používání smysluplných názvů usnadňuje ladění kódu pro procházení.
Krok 3: Vytvořit Mesh a nastavit vrcholy
Mesh je primární geometrická třída. Přidejte pozice vrcholů pomocí vkládání Vector4 hodnot do mesh.controlPoints, pak zavolejte createPolygon() k definování ploch podle indexu vrcholů:
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 používá homogenní souřadnice: w komponenta je 1 pro pozice a 0 pro směrové vektory.
Krok 4: Nastavte transformace uzlů
Každý uzel má transform vlastnost s translation, rotation, a scaling. Nastavte translation k posunutí uzlu relativně k jeho rodiči:
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 poskytuje matici transformace ve světovém prostoru (pouze pro čtení), vypočtenou spojením všech transformací předků.
Krok 5: Procházet strom
Napište rekurzivní funkci, která navštíví každý uzel. Zkontrolujte node.entity a node.childNodes na každé úrovni:
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);Pro výše vytvořenou hierarchii bude výstup:
[none]
parent [none]
child [Mesh]Název kořenového uzlu je prázdný řetězec, protože Scene vytváří jej bez argumentu name.
Vždy chraňte přístup k entitě kontrolou na null před přetypováním na konkrétní typ. Ne každý uzel nese entitu.
Krok 6: Uložit do glTF nebo GLB
Použijte GltfSaveOptions k řízení výstupního formátu. Nastavte binaryMode = true k vytvoření jediného samostatného .glb soubor; nechte ho false pro JSON .gltf + .bin sidecar pár:
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');Předat GltfFormat.getInstance() jako argument formátu, aby knihovna použila správný enkodér bez ohledu na příponu souboru.
Tipy a osvědčené postupy
- Použijte
createChildNode()namísto vytvářeníNodepřímo:createChildNode()automaticky propojí vztah rodič‑dítě a zaregistruje uzel ve stromu. - Zkontrolujte
node.entitypřed přístupem k vlastnostem entity: mnoho uzlů (skupinové uzly, kosti, lokátory) nemá žádnou entitu. Vždy to ošetřete kontrolou na null neboinstanceoftest. - Nastavit
translationna podřízených uzlech, ne na vrcholech mesh:modifikacetransform.translationje nedestruktivní a lze jej kombinovat s nadřazenými transformacemi. - Preferujte
binaryMode = truepro GLB:jediný.glbsoubor je snazší distribuovat, načíst v prohlížečích a importovat do herních enginů než rozdělený.gltf+.binformát. - Procházet pomocí
for...ofpřeschildNodes:vyhněte se číselnému indexování; použijte iterovatelný objekt přímo pro budoucí kompatibilitu.
Běžné problémy
| Symptom | Pravděpodobná příčina | Oprava |
|---|---|---|
child.entity = mesh nemá žádný vliv na export | Entita přiřazena k nesprávné úrovni uzlu | Přiřadit entity k listovému uzlu, ne ke skupinovému uzlu |
node.entity je vždy null | Pouze kontrola rootNode sám | Rekurzivně do node.childNodes; rootNode obvykle nemá žádnou entitu |
| Transformace se neodráží v prohlížeči GLB | globalTransform neaktualizováno | globalTransform se vypočítá při uložení; nastavit transform.translation před voláním scene.save() |
GLB vytváří samostatný .bin sidecar | binaryMode výchozí hodnota je false | Nastavit saveOpts.binaryMode = true |
Viz také
- Funkce a vlastnosti: úplná reference API pro všechny oblasti funkcí.
- Podpora formátů: podporované 3D formáty, možnost čtení/zápisu a možnosti formátu.
- Jak programově vytvořit 3D mesh