b175db0342
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++ 桥梁测试
179 lines
6.3 KiB
C++
179 lines
6.3 KiB
C++
#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
|