The data starts on the byte after the line end of end_header. It holds the
elements in the order the header declares them: every
item of the first element, then every item of the second, and so on. Each item holds its
properties in the order they were declared. The format line chooses how the
values are written.
Order of the data
| Level | Order |
|---|---|
| Elements | As the element lines appear in the header |
| Items of one element | From the first to the last; the count is on the element line, and items are numbered from 0 |
| Properties of one item | As the property lines appear under the element |
| A list property | Its count, then that many items |
Nothing marks where one element ends and the next begins. A reader has to read, or step over, every property of every item, which the header makes possible.
ascii
Values are written as decimal numbers separated by white space. By convention each
item takes one line, so a vertex is one line and a face is one line, but readers
should treat any white space alike. Numbers use the C locale: a full stop as the
decimal point and no thousands separators. Floating-point values may use an exponent,
as in 1.5e-3.
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
binary_little_endian and binary_big_endian
Each value is stored in the size of its type,
packed one after another with no separators, no padding and no alignment. Integers
are two’s complement and floating-point values are IEEE 754. The two binary encodings
differ only in byte order: binary_little_endian stores the least
significant byte first, as x86 and ARM processors do, and
binary_big_endian the most significant byte first.
A list stores its count in the count type, then its items in the item type, so the size of an item of an element with a list property varies from one item to the next.
Worked example
The same triangle as above in binary_little_endian. Its header is 169
bytes long, ending with the line feed after end_header, so the data
starts at offset 169 (A9) and the file is 218 bytes.
ply
format binary_little_endian 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
| Offset | Size | Type | Bytes | Meaning |
|---|---|---|---|---|
| 169 | 4 | float | 00 00 00 00 | Vertex 0, x = 0.0 |
| 173 | 4 | float | 00 00 00 00 | Vertex 0, y = 0.0 |
| 177 | 4 | float | 00 00 00 00 | Vertex 0, z = 0.0 |
| 181 | 4 | float | 00 00 80 3F | Vertex 1, x = 1.0 |
| 185 | 4 | float | 00 00 00 00 | Vertex 1, y = 0.0 |
| 189 | 4 | float | 00 00 00 00 | Vertex 1, z = 0.0 |
| 193 | 4 | float | 00 00 00 00 | Vertex 2, x = 0.0 |
| 197 | 4 | float | 00 00 80 3F | Vertex 2, y = 1.0 |
| 201 | 4 | float | 00 00 00 00 | Vertex 2, z = 0.0 |
| 205 | 1 | uchar | 03 | Face 0, list count: 3 vertices |
| 206 | 4 | int | 00 00 00 00 | Face 0, vertex 0 |
| 210 | 4 | int | 01 00 00 00 | Face 0, vertex 1 |
| 214 | 4 | int | 02 00 00 00 | Face 0, vertex 2 |
In binary_big_endian the bytes of each value are reversed: 1.0 becomes
3F 80 00 00 and vertex number 1 becomes 00 00 00 01. The
header is three bytes shorter, 166 bytes, since big has three letters
fewer than little.