feat(sdf): S12 — 可微分几何完整模块
CI / Build & Test (push) Failing after 39s
CI / Release Build (push) Failing after 32s

S12-A: 自动微分引擎
- sdf_gradient.h: 前向/反向梯度、解析梯度(sphere/box/torus/cylinder/plane/capsule)
- 链式法则: union/intersection/difference/smooth + translate/rotate/scale/twist/repeat
- 参数梯度: sphere/box/cylinder 的 param_grad
- test_sdf_gradient.cpp: 604 行测试

S12-B: 梯度驱动优化 + 应用
- sdf_optimize.h: 形状拟合/碰撞避免/可达性/对称检测/体积计算
- sdf_optimize.cpp: 682 行实现(数值梯度 + GradientDescent)
- test_sdf_optimize.cpp: 342 行,20 项测试

S12-C: PyTorch 集成 + Python
- sdf_torch.h/cpp: 批量 SDF 求值 + 梯度
- python/vde/sdf.py: 高级 Python API
- python/vde/torch_sdf.py: torch.autograd.Function
- test_sdf_torch_bridge.cpp: C++ 桥梁测试
This commit is contained in:
茂之钳
2026-07-24 07:23:28 +00:00
parent 08b5854c56
commit b175db0342
7 changed files with 2152 additions and 23 deletions
+178
View File
@@ -0,0 +1,178 @@
#pragma once
#include "vde/sdf/sdf_tree.h"
#include "vde/core/point.h"
#include <vector>
#include <functional>
namespace vde::sdf {
using core::Point3D;
using core::Vector3D;
// ────────────────────────────────────────────────
// Shape Optimization
// ────────────────────────────────────────────────
/// Optimization result
struct OptimizeResult {
SdfNodePtr optimized_shape;
double final_loss;
int iterations;
bool converged;
std::vector<double> loss_history;
};
/// Loss function type: takes SDF evaluator + target, returns scalar loss
using LossFn = std::function<double(const std::function<double(const Point3D&)>&)>;
// ── Shape Fitting ───────────────────────────────
/// Fit a parameterized shape to a target point cloud by minimizing
/// distance of surface to target points.
/// @param initial Initial shape (sphere, box, cylinder, etc.)
/// @param target_points Target point cloud (surface samples)
/// @param learning_rate Gradient descent step size
/// @param max_iterations Maximum iterations
/// @return Optimized shape + convergence info
[[nodiscard]] OptimizeResult fit_to_point_cloud(
const SdfNodePtr& initial,
const std::vector<Point3D>& target_points,
double learning_rate = 0.01,
int max_iterations = 100);
/// Fit a shape to minimize SDF values at target points (drive surface to points)
/// Loss = mean(|sdf(p_i)|) for p_i in targets
[[nodiscard]] OptimizeResult fit_surface_to_points(
const SdfNodePtr& initial,
const std::vector<Point3D>& surface_points,
double learning_rate = 0.01,
int max_iterations = 100);
/// Fit a shape to match another SDF (shape matching)
/// Loss = mean((sdf_a(p_i) - sdf_b(p_i))^2) over sample grid
[[nodiscard]] OptimizeResult fit_to_sdf(
const SdfNodePtr& source,
const std::function<double(const Point3D&)>& target_sdf,
const Point3D& bmin, const Point3D& bmax,
int grid_resolution = 16,
double learning_rate = 0.01,
int max_iterations = 100);
// ── Collision Avoidance ─────────────────────────
/// Push shapes apart to resolve interpenetration.
/// Modifies shapes in-place by translating them.
/// @param shape_a First shape
/// @param shape_b Second shape
/// @param step_size Translation step per iteration
/// @param max_iterations Max iterations
/// @return True if collision resolved
[[nodiscard]] bool resolve_collision(
SdfNodePtr& shape_a, SdfNodePtr& shape_b,
double step_size = 0.1,
int max_iterations = 50);
/// Find minimum translation distance to avoid collision
[[nodiscard]] double penetration_depth(
const SdfNodePtr& shape_a,
const SdfNodePtr& shape_b,
const Point3D& bmin, const Point3D& bmax,
int samples = 1000);
// ── Reachability / Accessibility ─────────────────
/// Compute accessibility score at point p on surface of shape.
/// Returns 0 (inaccessible) to 1 (fully accessible).
/// Uses hemisphere sampling + occlusion testing.
[[nodiscard]] double accessibility(
const SdfNodePtr& shape,
const Point3D& p, // surface point
const Vector3D& direction, // approach direction
int hemisphere_samples = 64);
/// Find point with maximum accessibility
[[nodiscard]] Point3D find_accessible_point(
const SdfNodePtr& shape,
const Vector3D& approach_dir,
const Point3D& bmin, const Point3D& bmax,
int grid_res = 32);
// ── Symmetry Detection ──────────────────────────
/// Detect if shape has reflective symmetry in given direction.
/// Returns symmetry score: 0 = asymmetric, 1 = perfectly symmetric.
[[nodiscard]] double symmetry_score(
const SdfNodePtr& shape,
const Point3D& bmin, const Point3D& bmax,
const Vector3D& plane_normal,
double plane_offset = 0.0,
int samples = 1000);
/// Find the best symmetry plane
struct SymmetryResult {
double score;
Vector3D normal;
double offset;
};
[[nodiscard]] SymmetryResult find_symmetry_plane(
const SdfNodePtr& shape,
const Point3D& bmin, const Point3D& bmax,
int samples = 1000);
// ── SDF Volume Computation ──────────────────────
/// Approximate volume of implicit shape via Monte Carlo sampling
[[nodiscard]] double estimate_volume(
const SdfNodePtr& shape,
const Point3D& bmin, const Point3D& bmax,
int samples = 10000);
/// Compute center of mass via Monte Carlo
[[nodiscard]] Point3D center_of_mass(
const SdfNodePtr& shape,
const Point3D& bmin, const Point3D& bmax,
int samples = 10000);
// ── Parameter Collection ────────────────────────
/// A reference to a mutable double parameter inside an SDF tree
struct ParamRef {
double* value;
std::string name;
};
/// Collect all mutable numeric parameters from primitive leaf nodes
[[nodiscard]] std::vector<ParamRef> collect_params(SdfNodePtr& root);
/// Compute numerical gradient of a scalar loss w.r.t. collected parameters
[[nodiscard]] std::vector<double> numerical_gradient(
const std::vector<ParamRef>& params,
const std::function<double()>& loss_fn,
double eps = 1e-6);
// ── Gradient Descent Utility ────────────────────
/// Simple gradient descent with fixed learning rate
class GradientDescent {
public:
explicit GradientDescent(double lr) : lr_(lr) {}
/// Step parameters toward minimizing loss.
/// @param params Parameter vector (mutable)
/// @param grad_fn Function that computes gradient for given params;
/// returns loss as scalar and fills gradient vector.
/// @return Current loss
double step(std::vector<double>& params,
const std::function<double(const std::vector<double>&,
std::vector<double>&)>& grad_fn);
void set_learning_rate(double lr) { lr_ = lr; }
[[nodiscard]] double learning_rate() const { return lr_; }
[[nodiscard]] int iteration() const { return iteration_; }
private:
double lr_;
int iteration_ = 0;
};
} // namespace vde::sdf