$search
00001 /* 00002 Szymon Rusinkiewicz 00003 Stanford Graphics Lab 00004 00005 trimesh_normals.cc 00006 Computation of per-vertex normals for trimeshes. 00007 */ 00008 00009 #include <stdio.h> 00010 #include "triutil.h" 00011 #include "trimesh.h" 00012 00013 namespace trimesh { 00014 00015 // Finds area-weighted per-vertex normals 00016 void TriMesh::FindNormals() 00017 { 00018 need_faces(); 00019 00020 printf("Computing normals... "); fflush(stdout); 00021 00022 if (!normals) 00023 normals = new vec[numvertices]; 00024 memset(normals, 0, numvertices*sizeof(vec)); 00025 00026 // For each face... 00027 for (int i=0; i < numfaces; i++) { 00028 // Find normal 00029 vec facenormal; 00030 FindNormal(vertices[faces[i][0]], 00031 vertices[faces[i][1]], 00032 vertices[faces[i][2]], 00033 facenormal); 00034 00035 // Accumulate. Note that facenormal is not unit-length, so 00036 // it is really an *area-weighted* normal. 00037 normals[faces[i][0]][0] += facenormal[0]; 00038 normals[faces[i][0]][1] += facenormal[1]; 00039 normals[faces[i][0]][2] += facenormal[2]; 00040 00041 normals[faces[i][1]][0] += facenormal[0]; 00042 normals[faces[i][1]][1] += facenormal[1]; 00043 normals[faces[i][1]][2] += facenormal[2]; 00044 00045 normals[faces[i][2]][0] += facenormal[0]; 00046 normals[faces[i][2]][1] += facenormal[1]; 00047 normals[faces[i][2]][2] += facenormal[2]; 00048 } 00049 00050 // Go back and make sure they're all unit-length 00051 for (int i=0; i < numvertices; i++) { 00052 float l = Len(normals[i]); 00053 if (l == 0) { 00054 normals[i][0] = normals[i][1] = 0; 00055 normals[i][2] = 1; 00056 continue; 00057 } 00058 float x = 1.0f/l; 00059 normals[i][0] *= x; 00060 normals[i][1] *= x; 00061 normals[i][2] *= x; 00062 } 00063 00064 printf("Done.\n"); 00065 SmoothNormals(1); 00066 } 00067 00068 00069 // Smooth out the normals in the mesh. The parameter tells how much smoothing 00070 // to do. Less smoothing is done in areas with sharp features. 00071 void TriMesh::SmoothNormals(float smooth) 00072 { 00073 need_faces(); 00074 need_normals(); 00075 00076 printf("Smoothing normals... "); fflush(stdout); 00077 00078 vec *newnormals = new vec[numvertices]; 00079 memset(newnormals, 0, numvertices*sizeof(vec)); 00080 00081 for (int i=0; i < numfaces; i++) { 00082 vec facenormal = { normals[faces[i][0]][0] + 00083 normals[faces[i][1]][0] + 00084 normals[faces[i][2]][0] , 00085 normals[faces[i][0]][1] + 00086 normals[faces[i][1]][1] + 00087 normals[faces[i][2]][1] , 00088 normals[faces[i][0]][2] + 00089 normals[faces[i][1]][2] + 00090 normals[faces[i][2]][2] }; 00091 newnormals[faces[i][0]][0] += facenormal[0]; 00092 newnormals[faces[i][1]][0] += facenormal[0]; 00093 newnormals[faces[i][2]][0] += facenormal[0]; 00094 newnormals[faces[i][0]][1] += facenormal[1]; 00095 newnormals[faces[i][1]][1] += facenormal[1]; 00096 newnormals[faces[i][2]][1] += facenormal[1]; 00097 newnormals[faces[i][0]][2] += facenormal[2]; 00098 newnormals[faces[i][1]][2] += facenormal[2]; 00099 newnormals[faces[i][2]][2] += facenormal[2]; 00100 } 00101 00102 for (int i=0; i < numvertices; i++) { 00103 Normalize(newnormals[i]); 00104 00105 // In an effort to avoid smoothing out features, we adjust the 00106 // smoothing based on how much we're about to change this 00107 // normal. 00108 float this_smooth = smooth; 00109 this_smooth *= Dot(newnormals[i], normals[i]); 00110 00111 normals[i][0] += this_smooth*newnormals[i][0]; 00112 normals[i][1] += this_smooth*newnormals[i][1]; 00113 normals[i][2] += this_smooth*newnormals[i][2]; 00114 00115 Normalize(normals[i]); 00116 } 00117 00118 delete [] newnormals; 00119 printf("Done.\n"); 00120 } 00121 00122 } // namespace trimesh