UINT8 – Header UINT32 – Number of triangles foreach triangle REAL32 – Normal vector REAL32 – Vertex 1 REAL32 – Vertex 2 REAL32 – Vertex 3 UINT16 – Attribute byte count end
Be extra careful to write the floating point numbers as little-endian, as the wikipedia article warns:
- A container to put the raw data in: an ArrayBuffer
- A helper to write heterogeneous binary datatypes: a DataView
Since this is binary data, we need to know how many bytes the file will be before we are able to start writing it. Its pretty straightforward to compute from the layout above:
// sizeInBytes = // 80 * sizeof(UINT8) // + 1 * sizeof(UINT32) // + (12 * sizeof(REAL32) + 1 * sizeof(UINT16)) * N triangles var buffer = new ArrayBuffer(84 + (50 * nTriangles));
That takes care of the ArrayBuffer container for the data, but how do we write data to it?
Because we are dealing with many different binary types (uint8, uint32, float32, etc.), we need an abstraction that allows us to write these types into the raw data buffer. That is what a DataView does. After creating a DataView using the raw ArrayBuffer it will write data into, you can easily write individual bytes of data in their corresponding types. You only have to keep track of the byte offset:
var dataview = new DataView(buffer); var offset = 0; // To skip data, no need to write zeros, just increase the offset offset += 80 // For the STL header // To write a vector like the face normal, or a vertex // need to pass in isLittleEndian=true / false as last param dataview.setFloat32(offset, v.x, isLittleEndian); offset += 4; // 4 = number of bytes in a float 32 dataview.setFloat32(offset, v.y, isLittleEndian); offset += 4; dataview.setFloat32(offset, v.z, isLittleEndian); offset += 4;
Putting those together, here is the full binary stl writer.