PLY to OBJ Converter

Paste a Stanford PLY mesh or point cloud — ASCII as text, binary as base64 or hex — and get a Wavefront OBJ file back. Vertex colors, normals and texture coordinates come across, and you can scale, reorient axes or triangulate n-gons, all locally in your browser.

Try:
Wavefront OBJ

About this tool

PLY (the Stanford Polygon Library format) is what most 3D scanners, photogrammetry pipelines and point-cloud tools export. Wavefront OBJ is what most modelling packages, game engines and slicers import. This converter turns one into the other in your browser — the file never leaves your machine, and there is no upload, sign-up or queue.

It reads all three PLY encodings the spec defines: ascii, binary_little_endian and binary_big_endian. An ASCII PLY is plain text, so paste it straight in. A binary PLY is not text — paste its bytes as base64 or hex instead (a data:…;base64,… URL works too) and leave the encoding on Auto-detect.

Both meshes and point clouds are supported. A PLY with no face element is a point cloud, and the OBJ comes back as v lines only — which is exactly what CloudCompare, MeshLab and Blender expect from a point-cloud OBJ.

Worked example

Input — an ASCII PLY triangle with per-vertex colors:

ply
format ascii 1.0
element vertex 3
property float x
property float y
property float z
property uchar red
property uchar green
property uchar blue
element face 1
property list uchar int vertex_indices
end_header
0 0 0 255 0 0
1 0 0 0 255 0
0 1 0 0 0 255
3 0 1 2

Output — Wavefront OBJ, with the colors carried across:

# OBJ generated by gizza ply-to-obj
# source: PLY (ascii), 3 vertices, 1 faces
# vertex colors are the r g b values after each v (0..1)
o mesh
v 0 0 0 1 0 0
v 1 0 0 0 1 0
v 0 1 0 0 0 1
f 1 2 3

PLY indices count from 0 and OBJ indices count from 1, so face 3 0 1 2 becomes f 1 2 3. The uchar color channels (0–255) are divided by 255 to the 0–1 range OBJ readers expect.

What comes across

PLY propertyWritten asNotes
x y zv x y zAlways.
red green bluev x y z r g bThe vertex-color extension MeshLab, CloudCompare and Blender read. uchar 0–255 is scaled to 0–1; float channels are used as-is.
nx ny nzvn + f v//vn
s/t, u/v, texture_u/texture_vvt + f v/vtAll three spellings are recognised.
vertex_indices / vertex_indexf …Both spellings are recognised.
alphaDropped: OBJ has no per-vertex alpha channel.
edges, materials, custom scanner propertiesSkipped, but still consumed so the rest of the file stays in sync.

Switch Output to Source-file summary to see what a file actually contains — its encoding, whether it is a mesh or a point cloud, vertex/face/polygon counts, which of colors/normals/UVs were declared and written, every header element, and which vertex properties were ignored — without converting it.

Limits and edge cases

FAQ

My PLY is binary — why can't I just paste it?

Binary PLY is raw bytes, not text: pasting it through a browser text field would mangle every byte that is not valid UTF-8. Paste the bytes as base64 or hex instead and the converter decodes them for you. On macOS or Linux, base64 -w0 model.ply gives you something you can paste directly; a data:…;base64,… URL is accepted too. Leave the encoding on Auto-detect — hex and base64 are both recognised, and the decoded bytes are checked for the ply magic word before parsing.

Will my vertex colors survive the conversion?

Yes, if the PLY declares red/green/blue properties. They are written using the v x y z r g b extension, where the three extra numbers on each v line are the colour in the 0–1 range. MeshLab, CloudCompare and Blender all read this form. It is an extension rather than base OBJ, so a stricter reader may ignore the extra values — untick Keep vertex colors to emit plain v x y z lines if that causes trouble. Per-vertex alpha is always dropped, because OBJ has no alpha channel.

Can it convert a point cloud, or does it need faces?

Point clouds work. A PLY with no face element — which is what most scanners and photogrammetry tools export before meshing — converts to an OBJ containing only v lines (plus v x y z r g b if it carries colours). No faces are invented. The Source-file summary output will tell you explicitly whether a file was read as a mesh or a point cloud.

Why does my OBJ have no .mtl material file?

Because PLY has no materials to convert. The format stores per-vertex data — positions, colours, normals, texture coordinates — but no material definitions, no texture image references and no shading parameters, so there is nothing a .mtl file could be generated from. If your model was textured, the texture image and its material live outside the PLY; re-attach them in your 3D application after importing the OBJ. Texture coordinates (s/t, u/v or texture_u/texture_v) do come across as vt lines.

My model is on its side after importing — what do I fix?

That is a coordinate-frame mismatch, not a conversion bug. Graphics tools (Blender's glTF path, Unity, three.js) treat +Y as up, while 3D-printing and CAD tools (slicers, Fusion, Blender's own scene) treat +Z as up. Set Axis conversion to Y-up → Z-up or Z-up → Y-up to rotate the model 90° about the X axis on the way out. Vertex normals rotate with the positions, so lighting stays correct.

What does the scale factor do, and when do I need it?

It multiplies every vertex position uniformly. PLY files carry no units, so a scanner exporting millimetres and a slicer expecting metres will disagree by 1000× with no way to detect it. Use 0.001 for millimetres → metres, 1000 for metres → millimetres, 25.4 for inches → millimetres, or 0.0393701 for the reverse. Leave it at 1 to change nothing. Normals are direction vectors and are deliberately left unscaled.

Does it handle files with edges or unusual scanner properties?

Yes. Unknown elements (edge, material, anything a particular scanner adds) and unmapped per-vertex properties such as quality, confidence or intensity are skipped — but they are still consumed from the file, so the values that follow them are read at the right offsets. This matters especially for binary PLY, where silently skipping an unknown property would desynchronise the byte stream and turn the rest of the file into garbage. Run the Source-file summary output to see exactly which properties were ignored.

Developer & Automation Access

Run it from the terminal

Same engine as this page, headless — via the gizza CLI:

gizza tool ply-to-obj "ply
format ascii 1.0
element vertex 3
property float x
property float y
property float z
element face 1
property list uchar int vertex_indices
end_header
0 0 0
1 0 0
0 1 0
3 0 1 2"

New to the CLI? Get gizza →

Open it by URL

Pre-fill and auto-run this tool with query parameters — the names match the API/CLI:

https://gizza.ai/tools/ply-to-obj/?ply=ply%0Aformat%20ascii%201.0%0Aelement%20vertex%203%0Aproperty%20float%20x%0Aproperty%20float%20y%0Aproperty%20float%20z%0Aelement%20face%201%0Aproperty%20list%20uchar%20int%20vertex_indices%0Aend_header%0A0%200%200%0A1%200%200%0A0%201%200%0A3%200%201%202&input_format=auto&colors=true&normals=true&uvs=true&triangulate=true&scale=1&axis=keep&name=mesh&output=obj

Machine-readable descriptor: tool.json — title + parameters JSON Schema for agents.