Files
ViewDesignEngine/include/vde/mesh/marching_cubes.h
T
茂之钳 4c9ee4f760
CI / Build & Test (push) Failing after 29s
CI / Release Build (push) Failing after 38s
docs: doxygen annotations for curves + mesh + sketch
2026-07-24 11:04:04 +00:00

124 lines
3.6 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#pragma once
#include "vde/core/point.h"
#include <vector>
#include <array>
#include <functional>
#include <cmath>
#include <algorithm>
namespace vde::mesh {
using core::Point2D;
using core::Point3D;
using core::Vector3D;
/**
* @brief Marching Cubes 输出网格
* @ingroup mesh
*/
struct MCMesh {
std::vector<Point3D> vertices; ///< 顶点坐标
std::vector<std::array<int, 3>> 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<double(double,double,double)>& 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