CGAL - OpenVDB网格化中的噪声

编程语言 2026-07-09

我正在尝试使用CGAL对一个OpenVDB (.vdb) 文件进行网格化。

在中等网格分辨率下,对有机形体的网格化效果很好。但特别是在尝试对高纵横比的形体进行网格化时,我输出的网格会有相当明显的噪声。起初我以为可能是体素分辨率过低导致的,但这个问题似乎并未因此而受到影响。

这个脚本是一个最小版本,用来重现这个问题(你需要CGAL和 OpenVDB的库,可能需要以release构建,至少我在调试模式下构建时遇到了困难):

#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Mesh_triangulation_3.h>
#include <CGAL/Mesh_complex_3_in_triangulation_3.h>
#include <CGAL/Mesh_criteria_3.h>
#include <CGAL/Labeled_mesh_domain_3.h>
#include <CGAL/make_mesh_3.h>

#include <openvdb/openvdb.h>
#include <openvdb/tools/Interpolation.h>

typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef CGAL::Labeled_mesh_domain_3<K>                     Mesh_domain;
typedef CGAL::Mesh_triangulation_3<Mesh_domain>::type       Tr;
typedef CGAL::Mesh_complex_3_in_triangulation_3<Tr>         C3t3;
typedef CGAL::Mesh_criteria_3<Tr>                           Mesh_criteria;

namespace params = CGAL::parameters;

int main()
{
    // --- Load VDB ---
    openvdb::initialize();
    openvdb::io::File file("../data/Cylinder.vdb");
    file.open();
    auto grid = openvdb::gridPtrCast<openvdb::FloatGrid>(
        file.readGrid(file.beginName().gridName()));
    file.close();

    const double voxelSize = grid->transform().voxelSize()[0];
    const openvdb::math::Transform& xform = grid->transform();

    // --- Bounding box ---
    openvdb::CoordBBox bbox = grid->evalActiveVoxelBoundingBox();
    openvdb::Vec3d worldMin = xform.indexToWorld(bbox.min().asVec3d());
    openvdb::Vec3d worldMax = xform.indexToWorld(bbox.max().asVec3d());

    K::Iso_cuboid_3 boundingBox(
        K::Point_3(worldMin[0], worldMin[1], worldMin[2]),
        K::Point_3(worldMax[0], worldMax[1], worldMax[2]));

    // --- Implicit domain from VDB SDF ---
    auto accessor = grid->getConstAccessor();
    Mesh_domain domain = Mesh_domain::create_implicit_mesh_domain(
        [&accessor, &xform, voxelSize](const K::Point_3& p) -> K::FT {
            openvdb::Vec3d idx = xform.worldToIndex(
                openvdb::Vec3d(p.x(), p.y(), p.z()));
            float val = openvdb::tools::PointSampler::sample(accessor, idx);
            return static_cast<K::FT>(val * voxelSize);
        },
        boundingBox);

    // --- Mesh criteria ---
    Mesh_criteria criteria(
        params::facet_angle(20)
               .facet_size(voxelSize * 300)
               .facet_distance(voxelSize * 3)
               .cell_radius_edge_ratio(2)
               .cell_size(voxelSize * 300));

    C3t3 c3t3 = CGAL::make_mesh_3<C3t3>(domain, criteria);

    std::ofstream out("out.mesh");
    CGAL::IO::write_MEDIT(out, c3t3);

    return 0;
}

有人有解决方法/解释吗,或者有其他方法能够用CGAL对 .vdb文件进行网格化吗?

低分辨率示例

高分辨率示例

解决方案

尝试在命名参数 relative_error_bound 中放入更好的近似。

   * \cgalNamedParamsBegin
   *   \cgalParamNBegin{relative_error_bound}
   *      \cgalParamDescription{the relative error bound used to compute intersection points between the implicit surface and query segments.
   *                            The bisection is stopped when the length of the intersected segment is less than the product
   *                            of `relative_error_bound` by the diameter of the bounding object.}
   *      \cgalParamDefault{FT(1e-3)}
   *   \cgalParamNEnd
   * \cgalNamedParamsEnd
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章