# SDF 隐式建模教程 有符号距离函数(Signed Distance Function)是 ViewDesignEngine 的核心建模方式之一。 通过数学函数直接定义几何体,无需依赖网格或曲面表示。 ## 核心概念 SDF 函数 `f(p)` 返回点 `p` 到最近表面的有符号距离: - `f(p) < 0`:点在几何体**内部** - `f(p) = 0`:点在几何体**表面**上 - `f(p) > 0`:点在几何体**外部** ## 基本图元(球、盒、环) ViewDesignEngine 提供的内建 SDF 图元,定义在 `vde/sdf/sdf_primitives.h`: ```cpp #include using namespace vde::sdf; using namespace vde::core; // 球体:位于原点,半径 1.0 double d = sphere(Point3D(1.0, 0.0, 0.0), 1.0); // d ≈ 0.0(点在球面上) // 轴对齐盒子:以原点为中心,半长为 halfExtent auto box_fn = [](double x, double y, double z) { return box(Point3D(x, y, z), Point3D(1.5, 1.5, 0.5)); }; // 环面(torus):major_radius = 环半径,minor_radius = 管半径 auto torus_fn = [](double x, double y, double z) { return torus(Point3D(x, y, z), 2.0, 0.4); }; // 椭球:指定各轴半径 auto ellipsoid_fn = [](double x, double y, double z) { return ellipsoid(Point3D(x, y, z), Point3D(2.0, 1.0, 1.5)); }; // 圆柱(沿 Y 轴) auto cylinder_fn = [](double x, double y, double z) { return cylinder(Point3D(x, y, z), 0.5, 3.0); }; // 胶囊体:两点 + 半径 auto capsule_fn = [](double x, double y, double z) { return capsule(Point3D(x, y, z), Point3D(0, -2, 0), Point3D(0, 2, 0), 0.4); }; // 无限长圆柱:沿任意轴 auto inf_cyl = [](double x, double y, double z) { return infinite_cylinder(Point3D(x, y, z), Vector3D(0, 0, 1), 0.5); }; ``` ## CSG 操作(并、交、差、光滑并集) 布尔组合运算定义在 `vde/sdf/sdf_operations.h`: ```cpp #include #include using namespace vde::sdf; // === 标准布尔运算 === // 并集 A ∪ B:取最小值(两个几何体的合并) auto union_shape = [](double x, double y, double z) { Point3D p(x, y, z); return op_union(sphere(p, 1.0), box(p, Point3D(0.8, 0.8, 0.8))); }; // 交集 A ∩ B:取最大值(两个几何体的共同区域) auto intersect_shape = [](double x, double y, double z) { Point3D p(x, y, z); return op_intersection(sphere(p, 1.0), box(p, Point3D(0.6, 0.6, 0.6))); }; // 差集 A \ B:从 A 中减去 B auto diff_shape = [](double x, double y, double z) { Point3D p(x, y, z); return op_difference(sphere(p, 1.0), box(p, Point3D(0.4, 0.4, 0.4))); }; // === 光滑布尔运算(带有机融合过渡) === // smooth union,k 控制过渡弧度 auto smooth_union_shape = [](double x, double y, double z) { Point3D p(x, y, z); double d1 = sphere(p, 1.0); double d2 = sphere(p - Point3D(1.5, 0, 0), 1.0); return op_smooth_union(d1, d2, 0.3); // k=0.3 适中的融合 }; // smooth intersection auto smooth_isect_shape = [](double x, double y, double z) { Point3D p(x, y, z); double d1 = sphere(p, 1.0); double d2 = box(p, Point3D(0.8, 0.8, 0.8)); return op_smooth_intersection(d1, d2, 0.2); }; // smooth difference auto smooth_diff_shape = [](double x, double y, double z) { Point3D p(x, y, z); double d1 = box(p, Point3D(1.5, 1.5, 1.5)); double d2 = sphere(p, 0.8); return op_smooth_difference(d1, d2, 0.2); }; ``` ## 域变形(重复、镜像、扭转) 域变形算子对采样点做空间变换,再传入 SDF 函数求值: ```cpp #include using namespace vde::sdf; // 无限重复:将空间单元化,在每个单元内放置几何体 auto repeated_shape = [](double x, double y, double z) { Point3D p(x, y, z); // 以 (2, 2, 2) 为周期重复 Point3D q = op_repeat(p, Point3D(2.0, 2.0, 2.0)); return sphere(q, 0.5); }; // 镜像:沿 YZ 平面对称(x 方向镜像,offset 为对称轴位置) auto mirrored_shape = [](double x, double y, double z) { Point3D p(x, y, z); Point3D q = op_mirror_x(p, 0.0); // 以 x=0 为镜像轴 return sphere(q - Point3D(1.5, 0, 0), 0.6); }; // 多维镜像组合 auto quad_mirror = [](double x, double y, double z) { Point3D p(x, y, z); Point3D q = op_mirror_x(op_mirror_y(p)); return sphere(q - Point3D(2.0, 2.0, 0), 0.5); }; // 平移 / 旋转 / 缩放 auto transformed_shape = [](double x, double y, double z) { Point3D p(x, y, z); // sdf_operations.h 提供 op_translate, op_rotate, op_scale 等 // 注意:是逆变换——要移动几何体,需反向移动采样点 Point3D q = op_translate(p, Point3D(2.0, 0, 0)); // 几何体向右移 2 return sphere(q, 1.0); }; // 扭转(沿 Y 轴) #include auto twisted_shape = [](double x, double y, double z) -> double { double angle = y * 0.5; // 扭转角度与 y 坐标成正比 double sx = std::sin(angle); double cx = std::cos(angle); double rx = cx * x - sx * z; double rz = sx * x + cx * z; Point3D q(rx, y, rz); return box(q, Point3D(0.8, 3.0, 0.3)); }; // 修饰算子:圆角、壳 auto decorated_shape = [](double x, double y, double z) { Point3D p(x, y, z); double d = box(p, Point3D(1.0, 1.0, 1.0)); // op_round: 对所有边做圆角(近似 round_box) d = op_round(d, 0.1); // op_onion: 创建壳层(空心厚度) // d = op_onion(d, 0.05); return d; }; ``` ## 从 SDF 到网格(Marching Cubes) ```cpp #include #include #include #include #include using namespace vde::core; using namespace vde::sdf; using namespace vde::mesh; using namespace vde::foundation; int main() { // 定义 SDF 函数 auto shape = [](double x, double y, double z) -> double { Point3D p(x, y, z); double d = box(p, Point3D(2.0, 2.0, 2.0)); d = op_round(d, 0.15); // 圆角 return d; }; // 采样区域:[-3,3]³ Point3D bmin(-3, -3, -3), bmax(3, 3, 3); // Marching Cubes:64³ 分辨率 auto mc = marching_cubes(shape, 0.0, bmin, bmax, 64); // 构建半边网格并导出 HalfedgeMesh mesh; mesh.build_from_triangles(mc.vertices, mc.triangles); GltfOptions opts; opts.binary = true; opts.include_normals = true; write_gltf("rounded_box.glb", mesh, opts); std::cout << "Vertices: " << mesh.num_vertices() << ", Faces: " << mesh.num_faces() << "\n"; return 0; } ``` **分辨率选择指南:** | 分辨率 | 适用场景 | 输出网格规模 | |--------|----------|-------------| | 32³ | 快速预览 | ~2K 顶点 | | 64³ | 一般用途 | ~8K 顶点 | | 128³ | 精细表面 | ~30K 顶点 | | 256³ | 高精度需求 | ~100K+ 顶点 | ## 完整示例:齿轮形状 ```cpp #include #include #include #include #include #include #include using namespace vde::core; using namespace vde::sdf; using namespace vde::mesh; using namespace vde::foundation; int main() { const double M_PI = 3.14159265358979323846; const double gear_radius = 2.0; // 齿轮半径 const double tooth_count = 12.0; // 齿数 const double tooth_depth = 0.3; // 齿深 const double gear_thickness = 0.5; // 齿轮厚度 auto gear_sdf = [&](double x, double y, double z) -> double { Point3D p(x, y, z); // 圆柱主体(沿 Y 轴的薄圆盘) double d_cylinder = cylinder(Point3D(x, y, z), gear_radius, gear_thickness); // 中心孔 double d_hole = cylinder(Point3D(x, y, z), 0.4, gear_thickness * 2); // 差集:打孔 double d = op_difference(d_cylinder, d_hole); // 齿轮齿:沿圆周等距分布 double angle = std::atan2(z, x); double radius = std::sqrt(x * x + z * z); // 每个齿是一个小 Box 沿径向放置 double teeth_union = 1e10; for (int i = 0; i < tooth_count; i++) { double theta = i * 2.0 * M_PI / tooth_count; double ca = std::cos(theta); double sa = std::sin(theta); // 旋转采样点到该齿的局部空间 double lx = ca * x + sa * z; double lz = -sa * x + ca * z; Point3D lp(lx, y, lz); double tooth = box(lp, Point3D(0.3, 0.6, gear_radius + tooth_depth)); // 向圆心方向偏移 double d_tooth = op_translate_along_x(lp, gear_radius + tooth_depth * 0.5).norm() > 0 ? box(Point3D(lx - (gear_radius + tooth_depth * 0.5), y, lz), Point3D(0.15, gear_thickness * 1.1, tooth_depth * 0.5)) : 1e10; // 用旋转矩阵的逆变换做齿的径向放置 double r = std::sqrt(x * x + z * z); double dx = r - (gear_radius + tooth_depth * 0.5); double dy_abs = std::abs(y); double dz = std::abs(std::atan2(z, x) - theta); if (dz > M_PI) dz = 2 * M_PI - dz; dz = dz * gear_radius; double tooth_dist = std::sqrt(dx * dx + dy_abs * dy_abs + dz * dz) - tooth_depth * 0.5; if (dy_abs <= gear_thickness * 0.55 && r >= gear_radius - 0.05) { teeth_union = std::min(teeth_union, tooth_dist); } } d = op_union(d, teeth_union); return d; }; // Marching Cubes Point3D bmin(-3, -3, -3), bmax(3, 3, 3); auto mc = marching_cubes(gear_sdf, 0.0, bmin, bmax, 128); HalfedgeMesh mesh; mesh.build_from_triangles(mc.vertices, mc.triangles); GltfOptions opts; opts.binary = true; opts.include_normals = true; write_gltf("gear.glb", mesh, opts); std::cout << "Gear exported: " << mesh.num_vertices() << " vertices, " << mesh.num_faces() << " faces\n"; return 0; } ``` 编译运行,用 `viewer/index.html` 查看效果。