Làm việc với Đồ thị Cảnh
Tất cả nội dung 3D trong Aspose.3D FOSS cho TypeScript nằm bên trong một Scene đối tượng được tổ chức thành một cây của Node các đối tượng. Hiểu được cấu trúc này là nền tảng để xây dựng, tải và xử lý bất kỳ tệp 3D nào.
Cài đặt
Cài đặt gói từ npm trước khi chạy bất kỳ đoạn mã nào trong hướng dẫn này:
npm install @aspose/3dĐảm bảo rằng tsconfig.json bao gồm "module": "commonjs" và "moduleResolution": "node" để giải quyết đúng việc nhập khẩu các đường dẫn phụ.
Các khái niệm Đồ thị Cảnh
Đồ thị cảnh có ba cấp:
| Cấp | Lớp | Vai trò |
|---|---|---|
| Cảnh | Scene | Bộ chứa cấp cao nhất. Chứa rootNode, animationClips, và assetInfo. |
| Nút | Node | Nút cây có tên. Có thể có các nút con, một thực thể, một phép biến đổi và các vật liệu. |
| Thực thể | Mesh, Camera, Light, … | Nội dung được gắn vào một nút. Một nút chỉ chứa tối đa một thực thể. |
Chuỗi kế thừa cho các khối xây dựng chính là:
A3DObject
└─ SceneObject
├─ Node (tree structure)
└─ Entity
└─ Geometry
└─ Mesh (polygon geometry)scene.rootNode được tạo tự động. Bạn không tạo nó theo cách thủ công; bạn tạo các nút con dưới nó.
Step 1: Create a 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)
Mới Scene bắt đầu với một nút gốc trống và không có clip hoạt hình. Bạn xây dựng nội dung bằng cách gắn các nút con.
Bước 2: Thêm các nút con
Sử dụng createChildNode() để phát triển cây. Phương thức trả về đối tượng mới Node, vì vậy bạn có thể nối các lời gọi tiếp theo từ bất kỳ cấp độ nào:
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)
Tên nút là các chuỗi tùy ý. Tên không cần phải duy nhất, nhưng việc sử dụng tên có ý nghĩa giúp mã duyệt dễ dàng gỡ lỗi hơn.
Bước 3: Tạo một Mesh và Đặt các đỉnh
Mesh là lớp hình học chính. Thêm vị trí đỉnh bằng cách đẩy Vector4 giá trị vào mesh.controlPoints, sau đó gọi createPolygon() để định nghĩa các mặt bằng chỉ số đỉnh:
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 sử dụng tọa độ đồng nhất: w thành phần là 1 cho vị trí và 0 cho các vector hướng.
Step 4: Set Node Transforms
Mỗi nút có một transform thuộc tính với translation, rotation, và scaling. Đặt translation để di chuyển nút tương đối so với cha của nó:
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 cung cấp ma trận biến đổi không gian thế giới (chỉ đọc), được tính bằng cách nối tất cả các biến đổi của tổ tiên.
Bước 5: Duyệt cây
Viết một hàm đệ quy để duyệt mọi nút. Kiểm tra node.entity và node.childNodes tại mỗi cấp độ:
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);Đối với cấu trúc phân cấp được tạo ở trên, đầu ra sẽ là:
[none]
parent [none]
child [Mesh]Tên nút gốc là một chuỗi rỗng vì Scene tạo nó mà không có đối số tên.
Luôn bảo vệ việc truy cập thực thể bằng kiểm tra null trước khi ép kiểu sang một loại cụ thể. Không phải mọi nút đều mang một thực thể.
Bước 6: Lưu dưới dạng glTF hoặc GLB
Sử dụng GltfSaveOptions để kiểm soát định dạng đầu ra. Đặt binaryMode = true để tạo một tệp tự chứa duy nhất .glb tệp; để lại nó false cho JSON .gltf + .bin cặp 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');Truyền GltfFormat.getInstance() làm đối số định dạng để thư viện sử dụng bộ mã hoá đúng bất kể phần mở rộng tệp.
Mẹo và Thực hành Tốt nhất
- Sử dụng
createChildNode()thay vì xây dựngNodetrực tiếp:createChildNode()tự động kết nối quan hệ cha-con và đăng ký nút trong cây. - Kiểm tra
node.entitytrước khi truy cập các thuộc tính của thực thể: nhiều nút (các nút nhóm, xương, bộ định vị) không có thực thể. Luôn bảo vệ bằng một kiểm tra null hoặcinstanceofkiểm tra. - Thiết lập
translationtrên các nút con, không phải trên các đỉnh lưới: sửa đổitransform.translationkhông phá hủy và có thể kết hợp với các biến đổi cha. - Ưu tiên
binaryMode = truecho GLB: một.glbtệp dễ dàng phân phối, tải trong trình duyệt và nhập vào các engine game hơn so với dạng chia tách.gltf+.binđịnh dạng. - Duyệt qua
for...oftrênchildNodes: tránh chỉ mục số; sử dụng trực tiếp iterable để tương thích về phía trước.
Các vấn đề thường gặp
| Triệu chứng | Nguyên nhân có khả năng | Khắc phục |
|---|---|---|
child.entity = mesh không ảnh hưởng đến việc xuất | Thực thể được gán vào mức nút sai | Gán entity đến nút lá, không phải nút nhóm |
node.entity luôn luôn null | Chỉ kiểm tra rootNode chính nó | Đệ quy vào node.childNodes; rootNode thường không có thực thể |
| Biến đổi không được phản ánh trong trình xem GLB | globalTransform không được cập nhật | globalTransform được tính khi lưu; đặt transform.translation trước khi gọi scene.save() |
GLB tạo ra một tệp riêng .bin tệp phụ | binaryMode mặc định là false | Đặt saveOpts.binaryMode = true |
Xem Thêm
- Tính năng và Chức năng: tài liệu tham chiếu API đầy đủ cho tất cả các khu vực tính năng.
- Hỗ trợ định dạng: các định dạng 3D được hỗ trợ, khả năng đọc/ghi, và các tùy chọn định dạng.
- Cách xây dựng 3D Mesh bằng lập trình.