How to convert STEP to 3MF
- Import the STEP partSelect a .step or .stp file; the reader reconstructs ISO 10303 advanced_face, edge_curve and manifold_solid_brep entities into exact trimmed NURBS surfaces and the product structure they belong to.
- Choose mesh densitySelect one of a quartet of chord-tolerance settings labelled Draft through Max; the chosen linear and angular bounds govern how finely curved faces are subdivided into triangles.
- Mesh the analytic facesTessellation is delegated to the OpenCascade WebAssembly module, which walks each B-rep face and inserts triangles until a chord-height bound and an angular bound are both satisfied.
- Collapse to one geometryAll surfaces collapse into a lone BufferGeometry that carries just positions and normals, stripping materials, texture coordinates, groups and any part structure before packaging.
- Build the 3MF packageThe writer zips [Content_Types].xml, _rels/.rels and 3D/3dmodel.model into a .3mf OPC container whose model declares millimetres and holds a single uncoloured object.
What happens when STEP is converted to 3MF
3MF is an OPC ZIP container
A .3mf file is not a flat stream but a ZIP archive following the Open Packaging Conventions. At minimum it holds [Content_Types].xml, which maps part names to content types, _rels/.rels, which points to the root 3D model, and 3D/3dmodel.model, the XML payload. Entries are usually deflate-compressed and the archive ends with a central directory that lets a reader locate parts without scanning the whole file. Because the whole thing is a package, even a tiny mesh carries fixed container overhead: the XML declarations, relationship records and ZIP bookkeeping occupy bytes that a raw STL or OBJ would not spend. This structure also allows 3MF to hold optional thumbnails and metadata parts alongside geometry.
Inside 3dmodel.model
The model document is XML whose core geometry lives in a <mesh> element. That element contains a <vertices> list of <vertex x= y= z=> positions and a <triangles> list of <triangle v1= v2= v3=> records referencing those vertices by index. A surrounding <object> (with an optional <components> or <build> section) places the mesh into the scene. This is an indexed representation: a vertex shared by many triangles is declared once and cited repeatedly, in contrast to a binary STL facet, which repeats all three coordinates every time. The converter emits exactly one such <object> and one <mesh>, with no <color>, <basematerials> or <texture> elements.
The declared millimetre unit
Unlike unit-less mesh targets, 3MF carries an explicit unit attribute on the <model> element, and this converter sets it to millimetres. A consuming slicer reads that attribute and interprets every stored coordinate as a millimetre value, so a STEP part whose source declared inches would need its coordinates rescaled to match; the writer does not inject such a conversion, it simply tags the tessellated numbers as mm. This declaration is one of 3MF's main advantages for additive manufacturing: physical size is recorded in the file rather than guessed by convention. It does not, however, restore any unit-dependent metadata that was dropped during flattening.
Tessellating the STEP boundary representation
A STEP solid's exact NURBS patches and trimmed faces cannot be placed directly into a <vertices>/<triangles> mesh, so they are discretised first. The OpenCascade WebAssembly kernel evaluates each face and subdivides until a linear chord-height tolerance and an angular tolerance are both met; the four presets from Draft to Max pick how tight those limits are. Curved surfaces therefore remain approximations: a cylindrical hole becomes a many-sided polygon, and finer settings increase the triangle count stored in <triangles>. A normal is sampled at each generated vertex during this pass, though the core <mesh> schema records positions and connectivity rather than normal attributes.
What the single object contains
Although 3MF can represent multiple objects, colour groups, material definitions and several <build> items, this exporter writes a single object holding one mesh and one build item. Every solid from the STEP assembly is fused into that lone geometry, with placement transforms baked into the coordinates, so named parts, PMI annotations and the product hierarchy disappear. There is no <basematerials> block, no per-triangle colour via <color> and no material indices on the triangle records. The result is one uncoloured, untextured mesh, a deliberate simplification that follows from the earlier collapse into a single BufferGeometry.
Normals, indexing and container cost
The <mesh> element stores vertex positions and triangle connectivity but no explicit normal vectors; shading is derived by the consuming application from the triangle winding, which on a coarse mesh yields visible faceting. Index reuse keeps the coordinate list compact, since a vertex used by dozens of triangles appears once in <vertices>, yet the surrounding ZIP adds [Content_Types].xml, relationship parts and deflate overhead that a bare mesh format avoids. The chosen deflection preset dominates size: more triangles mean more <triangle> records and more <vertex> entries, so a Max-quality export can be far larger than a Draft one even after ZIP compression.
STEP vs 3MF
| STEP ISO 10303 solid | 3MF package | |
|---|---|---|
| aspect | STEP solid | 3MF package |
| Container | Part 21 text entities | OPC ZIP with XML parts |
| Geometry basis | Exact trimmed NURBS faces | Indexed <vertices>/<triangles> mesh |
| Units | Declared SI unit | millimetre attribute on <model> |
| Vertex storage | Shared topological vertices | Declared once, referenced by index |
| Colour / materials | AP214/AP242 assignments | None; single uncoloured object |
| Assembly structure | Named product hierarchy | Single <object> and <build> item |
| Normals | Implicit analytic normals | Derived from winding; not stored |
| Compression | Plain text | Deflate-compressed ZIP parts |
| Curvature | Exact surfaces | Triangle approximation by deflection |
Supported formats
| Format | Read | Write | Notes |
|---|---|---|---|
| STEP (.step .stp) | Yes | – | ISO 10303 B-rep, AP203 / AP214 / AP242 |
| IGES (.iges .igs) | Yes | – | Entity-based surfaces, up to 5.3 |
| BREP (.brep) | Yes | – | OpenCascade native B-rep |
| STL (.stl) | Yes | Yes | Binary and ASCII triangles, no units |
| OBJ (.obj) | Yes | Yes | v / vn / f records; .mtl references ignored |
| PLY (.ply) | Yes | Yes | Binary position and normal arrays |
| GLB / glTF (.glb .gltf) | Yes | Yes | glTF 2.0, binary or JSON with data URI |
| 3MF (.3mf) | Yes | Yes | OPC/ZIP package, declares millimetres |
| FBX (.fbx) | Yes | – | Binary and ASCII, static mesh only |
| DAE (.dae) | Yes | – | Collada scene graph is flattened |
| 3DS (.3ds) | Yes | – | Legacy chunk-based 3D Studio format |
| AMF (.amf) | Yes | – | XML, ZIP-compressed packages supported |
| USDZ (.usdz) | Yes | Yes | ZIP containing a USD stage |
Known limitations and why a conversion can fail
One object, no colour or materials
The 3MF specification supports <color>, <basematerials>, <texture2d>, multiple <object> elements and several <build> items, but this converter uses none of them. All STEP solids are merged into a single mesh with one build item, and appearance data such as AP214 or AP242 RGB face colours is dropped along with the flattened geometry's unused material, UV and group channels. The packaged <mesh> therefore holds only positions and triangle indices. Triangle records carry no material-index attribute, and no <colorgroup> element appears anywhere in the model part. Anyone expecting coloured, multi-material or multi-part output must add those structures in a downstream 3MF editor; they are not reconstructed here.
Assembly hierarchy and PMI are lost
A STEP product tree may contain dozens of named components, each with a placement matrix, plus AP242 annotations, tolerances and a bill of materials. Because the exporter bakes transforms into vertex coordinates and writes a lone <object>, none of that structure reaches the 3MF build section. There are no <components> references and no per-part identifiers to select or reposition an individual bolt after import. PMI and face names are likewise discarded. Retaining separation means producing a separate .3mf per component and rebuilding the arrangement in the target tool, since one combined package cannot express it.
Curved surfaces remain polygonal
Declaring millimetres does not make the geometry exact. Every NURBS patch, cylinder or fillet is approximated by triangles whose chord error is bounded by the selected Draft, Standard, Fine or Max preset, so a nominally round bore is a finite-sided prism in the <triangles> list. Finer presets shrink that deviation but multiply the number of triangle records and vertex entries, inflating the XML payload and the compressed package. No parametric feature tree, constraint or dimension survives, so re-importing the 3MF gives a static mesh that must be reverse-engineered to recover design intent.
Shading normals are not stored
The core <mesh> schema written here contains <vertices> and <triangles> only; it carries no normal attributes, even though per-vertex normals were sampled during tessellation. A reader reconstructs shading from face winding, and on a coarse mesh that produces faceted highlights where the original STEP surface was smooth. There is no smoothing-group or per-triangle normal field in this minimal output to override that behaviour. Whether a curved wall looks smooth or segmented is consequently decided by the consuming application, not by data embedded in the .3mf. Finer deflection helps by shrinking each facet, but cannot add stored normals the package never included.
ZIP packaging adds fixed overhead
Because 3MF is an OPC archive, even a single tiny mesh must carry [Content_Types].xml, _rels/.rels, the 3D/3dmodel.model part, ZIP local headers and a central directory. Those bytes are spent regardless of triangle count, so a very small Draft export can be proportionally larger than an equivalent raw triangle stream. Deflate compression helps with repetitive XML, but the mandatory parts remain. Each ZIP entry also pays for a local file header, a data descriptor and its filename, and the central directory repeats those names once more. Combined with the deflection-driven growth of <vertex> and <triangle> records, file size reflects both the chosen mesh density and the unavoidable container scaffolding.
Frequently asked questions
What unit does the 3MF declare?
The <model> element is written with its unit attribute set to millimetres, so a slicer reads every stored coordinate as a mm value. This is a real declaration inside the file, unlike the bare numbers in unit-less mesh targets. The converter does not convert an inch-based STEP part into different coordinates, however; it tags the tessellated numbers as mm. If the source used another unit, rescale before export or correct the physical size downstream.
Does the 3MF keep colours or materials?
No. Although 3MF supports <color>, <basematerials>, texture parts and multiple objects, this exporter writes a single uncoloured mesh with one build item. STEP AP214 and AP242 colour assignments are discarded when the geometry is flattened into a lone BufferGeometry carrying only position and normal arrays. There are no material indices on the triangle records. Appearance has to be authored afterwards in a 3MF-capable editor; the package itself stores pure geometry.
What files are inside the .3mf archive?
A .3mf is a ZIP package following the Open Packaging Conventions. This converter includes [Content_Types].xml, which maps part names to content types, _rels/.rels, which locates the root model, and 3D/3dmodel.model, the XML geometry payload. Those mandatory parts plus ZIP headers and the central directory add fixed overhead to every export. You can inspect the structure by opening the file with any ZIP tool, though the model part is the only one carrying triangles.
Are vertices shared or repeated?
They are shared. The <vertices> element declares each coordinate once, and every <triangle v1= v2= v3=> record refers back to those positions by integer index. A vertex touching many facets is therefore stored a single time, which is more compact than a binary STL facet that repeats all three coordinates for every triangle. This indexed layout is a core 3MF trait; the converter preserves it when it funnels the merged mesh into one <mesh> element.
Is the STEP assembly kept as separate objects?
No. Named products, sub-assemblies and placement transforms are collapsed into a single <object> with one <build> item, and the transforms are baked into the vertex coordinates. Because the writer emits no <components> references and no additional objects, individual bolts or housings cannot be selected or moved after import. Part names, the bill of materials and AP242 annotations are lost. Exporting each component as its own .3mf is the only way to keep them apart.
Does the 3MF store surface normals?
The <mesh> written here contains <vertices> and <triangles> but no normal attributes, even though normals were sampled from the exact STEP surfaces during tessellation. A consuming application derives shading from the triangle winding instead, which on a coarse mesh produces visible faceting. There is no smoothing-group field in this minimal output to override that. A finer deflection preset reduces facet size but cannot introduce stored normals that the package never included.
Are curved STEP faces still exact?
No. NURBS patches, cylinders and fillets are approximated by triangles whose deviation is bounded by the Draft, Standard, Fine or Max deflection, so a round bore becomes a finite-sided polygon in the <triangles> list. Declaring millimetres fixes scale, not precision. Parametric features, constraints and dimensions are absent, so the 3MF is a static mesh that would need reverse-engineering to recover the original design. Finer presets reduce chord error at the cost of more XML records.
Why is the 3MF bigger than a raw mesh?
Two effects combine. First, 3MF is an OPC ZIP archive, so [Content_Types].xml, _rels/.rels, ZIP local headers and the central directory add fixed bytes no flat triangle format pays. Second, the XML <vertices> and <triangles> records are verbose text, and a fine deflection preset multiplies their number. Deflate compression softens the repetition but cannot remove the mandatory package parts, so both container scaffolding and mesh density drive the final file size.
Related converters
All converters
Last updated: