I tried to implement a grid that has all the face normals pointing out. To realize this, I load the grid from the * .ctm file, then look through all the triangles to determine the normal using the cross product, and if the normal points to the negative z direction, I flip v1 and v2 (thus the normal orientation). After that, I save the result in a * .ctm file and view it using Meshlab.
The result in Meshlab still shows that the normals indicate both positive and negative z directions (seen from black triangles). Also, when viewing the normals in Meshlab, they do point back.
Can someone give me some tips on how to solve this?
The source code for the normalization part is:
pcl::PointCloud<pcl::PointXYZRGBA>::Ptr cloud1 (new pcl::PointCloud<pcl::PointXYZRGBA> ()); pcl::fromROSMsg (meshFixed.cloud,*cloud1);for(std::vector<pcl::Vertices>::iterator it = meshFixed.polygons.begin(); it != meshFixed.polygons.end(); ++it) { alglib::real_2d_array v0; double _v0[] = {cloud1->points[it->vertices[0]].x,cloud1->points[it->vertices[0]].y,cloud1->points[it->vertices[0]].z}; v0.setcontent(3,1,_v0); //3 rows, 1col alglib::real_2d_array v1; double _v1[] = {cloud1->points[it->vertices[1]].x,cloud1->points[it->vertices[1]].y,cloud1->points[it->vertices[1]].z}; v1.setcontent(3,1,_v1); //3 rows, 1col alglib::real_2d_array v2; double _v2[] = {cloud1->points[it->vertices[2]].x,cloud1->points[it->vertices[2]].y,cloud1->points[it->vertices[2]].z}; v2.setcontent(1,3,_v2); //3 rows, 1col alglib::real_2d_array normal; normal = cross(v1-v0,v2-v0); //if z<0 change indices order v1->v2 and v2->v1 alglib::real_2d_array normalizedNormal; if(normal[2][0]<0) { int index1,index2; index1 = it->vertices[1]; index2 = it->vertices[2]; it->vertices[1] = index2; it->vertices[2] = index1; //make normal of length 1 double normalScaling = 1.0/sqrt(dot(normal,normal)); normal[0][0] = -1*normal[0][0]; normal[1][0] = -1*normal[1][0]; normal[2][0] = -1*normal[2][0]; normalizedNormal = normalScaling * normal; } else { //make normal of length 1 double normalScaling = 1.0/sqrt(dot(normal,normal)); normalizedNormal = normalScaling * normal; } //add to normal cloud pcl::Normal pclNormalizedNormal; pclNormalizedNormal.normal_x = normalizedNormal[0][0]; pclNormalizedNormal.normal_y = normalizedNormal[1][0]; pclNormalizedNormal.normal_z = normalizedNormal[2][0]; normalsFixed.push_back(pclNormalizedNormal); }
Result of this code:

I found the code in the VCG library to orient the normals of the face and vertices. After use, most of the mesh has the correct face normals, but not all.
New code:
// VCG library implementation MyMesh m; // Convert pcl::PolygonMesh to VCG MyMesh m.Clear(); // Create temporary cloud in to have handy struct object pcl::PointCloud<pcl::PointXYZRGBA>::Ptr cloud1 (new pcl::PointCloud<pcl::PointXYZRGBA> ()); pcl::fromROSMsg (meshFixed.cloud,*cloud1); // Now convert the vertices to VCG MyMesh int vertCount = cloud1->width*cloud1->height; vcg::tri::Allocator<MyMesh>::AddVertices(m, vertCount); for(unsigned int i=0;i<vertCount;++i) m.vert[i].P()=vcg::Point3f(cloud1->points[i].x,cloud1->points[i].y,cloud1->points[i].z); // Now convert the polygon indices to VCG MyMesh => make VCG faces.. int triCount = meshFixed.polygons.size(); if(triCount==1) { if(meshFixed.polygons[0].vertices[0]==0 && meshFixed.polygons[0].vertices[1]==0 && meshFixed.polygons[0].vertices[2]==0) triCount=0; } Allocator<MyMesh>::AddFaces(m, triCount); for(unsigned int i=0;i<triCount;++i) { m.face[i].V(0)=&m.vert[meshFixed.polygons[i].vertices[0]]; m.face[i].V(1)=&m.vert[meshFixed.polygons[i].vertices[1]]; m.face[i].V(2)=&m.vert[meshFixed.polygons[i].vertices[2]]; } vcg::tri::UpdateBounding<MyMesh>::Box(m); vcg::tri::UpdateNormal<MyMesh>::PerFace(m); vcg::tri::UpdateNormal<MyMesh>::PerVertexNormalizedPerFace(m); printf("Input mesh vn:%i fn:%i\n",m.VN(),m.FN()); // Start to flip all normals to outside vcg::face::FFAdj<MyMesh>::FFAdj(); vcg::tri::UpdateTopology<MyMesh>::FaceFace(m); bool oriented, orientable; if ( vcg::tri::Clean<MyMesh>::CountNonManifoldEdgeFF(m)>0 ) { std::cout << "Mesh has some not 2-manifold faces, Orientability requires manifoldness" << std::endl; // text return; // can't continue, mesh can't be processed } vcg::tri::Clean<MyMesh>::OrientCoherentlyMesh(m, oriented,orientable); vcg::tri::Clean<MyMesh>::FlipNormalOutside(m); vcg::tri::Clean<MyMesh>::FlipMesh(m); //vcg::tri::UpdateTopology<MyMesh>::FaceFace(m); //vcg::tri::UpdateTopology<MyMesh>::TestFaceFace(m); vcg::tri::UpdateNormal<MyMesh>::PerVertexNormalizedPerFace(m); vcg::tri::UpdateNormal<MyMesh>::PerVertexFromCurrentFaceNormal(m); // now convert VCG back to pcl::PolygonMesh pcl::PointCloud<pcl::PointXYZRGBA>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZRGBA>); cloud->is_dense = false; cloud->width = vertCount; cloud->height = 1; cloud->points.resize (vertCount); // Now fill the pointcloud of the mesh for(int i=0; i<vertCount; i++) { cloud->points[i].x = m.vert[i].P()[0]; cloud->points[i].y = m.vert[i].P()[1]; cloud->points[i].z = m.vert[i].P()[2]; } pcl::toROSMsg(*cloud,meshFixed.cloud); std::vector<pcl::Vertices> polygons; // Now fill the indices of the triangles/faces of the mesh for(int i=0; i<triCount; i++) { pcl::Vertices vertices; vertices.vertices.push_back(m.face[i].V(0)-&*m.vert.begin()); vertices.vertices.push_back(m.face[i].V(1)-&*m.vert.begin()); vertices.vertices.push_back(m.face[i].V(2)-&*m.vert.begin()); polygons.push_back(vertices); } meshFixed.polygons = polygons;
The result is: (Meshlab still shows that the normals are facing both sides)
