Bekerja dengan Scene Graph
Semua konten 3D dalam Aspose.3D FOSS untuk TypeScript berada di dalam sebuah Scene objek yang diatur sebagai pohon dari Node objek. Memahami hierarki ini adalah dasar untuk membangun, memuat, dan memproses setiap file 3D.
Instalasi
Instal paket dari npm sebelum menjalankan kode apa pun dalam panduan ini:
npm install @aspose/3dPastikan tsconfig.json menyertakan "module": "commonjs" dan "moduleResolution": "node" untuk resolusi impor sub‑path yang benar.
Konsep Scene Graph
Scene graph memiliki tiga tingkatan:
| Tingkat | Kelas | Peran |
|---|---|---|
| Adegan | Scene | Kontainer tingkat atas. Menyimpan rootNode, animationClips, dan assetInfo. |
| Node | Node | Node pohon bernama. Dapat memiliki node anak, sebuah entitas, transformasi, dan material. |
| Entitas | Mesh, Camera, Light, … | Konten yang terlampir pada sebuah node. Sebuah node membawa paling banyak satu entitas. |
Rantai pewarisan untuk blok bangunan utama adalah:
A3DObject
└─ SceneObject
├─ Node (tree structure)
└─ Entity
└─ Geometry
└─ Mesh (polygon geometry)scene.rootNode dibuat secara otomatis. Anda tidak membuatnya secara manual; Anda membuat node anak di bawahnya.
Langkah 1: Buat sebuah Scene
import { Scene } from '@aspose/3d';
const scene = new Scene();
console.log(scene.rootNode.name); // '' (empty string — the root node is created with no name)
Baru Scene dimulai dengan node root kosong dan tidak ada klip animasi. Anda membangun konten dengan melampirkan node anak.
Langkah 2: Tambahkan Node Anak
Gunakan createChildNode() untuk menumbuhkan pohon. Metode mengembalikan yang baru Node, sehingga Anda dapat menautkan panggilan lebih lanjut dari level mana pun:
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 node adalah string sewenang-wenang. Nama tidak harus unik, tetapi menggunakan nama yang bermakna membuat kode traversal lebih mudah di‑debug.
Langkah 3: Buat Mesh dan Atur Vertex
Mesh adalah kelas geometri utama. Tambahkan posisi vertex dengan mendorong Vector4 nilai ke dalam mesh.controlPoints, lalu panggil createPolygon() untuk mendefinisikan wajah dengan 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: w komponen adalah 1 untuk posisi dan 0 untuk vektor arah.
Langkah 4: Atur Transformasi Node
Setiap node memiliki sebuah transform properti dengan translation, rotation, dan scaling. translation untuk memindahkan node relatif terhadap induknya:
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 world-space transformation matrix (read-only), dihitung dengan menggabungkan semua transformasi nenek moyang.
Langkah 5: Jelajahi Pohon
Tulislah fungsi rekursif untuk mengunjungi setiap node. Periksa node.entity dan node.childNodes pada setiap level:
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 node akar adalah string kosong karena Scene membuatnya tanpa argumen nama.
Selalu lindungi akses entitas dengan pemeriksaan null sebelum melakukan casting ke tipe tertentu. Tidak setiap node membawa entitas.
Langkah 6: Simpan ke glTF atau GLB
Gunakan GltfSaveOptions untuk mengontrol format output. Atur binaryMode = true untuk menghasilkan satu berkas mandiri .glb berkas; biarkan false untuk JSON .gltf + .bin pasangan sidecar:
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 argumen format sehingga perpustakaan menggunakan encoder yang tepat terlepas dari ekstensi berkas.
Tips dan Praktik Terbaik
- Gunakan
createChildNode()alih-alih membangunNodesecara langsung:createChildNode()secara otomatis menghubungkan hubungan induk-anak dan mendaftarkan node dalam pohon. - Periksa
node.entitysebelum mengakses properti entitas: banyak node (node grup, tulang, lokator) tidak memiliki entitas. Selalu lindungi dengan pemeriksaan null atauinstanceofpengujian. - Setel
translationpada node anak, bukan pada vertex mesh: memodifikasitransform.translationtidak merusak dan dapat digabungkan dengan transformasi induk. - Lebih disukai
binaryMode = trueuntuk GLB: satu.glbfile lebih mudah didistribusikan, dimuat di peramban, dan diimpor ke mesin game dibandingkan yang terpisah.gltf+.binformat. - Jelajahi melalui
for...ofdi ataschildNodes: hindari pengindeksan numerik; gunakan iterable secara langsung untuk kompatibilitas ke depan.
Masalah Umum
| Gejala | Penyebab Kemungkinan | Perbaikan |
|---|---|---|
child.entity = mesh tidak berpengaruh pada ekspor | Entitas ditetapkan pada level node yang salah | Tetapkan entity ke node daun, bukan ke node grup |
node.entity selalu null | Hanya memeriksa rootNode sendiri | Merekur ke dalam node.childNodes; rootNode biasanya tidak memiliki entitas |
| Transformasi tidak tercermin di penampil GLB | globalTransform tidak diperbarui | globalTransform dihitung saat disimpan; set transform.translation sebelum memanggil scene.save() |
GLB menghasilkan terpisah .bin sidecar | binaryMode default ke false | Atur saveOpts.binaryMode = true |
Lihat Juga
- Fitur dan Fungsionalitas: referensi API lengkap untuk semua area fitur.
- Dukungan Format: format 3D yang didukung, kemampuan baca/tulis, dan opsi format.
- Cara Membuat Mesh 3D Secara Programatik