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/3dinstalled (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.tsCommon Issues
| Issue | Cause | Fix |
|---|---|---|
mesh.controlPoints.length is 0 after push | Mesh not referenced by any node | Push before assigning node.entity; order does not matter, but verify the reference |
| Export produces empty geometry | node.entity not assigned | Ensure node.entity = mesh before calling scene.save() |
| Normal count mismatch | data array shorter than controlPoints | Add one normal entry per control point when using MappingMode.ControlPoint |
| glTF viewer shows black mesh | Normals pointing inward | Reverse winding order in createPolygon (e.g., 0, 2, 1) or negate normal vectors |
| TypeScript: ’normals.data’ property not found | Wrong import path | Import 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.