How to Build a 3D Mesh Programmatically in TypeScript

How to Build a 3D Mesh Programmatically in TypeScript

Aspose.3D FOSS for TypeScript lets you build 3D geometry entirely in code without loading any file. You define vertex positions as control points, specify polygon faces by index, and attach optional vertex elements such as normals, UVs, or vertex colors. The result can be saved to any writable format — glTF, GLB, STL, FBX, or COLLADA.

Prerequisites

  • Node.js 16 or later
  • TypeScript 5.0 or later
  • @aspose/3d installed (see Step 1)

Step-by-Step Guide

Complete Example

The following is the full script combining all steps above:

import { Scene } from '@aspose/3d';
import { Mesh, VertexElementNormal } from '@aspose/3d/entities';
import { VertexElementType, MappingMode, ReferenceMode } from '@aspose/3d/entities';
import { Vector4 } 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.ControlPoint,
    ReferenceMode.Direct
) as VertexElementNormal;
normals.data.push(new Vector4(0, 0, 1, 0));
normals.data.push(new Vector4(0, 0, 1, 0));
normals.data.push(new Vector4(0, 0, 1, 0));

node.entity = mesh;

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

Run with ts-node:

npx ts-node triangle.ts

Common Issues

IssueCauseFix
mesh.controlPoints.length is 0 after pushMesh not referenced by any nodePush before assigning node.entity; order does not matter, but verify the reference
Export produces empty geometrynode.entity not assignedEnsure node.entity = mesh before calling scene.save()
Normal count mismatchdata array shorter than controlPointsAdd one normal entry per control point when using MappingMode.ControlPoint
glTF viewer shows black meshNormals pointing inwardReverse winding order in createPolygon (e.g., 0, 2, 1) or negate normal vectors
TypeScript: ’normals.data’ property not foundWrong import pathImport VertexElementNormal from @aspose/3d/entities, not from @aspose/3d root

Frequently Asked Questions

Can I create quads instead of triangles? Yes. Pass four indices to createPolygon(0, 1, 2, 3). The library triangulates quads during export to formats that require triangles (glTF, STL).

What is the difference between MappingMode.ControlPoint and MappingMode.ByPolygonVertex? ControlPoint stores one value per unique vertex. ByPolygonVertex stores one value per polygon-vertex pair, which allows different normals at the same vertex when it belongs to multiple polygons (hard edges).

Do I need to triangulate the mesh before saving to STL? No. The library handles triangulation automatically when exporting to formats that require triangles. You can define quads and n-gons in the mesh and save to STL directly.

How do I add UV coordinates? Use mesh.createElementUV(TextureMapping.Diffuse, MappingMode.ControlPoint, ReferenceMode.Direct) to create a VertexElementUV, then push Vector4 values into its data array, one per control point.

Can I build multiple meshes in one scene? Yes. Create multiple nodes under scene.rootNode and assign a separate Mesh to each node’s entity property.

See Also