Como unificar a orientação normal

Eu tenho tentado perceber uma malha que tem todas as faces normais apontando para fora. Para perceber isso, eu carrego uma malha de um arquivo * .ctm, em seguida, percorro todos os triângulos para determinar o normal usando um produto cruzado e se a normal estiver apontando para a direção z negativa, eu viro v1 e v2 (assim orientação normal). Depois disso, salve o resultado em um arquivo * .ctm e visualize-o com o Meshlab.

O resultado no Meshlab ainda mostra que as normais estão apontando na direção z positiva e negativa (pode ser vista nos triângulos pretos). Além disso, ao visualizar as normais no Meshlab, elas estão realmente apontando para trás.

Alguém pode me dar algum conselho sobre como resolver isso?

O código fonte da parte de normalização é:

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);
} 

O resultado deste código é:

Eu encontrei algum código na biblioteca VCG para orientar as normais de face e vértice. Depois de usar isso, uma grande parte da malha tem normais de face corretos, mas não todas.

O novo código:

// 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;

Que resulta em: (o Meshlab ainda mostra que as normais estão voltadas para os dois lados)

questionAnswers(1)

yourAnswerToTheQuestion