PeteUK
PeteUK

Reputation: 1112

Triangle vertex winding order in stereolithography (STL) files (triangulated objects)

I'm working on an STL file importer and thought I'd make use of the normal given to determine the triangle winding order. Sample data with 4 triangles is included below (original data has over 70k triangles). My code's logic computes the normal assuming the vertices are specified anticlockwise, then does a dot product of this calculated normal with the supplied normal. If the result is positive, then I assume anticlockwise, else clockwise.

        tm.SetCCW(Dot(Cross(facet.getVertex2() - facet.getVertex1(),facet.getVertex3() - facet.getVertex1()),facet.getNormal()) > 0.0);

This logic fails on a set of files from a particular 3D scanner. When I load these files into Rhino3D though, and issue "Dir" to look at the normal direction, Rhino has the direction correct! Same with a couple of other STL viewers I've tried.

My code deduces that the vertices are supplied in clockwise order on the sample data, but when using that winding order, the model is inside-out, implying the supplied normals are wrong.

This leads me to the conclusion that it is convention for STL importers to ignore the supplied normal, and assume anticlockwise winding order. I'm looking for people with more experience in the STL file format to weigh in on whether my assumption is correct.

solid object_name
    facet normal -0.651094 0.733745 -0.194150
        outer loop
            vertex 30.335684 -40.893806 -68.126500
            vertex 31.155055 -39.911656 -67.162500
            vertex 30.263726 -40.702583 -67.162500
        endloop
    endfacet
    facet normal -0.654292 0.732059 -0.189714
        outer loop
            vertex 30.335684 -40.893806 -68.126500
            vertex 31.225185 -40.098797 -68.126500
            vertex 31.155055 -39.911656 -67.162500
        endloop
    endfacet
    facet normal -0.711866 0.677947 -0.183397
        outer loop
            vertex 31.225185 -40.098797 -68.126500
            vertex 31.980540 -39.044870 -67.162500
            vertex 31.155055 -39.911656 -67.162500
        endloop
    endfacet
    facet normal -0.714326 0.676343 -0.179716
        outer loop
            vertex 31.225185 -40.098797 -68.126500
            vertex 32.048799 -39.228928 -68.126500
            vertex 31.980540 -39.044870 -67.162500
        endloop
    endfacet
endsolid

EDIT: My calculations for the first facet:

p1 = {30.335684, -40.893806, -68.126500}
p2 = {31.155055, -39.911656, -67.162500}
p3 = {30.263726, -40.702583, -67.162500}

u = p2 - p1 = {0.819371, 0.98215, 0.964}
w = p3 - p1 = {-0.071958, 0.191223, 0.964}

u x w = {0.762454, -0.859241, 0.227356}   (calculated normal)

given normal = {-0.651094, 0.733745, -0.194150}

calculated_normal <dot> given_normal = -1.17103

verdict: 90 < theta < 270 where theta is the angle between the calculated and given normals

Upvotes: 3

Views: 3618

Answers (1)

Bill H
Bill H

Reputation: 41

The vertices should be in counter-clockwise order when the vertices are viewed from outside of the object. (Obviously, viewing from inside the object they are then in clockwise order).

The normal should point outward.

I have read that some programs ignore the normal and only go by the vertex ordering, and I've even read a recommendation to set the normal to {0.0, 0.0, 0.0}, although the specification states that the normal and the vertex order should both be used.

The normal is redundant though. For many programs, the vertex order is all that is necessary. I don't know if that is generally true for all programs. I recommend making both be correct.

Upvotes: 4

Related Questions