How to convert STEP to OBJ
- Open the STEP sourceChoose a .step or .stp document. The reader resolves ISO 10303 Part 21 entities such as advanced_face, edge_curve and manifold_solid_brep, rebuilding trimmed NURBS surfaces and the named product structure before any text line is written.
- Set the mesh toleranceSelect one of the four deflection presets from coarse to maximal. The chosen linear chord bound and angular bound decide how densely curved faces are subdivided and therefore how many vertices the OBJ will list.
- Discretise each faceAn OpenCascade kernel compiled to WebAssembly samples every analytic surface into triangles, deriving a normal per vertex from the underlying geometry so that the vn records can be populated later.
- Merge the trianglesEvery facet is concatenated into one mesh exposing position plus normal arrays, with no material, UV, or group data, so the assembly hierarchy and part names vanish at this point.
- Emit OBJ recordsThe writer prints v lines for coordinates, vn lines for normals and f lines for triangular faces, skipping vt, .mtl, group and object lines, and delivers a single .obj text file.
What happens when STEP is converted to OBJ
OBJ as a line-oriented text format
Wavefront OBJ is an ASCII, line-based interchange format rather than a binary container. Each record begins with a keyword: v introduces a vertex coordinate triple, vn a normal vector, vt a texture coordinate, and f a face built from vertex references. Optional g and o lines name groups and objects, while a separate .mtl sidecar file, referenced by an mtllib line, holds materials. Because it is plain text, an OBJ can be opened in any editor and parsed with simple tokenisation, but it carries no binary precision and no mandatory header, so all structural meaning lives in those keywords and their argument order.
Exactly which records this converter writes
The exporter emits only three record types: v for positions, vn for normals and f for faces. It writes no vt texture lines, no mtllib or usemtl directives, no .mtl file and no g or o grouping lines. Every f line references three vertices, even though the OBJ specification allows polygons with four or more corners; the tessellated STEP faces are triangles, so the output is purely triangular. A typical face token takes the form v//vn, an index pair that points into the earlier v and vn lists, letting the single mesh reuse one shared normal per referenced vertex.
One-based indexing and shared vertices
Unlike STL, which repeats three raw coordinates per facet, OBJ stores a vertex pool once and refers to it by a one-based integer index from each face line. A negative index is legal too, counting backwards from the most recently declared vertex, though this writer uses positive forward references. Triples such as v/vt/vn or v//vn address position, texture and normal lists respectively; since no vt lines exist here, the middle slot is empty. This indexed layout means a vertex sitting on many triangles is transmitted a single time, which for a densely tessellated STEP model produces a noticeably smaller coordinate section than a flat triangle soup would.
How STEP surfaces become OBJ triangles
A STEP solid is defined by analytic geometry, so it cannot be written as text vertices until it is discretised. An OpenCascade kernel compiled to WebAssembly walks each trimmed advanced_face and inserts triangles until a linear chord tolerance and an angular tolerance are both satisfied; the coarse-to-maximal presets choose how tight those bounds are. During this pass a normal is sampled from the exact surface at each generated vertex, which is why the vn block exists at all. Curvature is only approximated: a cylinder becomes a polygonal prism whose facet count depends on the selected deflection.
Flattening into a single geometry
Whatever product hierarchy the STEP file contained, the exporter concatenates all sampled triangles into one BufferGeometry carrying just position and normal attributes. Placement matrices from the assembly are applied to the coordinates directly, so sub-components lose their individual transforms and names. There is no index of shared vertices kept as a separate group, no material slot, no UV channel and no object list, since the OBJ describes one unnamed surface. This is why g and o lines are absent: with a lone merged mesh there is nothing meaningful to name or separate.
Normals and the question of units
The vn records preserve the per-vertex normals sampled during tessellation, so smooth shading is possible, yet many importers disregard them and rebuild normals from face winding, which can alter the look of a gently curved region. OBJ declares no measurement unit at all: each v coordinate is a bare decimal with no mm or inch tag, and the writer does not smuggle a unit into a comment line. A STEP source may well have named a length unit, but that intent evaporates at export, leaving the importer to choose a scale by itself with nothing in the file to record the decision.
STEP vs OBJ
| STEP boundary representation | Wavefront OBJ text | |
|---|---|---|
| property | STEP document | OBJ text |
| Storage form | ISO 10303 Part 21 text entities | Line-oriented ASCII records |
| Geometry basis | Exact NURBS and trimmed faces | Triangulated v/vn/f records |
| Vertex referencing | Shared topological vertices | One-based v/vn indices |
| Face shape | Analytic bounded surfaces | Triangles only (no quads) |
| Materials | Colours in AP214/AP242 | No .mtl, no usemtl |
| Texture coordinates | Optional presentation data | No vt lines |
| Groups / objects | Named product hierarchy | No g or o lines |
| Units | Declared SI unit | None in text |
| Normals | Implicit from analytic surfaces | vn records, optionally recomputed |
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
No materials, colours or textures
A .mtl sidecar is the standard way OBJ carries diffuse colours, specular terms and texture maps, but this converter writes no .mtl, no mtllib line, no usemtl directive and no vt coordinates. The flattened BufferGeometry holds only position and normal arrays, so per-face STEP colour assignments and any texture coordinates are discarded before a single line is printed. An importer that expects a material library will find the object unshaded, typically falling back to a neutral default. Anyone needing appearance data must re-author it downstream rather than recover it from this .obj.
No unit declaration in the text
Wavefront OBJ has no header field for a measurement scale, and the v triples here are raw floating-point decimals copied from the tessellated coordinates. The converter does not add a comment stating millimetres, nor does it rescale an inch-based STEP part, so a model authored in imperial units arrives numerically unchanged and may be read as far too small. Verifying the model extents inside the destination program and dialling in an explicit scale there remains the practical fix, because the .obj itself gives no hint of the intended physical size.
Triangular faces only
OBJ face records may legally describe quads or n-gons, yet every f line produced here binds exactly three vertex references in v//vn form, because the OpenCascade tessellation outputs triangles and the writer makes no attempt to weld coplanar neighbours back into larger polygons. Most mesh consumers triangulate on import regardless, so this is usually invisible, but a workflow that relies on genuine quad topology will not recover it here. The f-line total therefore equals the generated triangle count, and tightening the deflection preset multiplies it in step. Winding order is preserved from the tessellator so that every three-index f record keeps a consistent outward-facing orientation for back-face culling.
No groups, objects or assembly parts
A STEP assembly carries a product tree of named components, each with a placement transform, plus optional AP242 PMI annotations. OBJ can express g and o names, but this writer emits neither, since all solids are fused into one geometry with transforms baked into the vertex coordinates. The result is a single unnamed object with no way to select an individual bolt or housing inside it. Part names, the bill of materials and any grouping vanish; keeping components apart requires exporting them as separate files rather than one combined .obj, then re-assembling them downstream.
Exact surfaces and normals are not guaranteed
Curved STEP faces survive only as polygonal approximations whose chord error is set by the chosen deflection, so a perfect bore becomes a finite-sided hole. Per-vertex vn lines are present, but they are optional hints: an importer is free to recompute normals from triangle winding, and doing so on a coarse mesh produces visible facets. Combined with the absence of any parametric feature tree, re-importing the .obj yields a static, triangulated shell that must be reverse-engineered to recover design intent. Finer presets shrink the geometric error at the price of a longer text file.
Frequently asked questions
Is an .mtl material file included?
No. The converter emits only v, vn and f lines and writes no .mtl sidecar, no mtllib reference and no usemtl directive. Because the merged mesh carries nothing beyond position and normal arrays, STEP colour assignments and textures are dropped before serialization. Most importers will display the object with a neutral default material. If you need appearance, you have to author a material library yourself after the fact rather than extract it from this file.
Are the faces triangles or quads?
Every f record references three vertices, so the geometry is entirely triangular even though the OBJ specification also permits quads and n-gons. That is because the OpenCascade tessellator outputs triangles and the writer does not recombine coplanar neighbours into larger polygons. The f-line count therefore equals the generated triangle total. Consumers that triangulate on import are unaffected, but anyone expecting quad topology will not find it here.
What measurement unit does the OBJ use?
OBJ has no unit field, and the v coordinates are bare decimal numbers with no millimetre or inch tag; the writer adds no clarifying comment either. A STEP source may have declared a length unit, but that information is not carried into the text. Importers commonly interpret the numbers as millimetres, so an inch-based part can appear dramatically undersized. Measure the model extents in the destination application and apply an explicit scale if the physical size matters.
Are UV texture coordinates (vt) written?
No vt lines appear in the output. The source STEP geometry is exact surface data rather than a mapped mesh, and the flattened BufferGeometry holds only position and normal attributes, so there are no texture coordinates to emit. Face records use the v//vn form with an empty texture slot. Any UV mapping must be generated later in a texturing tool; the .obj itself deliberately omits that channel.
Does the OBJ keep STEP colours?
Colours are not preserved. AP214 and AP242 can attach RGB values and material names to faces or parts, but the exporter strips appearance when it merges everything into one mesh with just position and normal arrays. OBJ would normally defer colour to a .mtl sidecar, and that sidecar is not produced. What a viewer shows is its own default shading, not data stored in the file, so plan to re-assign materials downstream.
Will the vertex normals be kept on import?
The file does contain vn lines holding normals sampled from the exact STEP surfaces during tessellation, so smooth shading is possible. They are advisory, however: many OBJ readers recompute normals from face winding and ignore the supplied vectors. When that happens on a coarsely meshed curve, the surface looks faceted despite the vn data being present. Whether you see smooth or flat shading therefore depends on the receiving program, not on this export.
Is the assembly hierarchy preserved?
No. Named products, sub-assemblies and placement matrices in the STEP tree are flattened into a single geometry, with transforms applied directly to the coordinate values. Since the writer emits no g or o lines, the result is one unnamed object with no selectable sub-parts. Part labels, the bill of materials and AP242 annotations are lost. To retain separation, export each component to its own .obj and rebuild the arrangement in the target scene.
Why can the OBJ text file get so large?
OBJ is an ASCII format, so every vertex, normal and face becomes a line of decimal numbers rather than a compact binary record. A fine deflection preset can generate a great many small triangles on curved faces, and each triangle adds an f line while shared vertices add v and vn lines. The indexed layout avoids repeating coordinates the way STL does, but high triangle counts still produce bulky text. Choosing a coarser preset is the main lever for size.
Related converters
All converters
Last updated: