#pragma once #include "vde/core/point.h" #include #include #include #include #include namespace vde::mesh { using core::Point2D; using core::Point3D; using core::Vector3D; /** * @brief Marching Cubes 输出网格 * @ingroup mesh */ struct MCMesh { std::vector vertices; ///< 顶点坐标 std::vector> triangles; ///< 三角形索引 }; /** * @brief Marching Cubes 等值面提取 * * 从标量场 f(x,y,z) 中提取等值面 S = { (x,y,z) | f(x,y,z) = iso_level }。 * 将包围盒划分为 resolution×resolution×resolution 体素网格, * 在每个体素的 8 个角求值 f,查表确定等值面穿越该体素的三角形配置。 * * @param f 标量场函数 f(x,y,z) → double * @param iso_level 等值面值(默认 0) * @param bmin 包围盒最小角 * @param bmax 包围盒最大角 * @param resolution 每轴采样分辨率(≥ 1),总网格 = resolution³ 个立方体 * @return MCMesh 三角形网格 * * @note 使用经典的 256 查表法(Lorensen & Cline 1987) * @code{.cpp} * // 提取球面等值面 * auto f = [](double x,double y,double z) { * return sdf_sphere(x,y,z, 0,0,0, 1.0); * }; * auto mesh = marching_cubes(f, 0.0, * {-2,-2,-2}, {2,2,2}, 64); * @endcode * @see sdf_sphere sdf_box * @ingroup mesh */ MCMesh marching_cubes(const std::function& f, double iso_level, const Point3D& bmin, const Point3D& bmax, int resolution); /** * @brief SDF 球体函数 * * @param x,y,z 采样点坐标 * @param cx,cy,cz 球心坐标 * @param r 半径 * @return 有符号距离:内部 < 0,表面 = 0,外部 > 0 * * @code{.cpp} * auto sphere_sdf = [](double x,double y,double z) { * return sdf_sphere(x,y,z, 0,0,0, 1.0); * }; * @endcode * @ingroup mesh */ inline double sdf_sphere(double x, double y, double z, double cx, double cy, double cz, double r) { return std::sqrt((x-cx)*(x-cx) + (y-cy)*(y-cy) + (z-cz)*(z-cz)) - r; } /** * @brief SDF 立方体函数(轴对齐,中心在原点) * * @param x,y,z 采样点坐标 * @param hx,hy,hz 半边长 * @return 有符号距离 * * @ingroup mesh */ inline double sdf_box(double x, double y, double z, double hx, double hy, double hz) { double dx = std::abs(x) - hx, dy = std::abs(y) - hy, dz = std::abs(z) - hz; return std::sqrt(std::max(dx,0.0)*std::max(dx,0.0) + std::max(dy,0.0)*std::max(dy,0.0) + std::max(dz,0.0)*std::max(dz,0.0)) + std::min(std::max({dx,dy,dz}), 0.0); } /** * @brief SDF 平滑并集(Smooth Union) * * 对两个 SDF 做平滑混合,k 控制过渡区宽度。 * * @param d1,d2 两个 SDF 值 * @param k 平滑宽度(> 0),值越大过渡越平滑 * @return 混合后的 SDF 值 * * @ingroup mesh */ namespace { inline double lerp_impl(double a, double b, double t) { return a + t * (b - a); } } inline double sdf_smooth_union(double d1, double d2, double k) { double h = std::clamp(0.5 + 0.5*(d2-d1)/k, 0.0, 1.0); return lerp_impl(d2, d1, h) - k*h*(1.0-h); } /** * @brief SDF 平滑差集(Smooth Subtraction) * * d1 减去 d2,过渡区由 k 控制。 * * @param d1,d2 两个 SDF 值 * @param k 平滑宽度(> 0) * @return 混合后的 SDF 值 * * @ingroup mesh */ inline double sdf_smooth_subtraction(double d1, double d2, double k) { double h = std::clamp(0.5 - 0.5*(d2+d1)/k, 0.0, 1.0); return lerp_impl(d2, -d1, h) + k*h*(1.0-h); } } // namespace vde::mesh