Cookies for analytics and advertising
We use cookies for analytics and advertising, both sent to Google. Refusing changes nothing you can see.Read the privacy page
Converting GLB to PLY gives mesh-processing tools the format they read first: a plain vertex list and a face list, with the glTF scene graph already resolved into world coordinates. The two things to plan around are that all the meshes are merged into one surface and that the PLY is written as text rather than binary.
Up to 100 files at once. Mixed formats are fine.
They convert one after another and download together as a ZIP.
GLB to PLY
The reason this pair exists is a mismatch between distribution and processing. GLB won as the way to hand somebody a model: one file, no sidecars, materials packed in, viewable in a browser with a single element. PLY won inside the geometry-processing world decades earlier, and trimesh, Open3D, MeshLab, CloudCompare and PyTorch3D all treat it as the format that needs no explanation.
So a collection arrives as GLB and the first thing anybody does with it is convert. What matters at that point is not fidelity to the source — nobody is going to render these — but knowing exactly what the loader will see: how many vertices, whether the surface is one piece, and whether the file is going to be five megabytes or fifty.
PLY has one `element vertex` block and one `element face` block. It has no notion of an object, a group or a name, so a GLB containing a body, a lid and a handle is merged: the vertex lists are concatenated and the face indices of each mesh are offset by the number of vertices already written.
The geometry is identical and the structure is gone. Connected-component analysis will still find the three pieces — `trimesh.Mesh.split()` and MeshLab’s Split in Connected Components both work on the result — but the names do not come back, and two parts that touched are now adjacent regions of one surface rather than two objects. If part identity matters to what you are doing, OBJ is the format here that keeps it.
The header always reads `format ascii 1.0`. There is no binary option and no setting to change it, so every coordinate is written as decimal digits and every face as a line beginning with the number 3. PLY is defined as either text or binary and this converter only writes the first, which is worth knowing because format summaries — this site’s included — describe PLY as a binary format.
Practically that means the file is several times the size of the binary equivalent: a float32 coordinate occupies four bytes packed and around ten to fifteen characters written out. Everything reads it, `head -20` shows you the header, and a diff between two exports is meaningful. If you need the binary form, MeshLab and trimesh both write it, and a single re-save converts.
Some sources on this site are welded on the way in — an STL stores three independent vertices per triangle and would otherwise produce a file four times larger than necessary. A GLB does not: its geometry is already an indexed vertex buffer, so the positions and the index array are carried across as they are.
That means the vertex count in the PLY matches the accessor counts in the source, which is exactly what you want when the conversion is a step in a measurement rather than a delivery. It also means duplicates the source contained are still there — a UV seam splits a vertex into two coincident copies in every glTF exporter, and those copies arrive in the PLY. If a downstream algorithm needs a watertight index, merge with a tolerance in the library rather than expecting the converter to have done it.
Nine lines and no more: the magic word, the format, a generator comment, the vertex element with its count and three float properties, the face element with its count and a `property list uchar int vertex_indices`, and `end_header`. Reading the two counts off the top of the file is the fastest triangle-and-vertex census available, and it needs no library at all.
What the header does not declare is anything else. No colour properties, no normals, no texture coordinates, no comments carrying units or provenance, no user-defined elements. A loader reading this file learns the geometry and nothing about where it came from, which is fine for a processing step and poor for an archive — so keep the GLB.
PLY is the format people reach for precisely because it holds per-vertex colour, which is why scanners write it. A GLB frequently has colour to give: a `COLOR_0` vertex attribute, or more often a base colour texture with UV coordinates. None of it is read, and the writer emits only x, y and z.
So the result is geometry with no appearance, and if the appearance is what you were going to analyse — comparing scans, checking a capture, evaluating a texture bake — this is the wrong route and the answer is a library that reads both attributes. `trimesh.load('model.glb')` gives you the visual as well as the mesh and exports a coloured PLY directly. For pure geometry work, none of this matters and the plain file is smaller.
The converter walks the scene graph from the default scene, composes each node matrix with its parent, and applies the result before writing. A GLB that placed one mesh in four positions therefore produces four sets of vertices in four places rather than one mesh and four matrices.
That is the right behaviour, because PLY has no way to express an instance, and it is also worth remembering when the numbers look wrong. A bounding box computed on the PLY covers the whole assembled scene, not the source mesh, and a model whose author left the scene root translated arrives nowhere near the origin. Both are properties of the GLB rather than of the conversion, and both are one `mesh.apply_translation(-mesh.centroid)` away from being fixed.
Neither GLB nor PLY carries a unit. glTF is authored by convention as though one unit is one metre; PLY makes no claim at all, and the scanning tools that write it usually work in millimetres. Nothing in the conversion reconciles those, and nothing could.
For a measurement pipeline that is a real hazard rather than a footnote, because a volume computed on unlabelled coordinates is a number with no unit attached. Establish the factor once, from a dimension you can verify in the source, and record it beside the dataset. If the collection came from a single generator the factor is usually constant across it, which makes this a five-minute job done once rather than a per-file question.
A folder converts here in one pass and comes back as a ZIP, which is a reasonable way to handle tens of files and a poor way to handle thousands. The free ceiling is 100 MB per file and the work happens in a browser tab, so a large collection is slow and, more importantly, unrepeatable — nothing about it is captured in a script.
For anything you will run twice, `trimesh.load(path, force='mesh').export(out)` is two lines and reads GLB natively, keeps vertex colours if you ask for them, and writes binary PLY. Use this page for what it is good at: converting three files by hand to see what the geometry actually looks like before committing to how the other three thousand will be processed.
In this browser tab. The conversion is plain JavaScript with no WebAssembly module to download, nothing is uploaded, there is no account and no daily allowance, and the network tab during a conversion shows nothing leaving.
That is worth checking rather than believing, and it matters for two overlapping reasons here: research datasets frequently come with redistribution terms, and a scanned or captured model of a real object can be a disclosure in itself. Neither question arises when the file never moves.
| GLB | PLY | |
|---|---|---|
| Full name | Binary glTF | Polygon File Format |
| File extension | .glb | .ply |
| Media type | model/gltf-binary | model/ply |
| First published | 2016 | 1994 |
| Published by | Khronos Group | Stanford University |
| Specification | glTF 2.0 | — |
| Licensing | Open standard | Open standard |
| Standing today | Current | Current |
| Opens in a browser | No browser | No browser |
| Considered instead | GLTF, OBJ | OBJ, STL |
Blender reads both GLB and PLY, so there is a way to check the result against the original without a second tool.
The two are aimed at different work: GLB at the web and handing a finished file over, PLY at scanning and moving data between programs. That is worth weighing before converting, because the reason one exists is usually the reason the other is awkward.
GLB is Khronos Group's format, published in 2016. The specification is glTF 2.0, and it is worth reading if the file has to outlive the tool that wrote it.
PLY comes from Stanford University and dates from 1994. MeshLab, Blender and CloudCompare all read it.
PLY was published in 1994 and GLB in 2016. The older one is generally the safer file to hand to somebody; the newer one usually does the job in fewer bytes.
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.
ASCII, always. The header is written as format ascii 1.0 with no option to change it, so every coordinate is decimal text. That is readable and it makes the file several times larger than the binary form of the same mesh.
One. PLY holds a single vertex list and a single face list, so every mesh in the GLB is merged into one surface with the indices renumbered. Part boundaries and mesh names do not survive.
No. A GLB arrives already indexed, so nothing is welded on this path — the vertices come across exactly as the file stored them, including any duplicated along a seam between two meshes.
They are not carried. PLY is the obvious place for per-vertex colour and the writer emits only x, y and z properties, so a GLB with a COLOR_0 attribute or a base colour texture produces a plain geometric PLY.
A folder converts in one pass and comes back as a ZIP, which is fine for tens of files. For thousands, do it in Python — trimesh reads GLB directly and writes PLY in two lines — because a browser page is the wrong shape for a pipeline you will run again.
Because it declares KHR_draco_mesh_compression and that decoder is not shipped here. Web-distributed models are compressed that way very often. Re-export without Draco or decode with gltf-transform first.