10 KiB
10 KiB
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:
#include <vde/sdf/sdf_primitives.h>
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:
#include <vde/sdf/sdf_primitives.h>
#include <vde/sdf/sdf_operations.h>
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 函数求值:
#include <vde/sdf/sdf_operations.h>
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 <cmath>
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)
#include <vde/sdf/sdf_primitives.h>
#include <vde/sdf/sdf_operations.h>
#include <vde/mesh/marching_cubes.h>
#include <vde/mesh/halfedge_mesh.h>
#include <vde/foundation/io_gltf.h>
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+ 顶点 |
完整示例:齿轮形状
#include <vde/sdf/sdf_primitives.h>
#include <vde/sdf/sdf_operations.h>
#include <vde/mesh/marching_cubes.h>
#include <vde/mesh/halfedge_mesh.h>
#include <vde/foundation/io_gltf.h>
#include <iostream>
#include <cmath>
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 查看效果。