Як програмно створити 3D‑меш у TypeScript

Як програмно створити 3D‑меш у TypeScript

Aspose.3D FOSS for TypeScript дозволяє створювати 3D‑геометрію повністю в коді без завантаження будь‑якого файлу. Ви визначаєте позиції вершин як контрольні точки, вказуєте полігональні грані за індексом і додаєте необов’язкові елементи вершин, такі як нормалі, UV‑координати або кольори вершин. Результат можна зберегти в будь‑який записуваний формат: glTF, GLB, STL, FBX або COLLADA.

Вимоги

  • Node.js 18 або новіше
  • TypeScript 5.0 або новіше
  • @aspose/3d встановлено (див. крок 1)

Покроковий посібник

Крок 1: Встановити @aspose/3d

npm install @aspose/3d

Ніякі нативні аддони чи системні бібліотеки не потрібні. Пакет включає визначення типів TypeScript.

Мінімум tsconfig.json:

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

Крок 2: Створити сцену та вузол

Scene — це контейнер верхнього рівня. Уся геометрія повинна бути приєднана до Node у дереві сцени:

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

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

createChildNode(name) створює іменований вузол і підключає його як дочірній до поточного вузла. Повернутий об’єкт Node — це те місце, куди ви приєднаєте сітку у кроці 7.


Крок 3: Створити Mesh Object

Mesh містить позиції вершин та визначення полігонів. Створіть один з необов’язковою назвою:

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

const mesh = new Mesh('triangle');

Мережа починає порожньою: немає вершин і граней. Ви додаєте їх у наступних кроках.


Крок 4: Додати контрольні точки (вершини)

Контрольні точки — це позиції вершин у локальному просторі. Перенесіть значення Vector4 у mesh.controlPoints. Четвертий компонент (w) є 1 для позицій:

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

Ви посилаєтеся на ці позиції за їх індексом, що починається з нуля, під час визначення граней полігонів.


Крок 5: Створити багатокутні грані

createPolygon() визначає грань, перераховуючи індекси вершин у порядку. Три індекси утворюють трикутник:

mesh.createPolygon(0, 1, 2);

Ви також можете визначати квадрати (чотири індекси) або довільні багатокутники для форматів, які їх підтримують. Для glTF бібліотека автоматично триангуляє квадрати та n-gons під час експорту.


Крок 6: Додати нормалі вершин

Нормалі покращують якість рендерингу. Використайте mesh.createElement() для створення VertexElementNormal, зберіть вектори нормалей у масив, а потім викличте setData() для їх збереження. Геттер data повертає захисну копію — додавання елементів до неї не має ефекту. Використовуйте FVector3 (одинарної точності float) для даних нормалей, а не 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 означає один нормаль на вершину. ReferenceMode.DIRECT означає, що масив даних індексується безпосередньо індексом вершини полігону.


Крок 7: Прикріпити сітку та зберегти у glTF

Призначте сітку вузлу за допомогою node.entity, потім збережіть сцену:

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');

Щоб створити один самодостатній .glb‑файл, встановіть saveOpts.binaryMode = true і змініть розширення вихідного файлу на .glb.

Повний приклад

Нижче наведено повний скрипт, який об’єднує всі кроки вище:

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');

Запустити з ts-node:

npx ts-node triangle.ts

Типові проблеми

IssueCauseFix
mesh.controlPoints.length дорівнює 0 після pushСітка не використовується жодним вузломВиконайте push перед присвоєнням node.entity; порядок не має значення, але перевірте посилання
Експорт створює порожню геометріюnode.entity не присвоєноПереконайтеся, що node.entity = mesh виконано перед викликом scene.save()
Несумісність кількості нормалейМасив, переданий у setData(), коротший за controlPointsДодайте один запис FVector3 на кожну контрольну точку при використанні MappingMode.CONTROL_POINT
glTF‑переглядач показує чорну сіткуНормалі спрямовані всерединуЗмініть порядок обходу у createPolygon (наприклад, 0, 2, 1) або інвертуйте вектори нормалей
TypeScript: властивість ’normals.data’ не знайденаНеправильний шлях імпортуІмпортуйте VertexElementNormal з @aspose/3d/entities, а не з кореня @aspose/3d

Часті запитання

Чи можу я створювати квадрати замість трикутників?
Так. Передайте чотири індекси до createPolygon(0, 1, 2, 3). Бібліотека триангуляє квадрати під час експорту у формати, які вимагають трикутників (glTF, STL).

Яка різниця між MappingMode.CONTROL_POINT та MappingMode.POLYGON_VERTEX?
CONTROL_POINT зберігає одне значення для кожної унікальної вершини. POLYGON_VERTEX зберігає одне значення для кожної пари полігон‑вершина, що дозволяє мати різні нормалі в одній і тій же вершині, коли вона належить кільком полігонам (жорсткі краї).

Чи потрібно триангуляти сітку перед збереженням у STL?
Ні. Бібліотека автоматично виконує триангуляцію під час експорту у формати, які вимагають трикутники. Ви можете визначати чотирикутники та n‑багатокутники у сітці та зберігати безпосередньо у STL.

Як додати UV‑координати?
Використовуйте mesh.createElementUV(TextureMapping.Diffuse, MappingMode.CONTROL_POINT, ReferenceMode.DIRECT) для створення VertexElementUV, потім викличте setData([...]) з масивом значень FVector2 або FVector3 — по одному на контрольну точку. Геттер data повертає копію; не додавайте до нього безпосередньо.

Чи можу я створювати кілька сіток в одній сцені?
Так. Створіть кілька вузлів під scene.rootNode і призначте окремий Mesh для властивості entity кожного вузла.

Дивіться також

 Українська