Cách tạo lưới 3D bằng lập trình trong TypeScript

Cách tạo lưới 3D bằng lập trình trong TypeScript

Aspose.3D FOSS for TypeScript cho phép bạn xây dựng hình học 3D hoàn toàn bằng mã mà không cần tải bất kỳ tệp nào. Bạn định nghĩa vị trí đỉnh dưới dạng các điểm điều khiển, chỉ định các mặt đa giác bằng chỉ mục, và gắn các phần tử đỉnh tùy chọn như vector pháp tuyến, UV, hoặc màu đỉnh. Kết quả có thể được lưu vào bất kỳ định dạng ghi được nào: glTF, GLB, STL, FBX, hoặc COLLADA.

Điều kiện tiên quyết

  • Node.js 18 hoặc mới hơn
  • TypeScript 5.0 hoặc mới hơn
  • @aspose/3d đã cài đặt (xem Bước 1)

Hướng Dẫn Từng Bước

Bước 1: Cài đặt @aspose/3d

npm install @aspose/3d

Không cần addon gốc hay thư viện hệ thống. Gói bao gồm các định nghĩa kiểu TypeScript.

Tối thiểu tsconfig.json:

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "moduleResolution": "node",
    "esModuleInterop": true,
    "strict": true
  }
}

Bước 2: Tạo một Scene và Node

Một Scene là container cấp cao nhất. Tất cả hình học phải được gắn vào một Node trong cây cảnh:

import { Scene } from '@aspose/3d';

const scene = new Scene();
const node = scene.rootNode.createChildNode('triangle');

createChildNode(name) tạo một nút có tên và nối nó như một nút con của nút hiện tại. Đối tượng Node được trả về là nơi bạn sẽ gắn lưới trong Bước 7.


Bước 3: Tạo một Đối tượng Mesh

Mesh chứa các vị trí đỉnh và định nghĩa đa giác. Tạo một đối tượng với tên tùy chọn:

import { Mesh } from '@aspose/3d/entities';

const mesh = new Mesh('triangle');

Lưới bắt đầu trống rỗng: không có đỉnh và không có mặt. Bạn sẽ thêm chúng trong các bước tiếp theo.


Bước 4: Thêm các điểm điều khiển (đỉnh)

Các điểm điều khiển là vị trí đỉnh trong không gian cục bộ. Đẩy các giá trị Vector4 vào mesh.controlPoints. Thành phần thứ tư (w) là 1 cho các vị trí:

import { Vector4 } from '@aspose/3d/utilities';

mesh.controlPoints.push(new Vector4(0.0, 0.0, 0.0, 1.0)); // index 0
mesh.controlPoints.push(new Vector4(1.0, 0.0, 0.0, 1.0)); // index 1
mesh.controlPoints.push(new Vector4(0.5, 1.0, 0.0, 1.0)); // index 2

Bạn tham chiếu các vị trí này bằng chỉ mục bắt đầu từ 0 khi định nghĩa các mặt đa giác.


Bước 5: Tạo các mặt đa giác

createPolygon() định nghĩa một mặt bằng cách liệt kê các chỉ số đỉnh theo thứ tự. Ba chỉ số tạo thành một tam giác:

mesh.createPolygon(0, 1, 2);

Bạn cũng có thể định nghĩa các hình tứ giác (bốn chỉ số) hoặc các đa giác tùy ý cho các định dạng hỗ trợ chúng. Đối với glTF, thư viện sẽ tự động chia tứ giác và n-gons thành tam giác khi xuất.


Bước 6: Thêm pháp tuyến đỉnh

Các vector pháp tuyến cải thiện chất lượng hiển thị. Sử dụng mesh.createElement() để tạo một VertexElementNormal, thu thập các vector pháp tuyến vào một mảng, sau đó gọi setData() để lưu chúng. Phương thức getter data trả về một bản sao bảo vệ — việc đẩy vào nó không có tác dụng. Sử dụng FVector3 (số thực đơn độ chính xác) cho dữ liệu pháp tuyến, không phải Vector4.

import { VertexElementNormal } from '@aspose/3d/entities';
import { VertexElementType, MappingMode, ReferenceMode } from '@aspose/3d/entities';
import { FVector3 } from '@aspose/3d/utilities';

const normals = mesh.createElement(
    VertexElementType.NORMAL,
    MappingMode.CONTROL_POINT,
    ReferenceMode.DIRECT
) as VertexElementNormal;

// Build the normal array, then call setData() — do NOT push to normals.data
normals.setData([
    new FVector3(0, 0, 1), // normal for vertex 0 (pointing +Z)
    new FVector3(0, 0, 1), // normal for vertex 1
    new FVector3(0, 0, 1), // normal for vertex 2
]);

MappingMode.CONTROL_POINT có nghĩa là một pháp tuyến cho mỗi đỉnh. ReferenceMode.DIRECT có nghĩa là mảng dữ liệu được đánh chỉ mục trực tiếp theo chỉ số đỉnh đa giác.


Bước 7: Gắn Mesh và Lưu thành glTF

Gán lưới cho nút thông qua node.entity, sau đó lưu cảnh:

import { GltfSaveOptions, GltfFormat } from '@aspose/3d/formats/gltf';

node.entity = mesh;

const saveOpts = new GltfSaveOptions();
scene.save('triangle.gltf', GltfFormat.getInstance(), saveOpts);
console.log('Triangle mesh saved to triangle.gltf');

Để tạo một tệp .glb tự chứa duy nhất thay thế, hãy đặt saveOpts.binaryMode = true và thay đổi phần mở rộng tệp đầu ra thành .glb.

Ví dụ đầy đủ

Dưới đây là kịch bản đầy đủ kết hợp tất cả các bước ở trên:

import { Scene } from '@aspose/3d';
import { Mesh, VertexElementNormal } from '@aspose/3d/entities';
import { VertexElementType, MappingMode, ReferenceMode } from '@aspose/3d/entities';
import { Vector4, FVector3 } from '@aspose/3d/utilities';
import { GltfSaveOptions, GltfFormat } from '@aspose/3d/formats/gltf';

const scene = new Scene();
const node = scene.rootNode.createChildNode('triangle');

const mesh = new Mesh('triangle');

mesh.controlPoints.push(new Vector4(0.0, 0.0, 0.0, 1.0));
mesh.controlPoints.push(new Vector4(1.0, 0.0, 0.0, 1.0));
mesh.controlPoints.push(new Vector4(0.5, 1.0, 0.0, 1.0));

mesh.createPolygon(0, 1, 2);

const normals = mesh.createElement(
    VertexElementType.NORMAL,
    MappingMode.CONTROL_POINT,
    ReferenceMode.DIRECT
) as VertexElementNormal;

// setData() is the correct API — normals.data returns a defensive copy; pushing to it has no effect
normals.setData([
    new FVector3(0, 0, 1),
    new FVector3(0, 0, 1),
    new FVector3(0, 0, 1),
]);

node.entity = mesh;

const saveOpts = new GltfSaveOptions();
scene.save('triangle.gltf', GltfFormat.getInstance(), saveOpts);
console.log('Triangle mesh saved to triangle.gltf');

Chạy với ts-node:

npx ts-node triangle.ts

Các vấn đề thường gặp

IssueCauseFix
mesh.controlPoints.length là 0 sau khi đẩyMesh không được tham chiếu bởi bất kỳ node nàoĐẩy trước khi gán node.entity; thứ tự không quan trọng, nhưng hãy xác minh tham chiếu
Xuất tạo ra hình học rỗngnode.entity chưa được gánĐảm bảo node.entity = mesh trước khi gọi scene.save()
Số lượng pháp tuyến không khớpMảng truyền vào setData() ngắn hơn controlPointsThêm một mục FVector3 cho mỗi điểm điều khiển khi sử dụng MappingMode.CONTROL_POINT
Trình xem glTF hiển thị mesh đenPháp tuyến hướng vào trongĐảo ngược thứ tự winding trong createPolygon (ví dụ, 0, 2, 1) hoặc đảo dấu các vector pháp tuyến
TypeScript: không tìm thấy thuộc tính ’normals.data'Đường dẫn import saiImport VertexElementNormal từ @aspose/3d/entities, không phải từ gốc @aspose/3d

Câu hỏi thường gặp

Tôi có thể tạo các quad thay vì tam giác không?
Có. Gửi bốn chỉ mục tới createPolygon(0, 1, 2, 3). Thư viện sẽ chuyển đổi các quad thành tam giác khi xuất ra các định dạng yêu cầu tam giác (glTF, STL).

Sự khác nhau giữa MappingMode.CONTROL_POINTMappingMode.POLYGON_VERTEX là gì?
CONTROL_POINT lưu trữ một giá trị cho mỗi đỉnh duy nhất. POLYGON_VERTEX lưu trữ một giá trị cho mỗi cặp đa giác‑đỉnh, cho phép các pháp tuyến khác nhau tại cùng một đỉnh khi nó thuộc nhiều đa giác (cạnh cứng).

Tôi có cần phân tam giác lưới trước khi lưu thành STL không?
Không. Thư viện tự động xử lý việc phân tam giác khi xuất sang các định dạng yêu cầu tam giác. Bạn có thể định nghĩa các quad và n‑gon trong lưới và lưu trực tiếp thành STL.

Làm thế nào để thêm tọa độ UV?
Sử dụng mesh.createElementUV(TextureMapping.Diffuse, MappingMode.CONTROL_POINT, ReferenceMode.DIRECT) để tạo một VertexElementUV, sau đó gọi setData([...]) với một mảng các giá trị FVector2 hoặc FVector3 — một giá trị cho mỗi điểm điều khiển. Trình lấy giá trị data trả về một bản sao; không được đẩy trực tiếp vào nó.

Có thể xây dựng nhiều lưới trong một cảnh không?
Có. Tạo nhiều nút dưới scene.rootNode và gán một Mesh riêng cho thuộc tính entity của mỗi nút.

Xem thêm

 Tiếng Việt