// copyVertexListToPointList a vector for Vec3 into a vector of Point's.
void copyVertexListToPointList(const VertexList& in,PointList& out)
{
    out.reserve(in.size());
    for(VertexList::const_iterator itr=in.begin();
        itr!=in.end();
        ++itr)
    {
        out.push_back(Point(0,*itr));
    }
}
Пример #2
0
// adapted from http://www.cgal.org/Manual/beta/examples/Surface_reconstruction_points_3/poisson_reconstruction_example.cpp
Mesh poissonSurface(const Mat ipoints, const Mat normals)
{
    // Poisson options
    FT sm_angle = 20.0; // Min triangle angle in degrees.
    FT sm_radius = 300; // Max triangle size w.r.t. point set average spacing.
    FT sm_distance = 0.375; // Surface Approximation error w.r.t. point set average spacing.

    PointList points;
    points.reserve(ipoints.rows);
    float min = 0, max = 0;
    for (int i=0; i<ipoints.rows; i++) {
        float const *p = ipoints.ptr<float const>(i), *n = normals.ptr<float const>(i);
        points.push_back(Point_with_normal(Point(p[0]/p[3], p[1]/p[3], p[2]/p[3]), Vector(n[0], n[1], n[2])));
        if (p[0]/p[3] > max) max = p[0]/p[3];
        if (p[0]/p[3] < min) min = p[0]/p[3];
    }

    // Creates implicit function from the read points using the default solver.

    // Note: this method requires an iterator over points
    // + property maps to access each point's position and normal.
    // The position property map can be omitted here as we use iterators over Point_3 elements.
    Poisson_reconstruction_function function(points.begin(), points.end(), CGAL::make_normal_of_point_with_normal_pmap(points.begin()) );

    // Computes the Poisson indicator function f() at each vertex of the triangulation.
    bool success = function.compute_implicit_function();
    assert(success);
#ifdef TEST_BUILD
    printf("implicit function ready. Meshing...\n");
#endif
    // Computes average spacing
    FT average_spacing = CGAL::compute_average_spacing(points.begin(), points.end(), 6 /* knn = 1 ring */);

    // Gets one point inside the implicit surface
    // and computes implicit function bounding sphere radius.
    Point inner_point = function.get_inner_point();
    Sphere bsphere = function.bounding_sphere();
    FT radius = std::sqrt(bsphere.squared_radius());

    // Defines the implicit surface: requires defining a
    // conservative bounding sphere centered at inner point.
    FT sm_sphere_radius = 5.0 * radius;
    FT sm_dichotomy_error = sm_distance*average_spacing/1000.0; // Dichotomy error must be << sm_distance
    Surface_3 surface(function, Sphere(inner_point,sm_sphere_radius*sm_sphere_radius), sm_dichotomy_error/sm_sphere_radius);

    // Defines surface mesh generation criteria
    // parameters: min triangle angle (degrees), max triangle size, approximation error
    CGAL::Surface_mesh_default_criteria_3<STr> criteria(sm_angle, sm_radius*average_spacing, sm_distance*average_spacing);

    // Generates surface mesh with manifold option
    STr tr; // 3D Delaunay triangulation for surface mesh generation
    C2t3 c2t3(tr); // 2D complex in 3D Delaunay triangulation
    // parameters: reconstructed mesh, implicit surface, meshing criteria, 'do not require manifold mesh'
    CGAL::make_surface_mesh(c2t3, surface, criteria, CGAL::Non_manifold_tag());

    assert(tr.number_of_vertices() > 0);

    // Search structure: index of the vertex at an exactly given position
    std::map<Point, int> vertexIndices;

    // Extract all vertices of the resulting mesh
    Mat vertices(tr.number_of_vertices(), 4, CV_32FC1), faces(c2t3.number_of_facets(), 3, CV_32SC1);
#ifdef TEST_BUILD
    printf("%i vertices, %i facets. Converting...\n", vertices.rows, faces.rows);
#endif
    {   int i=0;
        for (C2t3::Vertex_iterator it=c2t3.vertices_begin(); it!=c2t3.vertices_end(); it++, i++) {
            float *vertex = vertices.ptr<float>(i);
            Point p = it->point();
            vertex[0] = p.x();
            vertex[1] = p.y();
            vertex[2] = p.z();
            vertex[3] = 1;
            vertexIndices[p] = i;
        }
        vertices.resize(i);
    }

    // Extract all faces of the resulting mesh and calculate the index of each of their vertices
    {   int i=0;
        for (C2t3::Facet_iterator it=c2t3.facets_begin(); it!=c2t3.facets_end(); it++, i++) {
            Cell cell = *it->first;
            int vertex_excluded = it->second;
            int32_t* outfacet = faces.ptr<int32_t>(i);
            // a little magic so that face normals are oriented outside
            char sign = (function(cell.vertex(vertex_excluded)->point()) > 0) ? 1 : 2; // 2 = -1 (mod 3)
            for (char j = vertex_excluded + 1; j < vertex_excluded + 4; j++) {
                outfacet[(sign*j)%3] = vertexIndices[cell.vertex(j%4)->point()];
            }
        }
    }

    return Mesh(vertices, faces);
}
bool ShadowVolumeOccluder::computeOccluder(const NodePath& nodePath,const ConvexPlanarOccluder& occluder,CullStack& cullStack,bool /*createDrawables*/)
{


//    std::cout<<"    Computing Occluder"<<std::endl;

    CullingSet& cullingset = cullStack.getCurrentCullingSet();

    const RefMatrix& MV = *cullStack.getModelViewMatrix();
    const RefMatrix& P = *cullStack.getProjectionMatrix();

    // take a reference to the NodePath to this occluder.
    _nodePath = nodePath;

    // take a reference to the projection matrix.
    _projectionMatrix = &P;
    
    // initialize the volume
    _volume = 0.0f;
    

    // compute the inverse of the projection matrix.
    Matrix invP;
    invP.invert(P);
    
    float volumeview = cullStack.getFrustumVolume();

    
    // compute the transformation matrix which takes form local coords into clip space.
    Matrix MVP(MV*P);
    
    // for the occluder polygon and each of the holes do
    //     first transform occluder polygon into clipspace by multiple it by c[i] = v[i]*(MV*P)
    //     then push to coords to far plane by setting its coord to c[i].z = -1.
    //     then transform far plane polygon back into projection space, by p[i]*inv(P)
    //     compute orientation of front plane, if normal.z()<0 then facing away from eye pont, so reverse the polygons, or simply invert planes.
    //     compute volume (quality) betwen front polygon in projection space and back polygon in projection space.
    
    
    const VertexList& vertices_in = occluder.getOccluder().getVertexList();
    
    PointList points;
    
    if (clip(cullingset.getFrustum().getPlaneList(),vertices_in,points)>=3)
    {
        // compute the points on the far plane.
        PointList farPoints;
        farPoints.reserve(points.size());
        transform(points,farPoints,MVP);
        pushToFarPlane(farPoints);
        transform(farPoints,invP);
        
        // move the occlude points into projection space.
        transform(points,MV);

        // use the points on the front plane as reference vertices on the _occluderVolume
        // so that the vertices can later by used to test for occlusion of the occluder itself.
        copyPointListToVertexList(points,_occluderVolume.getReferenceVertexList());

        // create the front face of the occluder
        Plane occludePlane = computeFrontPlane(points);
        _occluderVolume.add(occludePlane);

        // create the sides of the occluder
        computePlanes(points,farPoints,_occluderVolume.getPlaneList());

        _occluderVolume.setupMask();
        
        // if the front face is pointing away from the eye point flip the whole polytope.
        if (occludePlane[3]>0.0f)
        {
            _occluderVolume.flip();
        }
        
        _volume = computePolytopeVolume(points,farPoints)/volumeview;

        
        for(ConvexPlanarOccluder::HoleList::const_iterator hitr=occluder.getHoleList().begin();
            hitr!=occluder.getHoleList().end();
            ++hitr)
        {
            PointList points;
            if (clip(cullingset.getFrustum().getPlaneList(),hitr->getVertexList(),points)>=3)
            {
                _holeList.push_back(Polytope());
                Polytope& polytope = _holeList.back();

                // compute the points on the far plane.
                PointList farPoints;
                farPoints.reserve(points.size());
                transform(points,farPoints,MVP);
                pushToFarPlane(farPoints);
                transform(farPoints,invP);

                // move the occlude points into projection space.
                transform(points,MV);

                // use the points on the front plane as reference vertices on the _occluderVolume
                // so that the vertices can later by used to test for occlusion of the occluder itself.
                copyPointListToVertexList(points,polytope.getReferenceVertexList());

                // create the front face of the occluder
                Plane occludePlane = computeFrontPlane(points);

                // create the sides of the occluder
                computePlanes(points,farPoints,polytope.getPlaneList());

                polytope.setupMask();

                // if the front face is pointing away from the eye point flip the whole polytope.
                if (occludePlane[3]>0.0f)
                {
                    polytope.flip();
                }

                // remove the hole's volume from the occluder volume.
                _volume -= computePolytopeVolume(points,farPoints)/volumeview;
            }
            
        }

        //std::cout << "final volume = "<<_volume<<std::endl;

        return true;
    }
    return false;
}