Loading...
Logo
Processing Forum
Hi all, I'm trying to figure out the direction of the normal of a face from an STL file I've loaded using Toxiclibs.  I did something very similar with the OBJloader library without issue (but have abandonded that library because it seems to have a lot of problems loading my files, whereas my STLs from Rhino have no issue with Toxiclibs).

Ultimately, the project is sort of a hack of ray-casting, so I need to know if I'm hitting the front or back of a face.

Looking at the normals, they appear to be normalized but I can't figure out how to go from that to direction.  It appears that STLs don't store normal's direction: "In most software this may be set to (0,0,0) and the software will automatically calculate a normal based on the order of the triangle vertices using the 'right-hand rule'."

Can this be done within the library (and I've simply missed this)?  Anyone implemented something similar or the right-hand rule ( http://en.wikipedia.org/wiki/Right-hand_rule)?

Thanks!

Replies(3)

Since sleep is optional, some more digging may have found a possible answer: the STL format lists the vertices in a specific order and when following the right-hand rule you can determine the direction of the normal by getting the cross-product of two corners in the order listed.  Here's some code (a little sloppy) that shows how reading the points one way will result in a +z vector and the other way in a -z.

Copy code
  1. // three corners, stored as vectors for convenience
  2. // the three values are x, y, and z coordinates
  3. PVector a = new PVector(200, -200, 0);
  4. PVector b = new PVector(0, 200, 0);
  5. PVector c = new PVector(-200, -200, 0);

  6. // other variables
  7. float rotX, rotY, ctrX, ctrY, ctrZ;
  8. PFont font;

  9. void setup() {
  10.   size(500, 500, P3D);
  11.   smooth();
  12.  
  13.   // find the center of the triangle
  14.   ctrX = (a.x + b.x + c.x)/3;
  15.   ctrY = (a.y + b.y + c.y)/3;
  16.   ctrZ = (a.z + b.z + c.z)/3;
  17.   font = loadFont("SansSerif-48.vlw");
  18.   textFont(font, 48);
  19.  
  20.   // find the direction of the normal!
  21.   // using right-to-left (A>B, B>C, or C>A)
  22.   PVector rh = a.cross(b);  // same result with other two combinations
  23.   rh.normalize();
  24.  
  25.   // result will be opposite if we reverse the
  26.   // order of points (C>B, B>A, or A>C)
  27.   PVector lh = b.cross(a);
  28.   lh.normalize();
  29.  
  30.   println("RIGHT-HAND: " + rh.x + ", " + rh.y + ", " + rh.z);
  31.   println("LEFT-HAND:  " + lh.x + ", " + lh.y + ", " + lh.z);
  32. }
  33. void draw() {
  34.  
  35.   // basic drawing stuff
  36.   background(150);
  37.   lights();
  38.   translate(width/2, height/2, 0);
  39.   rotateX(rotX + QUARTER_PI);
  40.   rotateY(rotY);
  41.  
  42.   // draw triangle
  43.   fill(255, 150, 0);
  44.   stroke(0);
  45.   beginShape();
  46.   vertex(a.x, a.y, a.z);
  47.   vertex(b.x, b.y, b.z);
  48.   vertex(c.x, c.y, c.z);
  49.   endShape(CLOSE);
  50.  
  51.   // label corners
  52.   fill(0);
  53.   text("A", a.x, a.y-50, a.z);
  54.   text("B", b.x+50, b.y, b.z);
  55.   text("C", c.x, c.y-50, c.z);
  56.  
  57.   // identify the center
  58.   pushMatrix();
  59.   translate(ctrX, ctrY, ctrZ);
  60.   fill(0);
  61.   noStroke();
  62.   sphere(10);
  63.   popMatrix();
  64. }

  65. void mouseDragged() {
  66.   rotX += (mouseX - pmouseX) * 0.01;
  67.   rotY -= (mouseY - pmouseY) * 0.01;
  68. }
However, it is late and I may be missing something obvious...
See the STLImportTest example under core/mesh. The normals are already a standard aspect of the TriangleMesh that the STL is imported into. See the TriangleMesh Toxiclibs javadocs for methods, such as computeFaceNormals() and getFaceNormalsAsArray(). However the normals are already calculated by default I believe when the STL is imported. Because in the example the normals are displayed at line length 10 (increase number to increase length) with the following display function:
Copy code
  1.   gfx.mesh(mesh,false,10); // means display mesh, no smooth, normals at line length 10
You can get to specific normals via TriangleMesh > Face > Normal which in code would be just...
Copy code
  1.   for (Face f : mesh.faces) {
  2.     println(f.normal);
  3.   }
Thanks Amnon, I should have mentioned that that's the method I had originally been using, but the returned list seemed strange.  I'm using a very simple box for testing so I can see what's happening - it has 12 triangles which should be 6 faces, but the normals array returns 144 sets of x,y,z coords.  When I check the number of vertices (returned as an array) I get 24, or 6 faces x 3 points each, as expected.

Hope that makes sense!