Bekerja dengan Scene Graph
Semua kandungan 3D dalam Aspose.3D FOSS untuk TypeScript berada di dalam objek Scene yang disusun sebagai pokok objek Node. Memahami hierarki ini adalah asas untuk membina, memuatkan, dan memproses mana-mana fail 3D.
Pemasangan
Pasang pakej dari npm sebelum menjalankan sebarang kod dalam panduan ini:
npm install @aspose/3dPastikan tsconfig.json anda termasuk "module": "commonjs" dan "moduleResolution": "node" untuk penyelesaian import sub‑laluan yang betul.
Konsep Graf Adegan
Graf adegan mempunyai tiga peringkat:
| Tier | Class | Role |
|---|---|---|
| Scene | Scene | Kontena peringkat atas. Menyimpan rootNode, animationClips, dan assetInfo. |
| Node | Node | Nod pokok bernama. Boleh mempunyai nod anak, entiti, transform, dan bahan. |
| Entity | Mesh, Camera, Light, … | Kandungan yang dilampirkan pada nod. Sebuah nod membawa paling banyak satu entiti. |
Rantaian pewarisan untuk blok binaan utama ialah:
A3DObject
└─ SceneObject
├─ Node (tree structure)
└─ Entity
└─ Geometry
└─ Mesh (polygon geometry)scene.rootNode dibuat secara automatik. Anda tidak membuatnya secara manual; anda membuat nod anak di bawahnya.
Langkah 1: Cipta Adegan
import { Scene } from '@aspose/3d';
const scene = new Scene();
console.log(scene.rootNode.name); // '' (empty string — the root node is created with no name)
Sebuah Scene baru bermula dengan node akar kosong dan tiada klip animasi. Anda membina kandungan dengan melampirkan node anak.
Langkah 2: Tambah Nod Anak
Gunakan createChildNode() untuk menumbuhkan pokok. Kaedah ini mengembalikan Node yang baru, jadi anda boleh menyambung panggilan selanjutnya dari mana-mana peringkat:
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)
Nama nod adalah rentetan sewenang-wenangnya. Nama tidak perlu unik, tetapi menggunakan nama yang bermakna menjadikan kod penelusuran lebih mudah untuk dibaiki.
Langkah 3: Cipta Mesh dan Tetapkan Vertices
Mesh adalah kelas geometri utama. Tambahkan posisi vertex dengan menolak nilai Vector4 ke dalam mesh.controlPoints, kemudian panggil createPolygon() untuk mendefinisikan muka mengikut indeks vertex:
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 menggunakan koordinat homogen: komponen w ialah 1 untuk kedudukan dan 0 untuk vektor arah.
Langkah 4: Tetapkan Transformasi Nod
Setiap nod mempunyai sifat transform dengan translation, rotation, dan scaling. Tetapkan translation untuk menggerakkan nod relatif kepada ibu bapa:
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 menyediakan matriks transformasi ruang-dunia (baca-sahaja), yang dikira dengan menggabungkan semua transformasi nenek moyang.
Langkah 5: Menelusuri Pokok
Tulis fungsi rekursif untuk melawat setiap nod. Semak node.entity dan node.childNodes pada setiap peringkat:
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);Untuk hierarki yang dibuat di atas, outputnya akan menjadi:
[none]
parent [none]
child [Mesh]Nama nod akar adalah rentetan kosong kerana Scene menciptanya tanpa argumen nama.
Sentiasa lindungi akses entiti dengan pemeriksaan null sebelum menukarkan kepada jenis tertentu. Tidak setiap nod membawa entiti.
Langkah 6: Simpan ke glTF atau GLB
Gunakan GltfSaveOptions untuk mengawal format output. Tetapkan binaryMode = true untuk menghasilkan satu fail .glb yang berdiri sendiri; biarkan false untuk pasangan sidecar 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');Berikan GltfFormat.getInstance() sebagai parameter format supaya perpustakaan menggunakan pengekod yang betul tanpa mengira sambungan fail.
Petua dan Amalan Terbaik
- Gunakan
createChildNode()dan bukannya membinaNodesecara langsung:createChildNode()secara automatik menyambungkan hubungan ibu‑bapa dan mendaftar nod dalam pokok. - Periksa
node.entitysebelum mengakses sifat entiti: banyak nod (nod kumpulan, tulang, penunjuk) tidak membawa entiti. Sentiasa lindungi dengan pemeriksaan null atau ujianinstanceof. - Tetapkan
translationpada nod anak, bukan pada verteks mesh: mengubahtransform.translationtidak merosakkan dan boleh digabungkan dengan transformasi ibu bapa. - Utamakan
binaryMode = trueuntuk GLB: satu fail.glblebih mudah diedarkan, dimuatkan dalam pelayar, dan diimport ke dalam enjin permainan berbanding format terbahagi.gltf+.bin. - Lalui melalui
for...ofberbandingchildNodes: elakkan penomboran indeks; gunakan iterable secara langsung untuk keserasian ke hadapan.
Isu Umum
| Symptom | Likely Cause | Fix |
|---|---|---|
child.entity = mesh tidak memberi kesan pada eksport | Entiti ditetapkan pada tahap nod yang salah | Tetapkan entity kepada nod daun, bukan kepada nod kumpulan |
node.entity sentiasa null | Hanya memeriksa rootNode itu sendiri | Lakukan rekursi ke dalam node.childNodes; rootNode biasanya tidak mempunyai entiti |
| Transformasi tidak dipaparkan dalam penonton GLB | globalTransform tidak dikemas kini | globalTransform dikira semasa menyimpan; tetapkan transform.translation sebelum memanggil scene.save() |
GLB menghasilkan fail .bin sidecar berasingan | binaryMode secara lalai kepada false | Tetapkan saveOpts.binaryMode = true |
Lihat Juga
- Ciri-ciri dan Fungsi: rujukan API penuh untuk semua kawasan ciri.
- Sokongan Format: format 3D yang disokong, keupayaan baca/tulis, dan pilihan format.
- Cara Membina Mesh 3D Secara Programatik