# Beware of the STL file format

**URL:** <https://discourse.slicer.org/t/beware-of-the-stl-file-format/7642>\
**Category:** Support\
**Created:** [July 17, 2019, 7:25pm UTC](https://discourse.slicer.org/t/beware-of-the-stl-file-format/7642 "2019-07-17T19:25:20Z")\
**Posts on this page:** 17\
**Page:** 1

<div class="post-metadata">

**Author:** ![Chris\_Rorden](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/chris_rorden/32/4073_2.png) [@Chris\_Rorden](https://discourse.slicer.org/u/Chris_Rorden)\
**Post date:** [July 17, 2019, 7:25pm UTC](https://discourse.slicer.org/t/beware-of-the-stl-file-format/7642/1 "2019-07-17T19:25:20Z")

</div>

Many topics on this forum mention the STL format. While it is great that Slicer supports so many formats, I would advocate that Slicer discourage users from exporting to STL (e.g. from the “Save Scene and Unsaved Data” dialog change the file format pull-down to list “STL (.stl) deprecated” versus the current “STL (.stl)”. The only reason to export to STL is if it is the only format supported by the software or 3D printer you are using. Fortunately, modern 3D printing companies like Shapeways now support better formats such as OBJ.

The fundamental issue with STL is that it does not reuse vertices. This means that the resulting meshes will either look faceted (e.g. Slicer) or will be extremely slow to load (if the software attempts to unify vertices, e.g. Surfice). In addition, this feature makes this format exceptionally inefficient yielding large file sizes (about 3 times the file size of a simple uncompressed binary format). Not only are the faceted images ugly, they are slower and more resource intensive to render with [modern methods](http://hacksoflife.blogspot.com/2010/01/to-strip-or-not-to-strip.html).

The issue is illustrated in the image below. This is a mesh created with Slicer’s Editor function and then the same mesh is saved as both STL and OBJ format. The two meshes are then reloaded in Slicer. Note that the OBJ file has nice per-pixel shading, while the STL file has jagged per-triangle shading.

Given that the format is so popular with Slicer users, the other option is to support vertex-unification when STL files are loaded. This will make the loaded STL images look nicer (though loading times will increase).

 ![stl_vs_obj](https://us1.discourse-cdn.com/flex002/uploads/slicer/original/3X/9/c/9c31b53fccf19e399f051a7b3980c318719f2b7d.jpeg)

---

<div class="post-metadata">

**Author:** ![pieper](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/pieper/32/8_2.png) [@pieper](https://discourse.slicer.org/u/pieper)\
**Post date:** [July 17, 2019, 11:11pm UTC](https://discourse.slicer.org/t/beware-of-the-stl-file-format/7642/2 "2019-07-17T23:11:43Z")

</div>

Hi @Chris_Rorden - I totally agree that STL is a _terrible_ format for storing geometry and should be avoided whenever possible. As you point out, many 3D printer companies don’t seem to realize this and use it for some kind of legacy reasons (even though it must make their lives harder too). Unfortunately the user community seems to have gotten into the habit of saying STL whenever they mean polygon surface mesh and so the cycle continues.

Regarding your specific proposal, maybe instead of adding the word ‘deprecated’ how about adding ‘discouraged’ or some other term. I think we should reserve ‘deprecated’ for things we’ll be removing in an upcoming release, but, alas, I don’t think we will ever be able to remove STL.

---

<div class="post-metadata">

**Author:** ![lassoan](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/lassoan/32/13_2.png) [@lassoan](https://discourse.slicer.org/u/lassoan)\
**Post date:** [July 18, 2019, 12:08am UTC](https://discourse.slicer.org/t/beware-of-the-stl-file-format/7642/3 "2019-07-18T00:08:55Z")

</div>

Very interesting discussion. I don’t like STL file format either and very surprised that is is still so widely used. However, I find most consumer/gaming mesh formats about equally bad for medical image computing. Yes, STL is the most basic format, and yes, OBJ is better in a couple of things (it supports polygon cells, surface normals, textures), but it has some disadvantages, too, even compared to STL.

Some of the problems with OBJ:

- it is not possible to specify unit (mm/inches/m) or coordinate system (LPS/RAS/…) in a standard way (same as STL)
- no way to store arbitrary metadata (same as STL)
- it is ASCII only, so files are larger and/or lose precision and much slower to parse than binary STL (worse than STL)
- we cannot claim to be fully compatible with OBJ, as it has some features that would be very difficult to fully support, such as NURBS curves and surfaces, or multi-texture (worse than STL)

> [@Chris\_Rorden](#):
>
> resulting meshes will either look faceted (e.g. Slicer) or will be extremely slow to load

VTK clean polydata filter can merge coincident points and compute surface normals in negligible time, so computation time should not be an issue.

We’ve been planning to add an optional normal computation step into the model display pipeline. This could be enabled by default for STL files or for any other surface mesh files that did not happen to have the normals available.

> [@Chris\_Rorden](#):
>
> In addition, this feature makes this format exceptionally inefficient yielding large file sizes

Standard OBJ format is text only, so file sizes are larger than binary STL.

> [@Chris\_Rorden](#):
>
> change the file format pull-down to list “STL (.stl) deprecated”

Adding “deprecated” there sounds too harsh to me (and as @pieper pointed out not even accurate). But even if we could find a better word: I would not single out STL as the bad guy. Is PLY any better? Would you _always_ recommend OBJ over STL? We should probably just try to educate users on the forum, documentation, etc. where there is a room for explaining our rationale for preferring one file format over another.

---

<div class="post-metadata">

**Author:** ![Lorensen](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/lorensen/32/31_2.png) [@Lorensen](https://discourse.slicer.org/u/Lorensen)\
**Post date:** [July 18, 2019, 3:43am UTC](https://discourse.slicer.org/t/beware-of-the-stl-file-format/7642/4 "2019-07-18T03:43:39Z")

</div>

In the near future, I’ll modify the vtk obj so that there is no loss in precision. I used the class vtkNumberToString in the vtkXMLWriter.

---

<div class="post-metadata">

**Author:** ![lassoan](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/lassoan/32/13_2.png) [@lassoan](https://discourse.slicer.org/u/lassoan)\
**Post date:** [July 18, 2019, 4:34am UTC](https://discourse.slicer.org/t/beware-of-the-stl-file-format/7642/5 "2019-07-18T04:34:10Z")

</div>

> [@Lorensen](#):
>
> I’ll modify the vtk obj so that there is no loss in precision

This will be great, thank you, one issue will be taken care of then!

(Still, writing/reading numbers as text will be much slower and file size will be larger compared to using a binary file format, and other OBJ file issues still remain.)

---

<div class="post-metadata">

**Author:** ![Lorensen](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/lorensen/32/31_2.png) [@Lorensen](https://discourse.slicer.org/u/Lorensen)\
**Post date:** [July 18, 2019, 6:05am UTC](https://discourse.slicer.org/t/beware-of-the-stl-file-format/7642/6 "2019-07-18T06:05:37Z")

</div>

I just submitted an [MR](https://gitlab.kitware.com/vtk/vtk/merge_requests?assignee_id=&author_id=&label_name=&milestone_id=&scope=all&sort=updated_desc&state=opened) to improve the saved floating point values.

---

<div class="post-metadata">

**Author:** ![Chris\_Rorden](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/chris_rorden/32/4073_2.png) [@Chris\_Rorden](https://discourse.slicer.org/u/Chris_Rorden)\
**Post date:** [July 18, 2019, 5:35pm UTC](https://discourse.slicer.org/t/beware-of-the-stl-file-format/7642/7 "2019-07-18T17:35:06Z")

</div>

PLY format reuses vertices, so it does not suffer the issues of STL. I for one **do** single out STL as the worst popular mesh format as it is the only one that does not reuse vertices.

As @lassoan notes, a major disadvantage of OBJ is that it is only ASCII. Both PLY and STL have ASCII and binary variants. With ASCII you need to trade off file size and precision, and file loading is always extremely slow. In my software OBJ (with moderate precision) is about [13 times slower and 7 times larger](https://www.nitrc.org/plugins/mwiki/index.php/surfice:MainPage#Supported_Formats) than a simple gzipped binary format (MZ3).

The [MZ3](https://github.com/neurolabusc/surf-ice/tree/master/mz3) format can be extended, is very fast and relatively compact. I might be biased here as I developed it, but I would be happy to extend this. The current version was extended to support features for PALM (Anderson Winkler) and SPM (Guillaume Flandin) and I provide Matlab, [JavasScript](https://neurolabusc.github.io/) and Python/Blender code. The strength of this format is that is virtually identical to the raw data one sends to the GPU, which makes it fast. However, just like modern GPUs it only represents triangles. The advantage of triangles is that as long as three points are not co-linear they define a single plane, while this is not true of all quads (e.g. all 3-legged stools are stable, but many 4 legged chairs rock between legs). While modern GPUs do not use quads as a base type, quads can be useful for a file format to store if one is interested in subdivision.

The [GIfTI format](https://www.nitrc.org/projects/gifti/) does allow meta data. It is XML-based and so it is human readable. It uses base-64 storage for binary data which adds a bit of a speed and file size hit, but this is pretty modest. It seems like a reasonable interchange format for brain imaging.

The Draco format is very clever, creating extremely compact files. However, it is very complicated and the fact that it re-indexes vertices would probably be a problem for a lot of brain imaging applications.

---

<div class="post-metadata">

**Author:** ![pieper](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/pieper/32/8_2.png) [@pieper](https://discourse.slicer.org/u/pieper)\
**Post date:** [July 19, 2019, 12:15am UTC](https://discourse.slicer.org/t/beware-of-the-stl-file-format/7642/8 "2019-07-19T00:15:24Z")

</div>

And of course let’s not forget [glTF](https://www.khronos.org/gltf/), which [is already being integrated with Slicer](https://discourse.slicer.org/t/transferring-models-using-gltf-2-0/7064). It’s more graphics-oriented than medical, but the features and community support, not to mention compactness and extensibility are impressive. No reason we couldn’t propose an extension to embed some things like coordinate system reference (probably LPS by default) and other useful things like anatomy codes.

---

<div class="post-metadata">

**Author:** ![lassoan](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/lassoan/32/13_2.png) [@lassoan](https://discourse.slicer.org/u/lassoan)\
**Post date:** [July 19, 2019, 2:34am UTC](https://discourse.slicer.org/t/beware-of-the-stl-file-format/7642/10 "2019-07-19T02:34:07Z")

</div>

> [@Chris\_Rorden](#):
>
> I for one **do** single out STL as the worst popular mesh format as it is the only one that does not reuse vertices.

I’m just curious, why it is a problem that vertices are not reused? I’ve just tried and VTK loads a mesh that contains 1.5 million points in 2 seconds from .vtk file, and in about 3 seconds from .stl file (including coincident point merging). So, performance should not be a huge issue.

> [@pieper](#):
>
> No reason we couldn’t propose an extension to embed some things like coordinate system reference (probably LPS by default) and other useful things like anatomy codes.

I agree, I always feel that there are already too many file formats and we should rather spend our time with improving existing ones.

---

<div class="post-metadata">

**Author:** ![Chris\_Rorden](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/chris_rorden/32/4073_2.png) [@Chris\_Rorden](https://discourse.slicer.org/u/Chris_Rorden)\
**Post date:** [July 19, 2019, 8:10pm UTC](https://discourse.slicer.org/t/beware-of-the-stl-file-format/7642/11 "2019-07-19T20:10:36Z")

</div>

@lassoan - the 2 second load for a vtk file reflects a poorly optimized VTK loader. Slicer saves [VTK files](https://vtk.org/wp-content/uploads/2015/04/file-formats.pdf) as triangles in binary VTK format, e.g. the header will report “POLYGONS n sz” where sz = n \* 4. This represents a special case: when sz = n \* 4 you can read the entire array from disk and ignore the numPointsN as it will always be 3 (if sz \> n \* 4 you must read the numPointsN for each NGon and reconstruct it).

```
POLYGONS n size
numPoints0, i0, j0, k0, ...
numPoints1, i1, j1, k1, ...
...
numPointsn-1, in-1, jn-1, kn-1, ...

```

Here are times for reading meshes with my software (vtk, obj and stl created with Slicer):  
mz3 (raw) 14ms  
mz3 (gzip) 134ms  
vtk (ignore numPoints) 67ms  
obj (ascii) 2710ms  
vtk (naive) 2857ms  
stl (binary, unify) 4717ms

I think it would be terrific if Slicer would automatically unify STL vertices. However, I would still discourage users from saving in STL unless absolutely required, as many tools do not apply this step and therefore the resulting meshes look poor.

---

<div class="post-metadata">

**Author:** ![lassoan](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/lassoan/32/13_2.png) [@lassoan](https://discourse.slicer.org/u/lassoan)\
**Post date:** [July 19, 2019, 9:05pm UTC](https://discourse.slicer.org/t/beware-of-the-stl-file-format/7642/12 "2019-07-19T21:05:30Z")

</div>

VTK’s STL reader merges coincident points by default. Slicer uses this default setting.

---

<div class="post-metadata">

**Author:** ![Chris\_Rorden](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/chris_rorden/32/4073_2.png) [@Chris\_Rorden](https://discourse.slicer.org/u/Chris_Rorden)\
**Post date:** [July 19, 2019, 9:26pm UTC](https://discourse.slicer.org/t/beware-of-the-stl-file-format/7642/13 "2019-07-19T21:26:44Z")

</div>

Is this a new feature? The STL and OBJ images from the initial comment were both generated by Slicer and loaded by Slicer (version 4.10.2 on MacOS). The STL and OBJ files look identical to each other when I load them with Surfice (which unifies vertices, e.g. the STL looks faceted in Slicer but not Surfice).

---

<div class="post-metadata">

**Author:** ![Chris\_Rorden](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/chris_rorden/32/4073_2.png) [@Chris\_Rorden](https://discourse.slicer.org/u/Chris_Rorden)\
**Post date:** [July 19, 2019, 10:18pm UTC](https://discourse.slicer.org/t/beware-of-the-stl-file-format/7642/14 "2019-07-19T22:18:32Z")

</div>

One other thought, is it possible that Slicer/VTK estimate the vertex normals before unifying the vertices? This would explain the faceted look. It is important to calculate surface normals after unifying the vertices.

---

<div class="post-metadata">

**Author:** ![lassoan](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/lassoan/32/13_2.png) [@lassoan](https://discourse.slicer.org/u/lassoan)\
**Post date:** [July 19, 2019, 10:44pm UTC](https://discourse.slicer.org/t/beware-of-the-stl-file-format/7642/15 "2019-07-19T22:44:38Z")

</div>

The faceted look of models loaded from STL files is due to that we do not compute the normals automatically. If normals are not stored in the file then model surface will be displayed with flat shading. I noticed this year’s ago but did not want to simply add a few lines to compute normals with some default settings if they are not available in the input file because of potential rendering artifacts (especially when cells are large and highly angled), the extra computation time, and maybe a module that loads the data may want to compute normals in a specific way (splitting at feature edges, etc). Comouting missing surface normals in the display pipeline would not have any of these limitations, but we have not get around to implement it.

Users can always compute surface normals using Surface toolbox module if they need it.

---

<div class="post-metadata">

**Author:** ![Chris\_Rorden](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/chris_rorden/32/4073_2.png) [@Chris\_Rorden](https://discourse.slicer.org/u/Chris_Rorden)\
**Post date:** [July 19, 2019, 11:17pm UTC](https://discourse.slicer.org/t/beware-of-the-stl-file-format/7642/16 "2019-07-19T23:17:55Z")

</div>

That is understandable. Sounds like a good reason to discourage users from choosing the STL format if they want to render the data in Slicer. As shown above, the per-vertex surface normals of the OBJ files that are created are more accurate than the per-face normals required by the STL format. I appreciate that the vertex unification of slicer will remove my concerns regarding the usage of GPU resources and performance.

---

<div class="post-metadata">

**Author:** ![Juicy](https://avatars.discourse-cdn.com/v4/letter/j/74df32/32.png) [@Juicy](https://discourse.slicer.org/u/Juicy)\
**Post date:** [July 20, 2019, 2:05am UTC](https://discourse.slicer.org/t/beware-of-the-stl-file-format/7642/17 "2019-07-20T02:05:33Z")

</div>

I use the STL file a lot for downstream CAD modelling as well as 3d printing. It is a very well recognised file format across many programs.

I appreciate the education regarding the inefficiencies associated with the format as I was not really aware (I do notice the huge file sizes though)

Although I do think this info would be best shared on forums and documentation as mentioned previously. I think it would look very unprofessional to have little comments next to the file formats in the drop down menu. I have never seen other software with this.

I know when I select STL it is because there is no other option for getting slicer models into other CAD software and 3d printers.

---

<div class="post-metadata">

**Author:** ![fangq](https://avatars.discourse-cdn.com/v4/letter/f/ec9cab/32.png) [@fangq](https://discourse.slicer.org/u/fangq)\
**Post date:** [September 2, 2019, 1:56am UTC](https://discourse.slicer.org/t/beware-of-the-stl-file-format/7642/18 "2019-09-02T01:56:46Z")

</div>

in case someone is still interested in considering a new mesh format, I have been working on (text/binary) JSON based mesh data format - JMesh - as part of the work related to my 3D mesh generator Iso2Mesh ([http://iso2mesh.sf.net](http://iso2mesh.sf.net)). This summer, I wrote a few JSON/JData based file specifications, including an early draft for JMesh.

> **[fangq/jmesh](https://github.com/fangq/jmesh)**
>
> JMesh - A portable and versatile JSON data format for storage of unstructured mesh and shape data - fangq/jmesh

More related discussion can be found in my mailing list post in the below link

[https://groups.google.com/forum/#!topic/iso2mesh-users/EIG4V7Gzpl0](https://groups.google.com/forum/#!topic/iso2mesh-users/EIG4V7Gzpl0)

Essentially, a text-based JMesh file is basically a plain JSON file that can be parsed by nearly all JSON parsers; to save space, it can be converted to a binary-version (and convert back) using the UBJSON specification ([http://ubjson.org](http://ubjson.org)). Both formats support strongly-typed data and internal compression.

Currently, working parsers/writers for MATLAB already exist, and the support for other languages (without advanced JData features) can be readily added by linking with any JSON/UBJSON parsers available.

Happy to chat more if anyone is interested in this format. Any suggestion is welcome.
