浏览代码

normals example

Former-commit-id: de279a738556b4163b920296f44d49a91f3e6bf7
Alec Jacobson 11 年之前
父节点
当前提交
43b01106e9

+ 2 - 0
include/igl/normalize_row_lengths.h

@@ -16,6 +16,8 @@
 
 namespace igl
 {
+  // Obsolete: just use A.rowwise().normalize() or B=A.rowwise().normalized();
+  //
   // Normalize the rows in A so that their lengths are each 1 and place the new
   // entries in B
   // Inputs:

+ 1 - 3
include/igl/per_vertex_normals.cpp

@@ -8,7 +8,6 @@
 #include "per_vertex_normals.h"
 
 #include "per_face_normals.h"
-#include "normalize_row_lengths.h"
 
 template <typename DerivedV, typename DerivedF>
 IGL_INLINE void igl::per_vertex_normals(
@@ -48,8 +47,7 @@ IGL_INLINE void igl::per_vertex_normals(
       N.row(F(i,j)) += FN.row(i);
     }
   }
-  // normalize each row
-  igl::normalize_row_lengths(N,N);
+  N.rowwise().normalize();
 }
 
 #ifndef IGL_HEADER_ONLY

+ 18 - 13
tutorial/201_Normals/main.cpp

@@ -15,15 +15,19 @@ Eigen::MatrixXd N_corners;
 // This function is called every time a keyboard button is pressed
 bool key_down(igl::Viewer& viewer, unsigned char key, int modifier)
 {
-  if (key == '1')
-    viewer.set_normals(N_vertices);
-
-  if (key == '2')
-    viewer.set_normals(N_faces);
-
-  if (key == '3')
-    viewer.set_normals(N_corners);
-
+  switch(key)
+  {
+    case '1':
+      viewer.set_normals(N_faces);
+      return true;
+    case '2':
+      viewer.set_normals(N_vertices);
+      return true;
+    case '3':
+      viewer.set_normals(N_corners);
+      return true;
+    default: break;
+  }
   return false;
 }
 
@@ -32,18 +36,19 @@ int main(int argc, char *argv[])
   // Load a mesh in OFF format
   igl::readOFF("../shared/fandisk.off", V, F);
 
-  // Compute per-vertex normals
-  igl::per_vertex_normals(V,F,N_vertices);
-
   // Compute per-face normals
   igl::per_face_normals(V,F,N_faces);
 
-  // Compute per-corner normals
+  // Compute per-vertex normals
+  igl::per_vertex_normals(V,F,N_vertices);
+
+  // Compute per-corner normals, |dihedral angle| > 20 degrees --> crease
   igl::per_corner_normals(V,F,20,N_corners);
 
   // Plot the mesh
   igl::Viewer viewer;
   viewer.callback_key_down = &key_down;
+  viewer.options.show_lines = false;
   viewer.set_mesh(V, F);
   viewer.set_normals(N_vertices);
   viewer.launch();

+ 1 - 0
tutorial/images/fandisk-normals.jpg.REMOVED.git-id

@@ -0,0 +1 @@
+f2cb86a67341a5a5f3978f2c336eed2bb29cdc83

+ 59 - 0
tutorial/readme.md

@@ -33,6 +33,7 @@ applications for each topic.
 * **100_FileIO**: Example of reading/writing mesh files
 * **101_Serialization**: Example of using the XML serialization framework
 * **102_DrawMesh**: Example of plotting a mesh
+* [201 Normals](#norm)
 * [202 Gaussian Curvature](#gaus)
 * [203 Curvature Directions](#curv)
 * [204 Gradient](#grad)
@@ -71,6 +72,64 @@ mesh. This also provides an introduction to basic drawing and coloring routines
 in our example viewer. Finally, we construct popular discrete differential
 geometry operators.
 
+## <a id=norm></a> Normals
+
+### Per-face 
+Well defined normal orthogonal to triangle's plane. Produces piecewise-flat
+rending: not smooth.
+
+### Per-vertex
+Using per-vertex normals, Phong or Gouraud shading will produce smooth(er)
+renderings. Most techniques for computing per-vertex normals take an average of
+incident face normals. The techniques vary with respect to their different
+weighting schemes. Uniform weighting is heavily biased by the discretization
+choice, where as area-based or angle-based weighting is more forgiving.
+
+The typical half-edge style computation of area-based weights might look
+something like this:
+
+```cpp
+N.setZero(V.rows(),3);
+for(int i : vertices)
+{
+  for(face : incident_faces(i))
+  {
+    N.row(i) += face.area * face.normal;
+  }
+}
+N.rowwise().normalize();
+```
+
+Without a half-edge data-structure it may seem at first glance that looping
+over incident faces---and thus constructing the per-vertex normals---would be
+inefficient. However, per-vertex normals may be _throwing_ each face normal to
+running sums on its corner vertices:
+
+```cpp
+N.setZero(V.rows(),3);
+for(int f = 0; f < F.rows();f++)
+{
+  for(int c = 0; c < 3;c++)
+  {
+    N.row(F(f,c)) += area(f) * face_normal.row(f);
+  }
+}
+N.rowwise().normalize();
+```
+
+### Per-corner
+
+Storing normals per-corner is an efficient an convenient way of supporting both
+smooth and sharp (e.g. creases and corners) rendering. This format is common to
+OpenGL and the .obj mesh file format. Often such normals are tuned by the mesh
+designer, but creases and corners can also be computed automatically. Libigl
+implements a simple scheme which computes corner normals as averages of
+normals of faces incident on the corresponding vertex which do not deviate by a
+specified dihedral angle (e.g. 20°).
+
+![The `Normals` example computes per-face (left), per-vertex (middle) and
+per-corner (right) normals](images/fandisk-normals.jpg)
+
 ## <a id=gaus></a> Gaussian Curvature
 Gaussian curvature on a continuous surface is defined as the product of the
 principal curvatures: