Jump to content

STL file format


Recommended Posts

Hey team, for the very first time I have a question :)


I'm looking for someone motivated to do an small piece of JS code to do a loader for STL file.


The idea will be to have it part of the repo but not merged with it so people will be able to use it only if they need it



Please reply here if you are interested


Link to comment
Share on other sites

Hey DK,


I'm not a candidate for this task, but I was wondering if you're asking for a loader for STL ascii, STL binary, or both?  It might be good to provide such additional info to whomever is able to take on this task.  I assume it's only for STL ascii files.  Also, are you seeking to support loading only the mesh, or also loading attributes such as color?



Link to comment
Share on other sites

Mind you I never even heard of an STL, before.  I just hit the raw button.  This came from Blender. 


The word "loader" is troublesome it is just a text file.  Looks like the format is:

solid Exported from Blender-2.74 (sub 0)facet normal -0.878070 0.128710 0.460898outer loopvertex -8.395496 -20.847273 86.863701vertex -8.345828 -20.835844 86.955132vertex -8.365781 -20.765602 86.897507endloopendfacet...facet normal 0.156189 -0.965122 -0.210105outer loopvertex 3.992925 -21.059233 82.928780vertex 2.446122 -21.603874 84.280746vertex 1.534460 -21.716881 84.122154endloopendfacetendsolid Exported from Blender-2.74 (sub 0)

Do not know what an "outer loop" is for (parenting?).  Is there some rules for this?  If there can be only 1 solid-endsolid per file, then surely it is just a mesh, not an entire .babylon.  Also what are you language requirements:  C, C++, C#, Java, Typescript, javascript?

Link to comment
Share on other sites

Ok, I usually answer some of my own questions.  You want this written in Typescript.  You want it to be part of a running scene.  The code should interogate the VertexData associated with a given mesh.


It is going have to turn the data into a Blob, then "write it out", by saving it to the downloads directory like:

var objectUrl = (window.webkitURL || window.URL).createObjectURL(blob);            var link = window.document.createElement('a');link.href = objectUrl;link.download = filename;var click = document.createEvent("MouseEvents");click.initEvent("click", true, false);link.dispatchEvent(click);          

Still do not know if it needs to be a single mesh, though.

Link to comment
Share on other sites


module BABYLON {    export class STLFileLoader implements ISceneLoaderPlugin {        public solidPattern = /solid (\S*)([\S\s]*)endsolid[ ]*(\S*)/g;        public facetsPattern = /facet([\s\S]*?)endfacet/g;        public normalPattern = /normal[\s]+([\-+]?[0-9]+\.?[0-9]*([eE][\-+]?[0-9]+)?)+[\s]+([\-+]?[0-9]*\.?[0-9]+([eE][\-+]?[0-9]+)?)+[\s]+([\-+]?[0-9]*\.?[0-9]+([eE][\-+]?[0-9]+)?)+/g;        public vertexPattern = /vertex[\s]+([\-+]?[0-9]+\.?[0-9]*([eE][\-+]?[0-9]+)?)+[\s]+([\-+]?[0-9]*\.?[0-9]+([eE][\-+]?[0-9]+)?)+[\s]+([\-+]?[0-9]*\.?[0-9]+([eE][\-+]?[0-9]+)?)+/g;        public extensions = ".stl";        public importMesh(meshesNames: any, scene: Scene, data: any, rootUrl: string, meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]): boolean {            var matches;            while (matches = this.solidPattern.exec(data)) {                var meshName = matches[1];                var meshNameFromEnd = matches[3];                if (meshName != meshNameFromEnd) {                    console.log("error in stl, solid name != endsolid name");                }                //check meshesNames                if (meshesNames && meshName) {                    if (meshesNames instanceof Array) {                        if (!meshesNames.indexOf(meshName)) {                            continue;                        }                    } else {                        if (meshName !== meshesNames) {                            continue;                        }                    }                }                //stl mesh name can be empty as well                meshName = meshName || "stlmesh";                var babylonMesh = new Mesh(meshName, scene);                this.parseSolid(babylonMesh, matches[2]);            }            return true;        }        public load(scene: Scene, data: string, rootUrl: string): boolean {            return this.importMesh(null, scene, data, rootUrl, null, null, null);        }        private parseSolid(mesh: Mesh, solidData: string) {            var normals = [];            var positions = [];            var indices = [];            var indicesCount = 0;            //load facets, ignoring loop as the standard doesn't define it can contain more than vertices            var matches;            while (matches = this.facetsPattern.exec(solidData)) {                var facet = matches[1];                //one normal per face                var normalMatches = this.normalPattern.exec(facet);                this.normalPattern.lastIndex = 0;                if (!normalMatches) {                    continue;                }                var normal = [Number(normalMatches[1]), Number(normalMatches[5]), Number(normalMatches[3])];                var vertexMatch;                while (vertexMatch = this.vertexPattern.exec(facet)) {                    positions.push(Number(vertexMatch[1]), Number(vertexMatch[5]), Number(vertexMatch[3]));                    normals.push(normal[0], normal[1], normal[2]);                    indices.push(indicesCount++);                }                this.vertexPattern.lastIndex = 0;            }            this.facetsPattern.lastIndex = 0;            mesh.setVerticesData(VertexBuffer.PositionKind, positions);            mesh.setVerticesData(VertexBuffer.NormalKind, normals);            mesh.setIndices(indices);            mesh.computeWorldMatrix(true);        }    }    BABYLON.SceneLoader.RegisterPlugin(new STLFileLoader());}

Y and Z had to be switched, since every file i tested had them flipped. This should be investigated :-)


Regex were partly self-generated / modified and partly shamelessly stolen from a different (very famous and highly used) 3D WebGL engine. 


Want a PR for that?

Link to comment
Share on other sites


Here, you parse and store the STL faces as they are.

For adjacent faces, you don't try to reuse vertices what is quite complex.

So normals aren't computed by taking in account the fact a vertex could belong to more than one face.

Am I right ?


I guess we have to trust the face normals as they are set in the STL file.

Link to comment
Share on other sites

I am not making any optimizations. There is quite a lot that is possible, including normal computation in the engine, question is if it is needed. I used compute normals once, there was no change in the result, and I usually believe that the exported normals are correct.

Regarding vertex duplication - this is more than possible to integrate. I thought about it, this might reduce the amount of vertices in ~10-20% in simple meshes. I am simply not sure where this loader will be used, if it is just a temporary thing there is no need to invest too much :-) if it will be integrated in the framework, commenting and improvements are in order.

Link to comment
Share on other sites

@RaananW - The Y - Z switching is also done exporting out of Blender.  Think this is discussed as a "Left hand" - "Right hand" design difference.


Speaking of vertex reuse, it does add much complexity.  If you can read Python, check Blender exporter.  Since this is just "writing" to CPU / GPU memory, I do not see any advantage in doing this.  Suppose someone could combine this with serializing to a .babylon, but seems a very small use case.

Link to comment
Share on other sites


the only advantage of vertex re-use is in the case where the imported mesh is then updated within BJS and its normals recomputed.

The computeNormals() takes into account the vertex belonging to many faces.


I think it's not that important however ...

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Create New...