Convert glTF to OBJ

A glTF is text but its geometry is not: the coordinates sit in a base64 buffer behind accessors and buffer views. Converting glTF to OBJ moves those numbers into the open, one vertex and one triangle per line, so you can count them, measure them or feed them to your own script without a glTF library.

  • Where it runs In your browser. The file is never uploaded.
  • Rebuilt OBJ works differently from a GLTF, so this is not the gradual degradation a lossy codec applies. What OBJ can express is reproduced faithfully; what it has no equivalent for does not survive at all.
  • File size limit Up to 100 MB per file, free, without an account.
  • Worth knowing Geometry only. Materials, colours, textures and animation are not carried across, and a model placed several times comes back with each copy baked into its own position.

Up to 100 files at once. Mixed formats are fine.

Why glTF to OBJ is a step down in indirection

Both formats are text, and that similarity is misleading. Opening a .gltf gives you a JSON document in which the vertex data is a base64 string on a buffer, sliced by byte offsets recorded in buffer views, interpreted by accessors that declare a component type and an element type. Four indirections stand between the file and a coordinate, and reading one out by hand is genuinely tedious.

An OBJ has none of that. A line beginning with v is a vertex and the three numbers after it are its coordinates. A line beginning with f is a triangle and the three numbers after it are indices into the vertex list. That is the whole grammar you need for the geometry, which is why OBJ has outlived every format designed to replace it whenever the task is inspection rather than rendering.

The exact shape of the OBJ this converter emits

A single comment line at the top naming the writer, then, per mesh: an o line carrying the mesh name from the glTF, a run of v lines, and a run of f lines. Nothing else appears — no vt texture coordinates, no vn normals, no s smoothing groups, no usemtl, no mtllib, and no blank-line separators to trip a naive splitter.

That makes the parser you would write for it about six lines long, and it makes tools like wc, grep and awk useful directly. Counting f lines gives the triangle count; counting v lines gives the vertex count. If you are writing something that consumes this output, note that the numbers are printed with JavaScript default float formatting, so you will see both 1 and 1.0000001 in the same file and should parse rather than pattern-match.

One-based indices, counted across the whole glTF

OBJ face indices start at one. They also run continuously through the file rather than restarting at each o group, which is the detail most hand-written parsers get wrong. The converter keeps a running vertex offset as it writes each mesh and adds it to every index in that mesh.

If you are reading the file back, the rule is: accumulate the count of v lines seen so far, and subtract one to get a zero-based index. Negative indices are legal in OBJ and count backwards from the most recent vertex — this writer never emits them, though the reader on the reverse pages accepts them, because plenty of exporters do use them.

Coordinates in the OBJ are world coordinates from the glTF scene

A glTF node tree can place a mesh anywhere through a chain of matrices, and can place the same mesh in several places at once. OBJ has no scene graph and no instancing, so the conversion resolves the tree: each node matrix is multiplied by its parent, and the world matrix is applied to every vertex before it is written.

The practical consequence for anyone measuring the result is good — the numbers you read are where the geometry actually is, not where it would be before a transform. The consequence for file size is that repeated instances become repeated vertex data. A glTF placing one bolt forty times yields forty groups of identical shape at forty different positions.

What the glTF document contains that the OBJ cannot express

Materials, textures, images, samplers, UV coordinates, normals, tangents, vertex colours, morph targets, skins, animation channels and samplers, cameras, lights, and any extension the file declares. None of them is read and none is written.

OBJ could in principle carry the UVs and normals, and a separate MTL could carry a material reference. This converter writes neither, because it moves geometry between six formats and inventing a material file from data it never extracted would be worse than leaving it out. If you need the texture coordinates preserved, this is not the route and gltf-transform is.

Only triangle geometry crosses from glTF into the OBJ

glTF primitives declare a mode. Mode 4 is a triangle list and is the only one read; points, lines, line loops, line strips, triangle strips and triangle fans are skipped. A file containing nothing but line geometry ends with a message that no triangle geometry was found, which is more useful than an empty OBJ.

Draco-compressed geometry stops with a message naming Draco, because the decoder for KHR_draco_mesh_compression is not shipped here. If your glTF came from a size-optimised export pipeline this is the most likely reason it will not convert, and re-exporting without Draco is a single flag in every tool that applies it.

The vertex count in the OBJ against the glTF accessor count

They match exactly, per mesh. Nothing is merged on this path: the POSITION accessor is decoded element by element into v lines in the same order, and the index accessor becomes f entries pointing at them. The merging step that collapses coincident coordinates runs when reading STL and OBJ, where unshared vertices are the norm, and is not applied to a glTF that already has an index buffer.

That makes the count a usable check — if your tool reported 48,213 vertices and the OBJ has 48,213 v lines, nothing was skipped. It also means coincident vertices survive. Exporters split a vertex wherever two faces need different UVs or normals, and those duplicates arrive as separate v lines at identical coordinates, so a closed surface can report boundary edges along its seams. If your analysis depends on adjacency, merge by distance before running it.

Size and precision when glTF floats become OBJ decimals

A float32 coordinate is four bytes in a glTF buffer. The same number written as decimal text is typically eight to eighteen characters plus a separator, so the OBJ is several times larger than the geometry portion of the glTF even after base64 inflation is accounted for. A million-triangle model is a large text file and worth expecting.

Precision is preserved rather than truncated: the values are printed at whatever precision JavaScript needs to round-trip the float, so nothing is silently rounded on the way out. The only rounding in the pipeline is the six-decimal key used for welding, and that decides which vertices are the same vertex, not what their coordinates are.

When to leave the glTF alone

If you are going to render the model, keep the glTF. Everything that makes it worth looking at — the materials, the textures, the animation — is in the parts this conversion discards, and every modern viewer reads it directly.

Convert when the model is data rather than an asset: when you need a triangle count you trust, a bounding box you measured yourself, a diff between two exports of the same part, or an input to code you wrote. That is a narrow reason and a real one, and it is the only one this page is written for.

How to convert GLTF to OBJ

  1. Drop a self-contained .gltf onto this page, or click to choose one.
  2. The accessors are decoded and written out as plain OBJ text in your browser.
  3. Download the .obj and open it in an editor or a script.

glTF beside OBJ: indirection against plain numbers

GLTF compared with OBJ
GLTFOBJ
Full nameGL Transmission FormatWavefront Object
File extension.gltf.obj
Media typemodel/gltf+jsonmodel/obj
First published20151992
Published byKhronos GroupWavefront Technologies
SpecificationglTF 2.0
LicensingOpen standardOpen standard
Standing todayCurrentCurrent
Opens in a browserNo browserNo browser
Considered insteadGLBPLY, STL

Opening the result

Blender reads both GLTF and OBJ, so there is a way to check the result against the original without a second tool.

What each format is for

The two are aimed at different work: GLTF at the web and handing a finished file over, OBJ at moving data between programs and editing. That is worth weighing before converting, because the reason one exists is usually the reason the other is awkward.

GLTF is Khronos Group's format, published in 2015. The specification is glTF 2.0, and it is worth reading if the file has to outlive the tool that wrote it.

OBJ comes from Wavefront Technologies and dates from 1992. Blender, MeshLab and Maya all read it.

OBJ was published in 1992 and GLTF in 2015. The older one is generally the safer file to hand to somebody; the newer one usually does the job in fewer bytes.

glTF to OBJ: questions from people parsing the output

Are my GLTF files uploaded anywhere?

No. This conversion runs entirely inside your browser, so the file never leaves your device. You can confirm it yourself: open the network tab of your browser's developer tools and convert something. You will see the page load, plus the analytics and advertising the site is paid for with — and nothing carrying your file.

How do I count the vertices in the OBJ afterwards?

Count the lines beginning with "v " — one per vertex. Lines beginning with "f " are triangles, one each. Both counts are exact because the writer emits nothing else, with no vt, vn or usemtl lines to filter out.

Are the OBJ face indices zero-based or one-based?

One-based, as the format requires, and numbered across the whole file rather than restarting at each o group. A second object referencing its own first vertex is written with every preceding vertex counted into the index.

Does it write quads or n-gons?

No. Every face line has exactly three indices. Any polygon in the source was already triangulated in the glTF, and the writer never merges triangles back into larger faces.

Are the coordinates local or world coordinates?

World. Each node matrix is composed with its parents and applied to the vertices before they are written, so a part positioned by a transform in the glTF appears at its final position in the OBJ.

My glTF refers to a .bin file and will not convert. Why?

Because a single-file converter cannot follow the reference. Only a glTF whose buffer is embedded as a base64 data URI has its geometry inside the file. Re-export with buffers embedded, or convert the .glb version instead.

More about these formats