You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
111 lines
5.1 KiB
111 lines
5.1 KiB
// sdf_visualizer.cpp
|
|
// ──────────────────────────────────────────────────────────────────────────────
|
|
// 依赖:
|
|
// prim_gen.hpp → baked_blobtree_t、aabb_t、primitive_t …
|
|
// base/subface.hpp → internal::get_eval_sdf_ptr、surface_type
|
|
//
|
|
// 文件格式(output_path):
|
|
// 行 0 : grid_res y_slice
|
|
// 行 1 : x0 x1 z0 z1 (世界坐标范围)
|
|
// 行 2 : num_subfaces
|
|
// 然后对每个 subface 重复:
|
|
// 行 : surface_type_int
|
|
// N 行 : N 个空格分隔的 float(iz 行,ix 列,N = grid_res+1)
|
|
// ──────────────────────────────────────────────────────────────────────────────
|
|
|
|
#include "sdf_visualizer.hpp"
|
|
#include <base/subface.hpp> // internal::get_eval_sdf_ptr, surface_type
|
|
|
|
#include <Eigen/Dense>
|
|
#include <fstream>
|
|
#include <functional>
|
|
#include <iostream>
|
|
#include <limits>
|
|
#include <vector>
|
|
|
|
void dump_sdf_slice(const baked_blobtree_t& tree,
|
|
const std::string& output_path,
|
|
double y_slice,
|
|
int grid_res,
|
|
double extra_margin)
|
|
{
|
|
// ── 0. 基本校验 ────────────────────────────────────────────────────────
|
|
if (tree.subfaces.empty()) {
|
|
std::cerr << "[SDF_VIZ] No subfaces — nothing to dump.\n";
|
|
return;
|
|
}
|
|
|
|
// ── 1. 计算场景 AABB(含边距)──────────────────────────────────────────
|
|
aabb_t scene_aabb{};
|
|
for (const auto& prim : tree.primitives) { scene_aabb.extend(prim->fetch_aabb()); }
|
|
if (scene_aabb.isEmpty()) {
|
|
std::cerr << "[SDF_VIZ] Scene AABB is invalid.\n";
|
|
return;
|
|
}
|
|
const double base_margin = scene_aabb.sizes().maxCoeff() * extra_margin + 0.05;
|
|
scene_aabb.min().array() -= base_margin;
|
|
scene_aabb.max().array() += base_margin;
|
|
|
|
const double x0 = scene_aabb.min().x(), x1 = scene_aabb.max().x();
|
|
const double z0 = scene_aabb.min().z(), z1 = scene_aabb.max().z();
|
|
const int N = grid_res + 1; // 每轴采样点数
|
|
|
|
const uint32_t ns = static_cast<uint32_t>(tree.subfaces.size());
|
|
std::cout << "[SDF_VIZ] Grid " << N << "×" << N << " | " << ns << " subface(s)"
|
|
<< " | Y=" << y_slice << " | X[" << x0 << ", " << x1 << "]"
|
|
<< " | Z[" << z0 << ", " << z1 << "]\n";
|
|
|
|
// ── 2. 对每个 subface 在网格上采样 SDF ────────────────────────────────
|
|
// grids[s][iz * N + ix] = SDF 值(float 节省内存)
|
|
std::vector<std::vector<float>> grids(ns, std::vector<float>(N * N, 0.0f));
|
|
|
|
for (uint32_t s = 0; s < ns; ++s) {
|
|
// 不再调用 .raw() 获取原始指针,而是直接使用包装器对象
|
|
const auto& subface_wrapper = tree.subfaces[s]; // 使用引用,避免拷贝
|
|
surface_type subface_type = tree.subface_types[s];
|
|
|
|
auto sdf_fn = internal::get_eval_sdf_ptr(subface_type);
|
|
if (!sdf_fn) {
|
|
std::cout << "[SDF_VIZ] subface[" << s << "] type=" << static_cast<int>(subface_type)
|
|
<< " → null eval_sdf, skipped.\n";
|
|
continue;
|
|
}
|
|
|
|
for (int iz = 0; iz < N; ++iz) {
|
|
const double z = z0 + (z1 - z0) * static_cast<double>(iz) / grid_res;
|
|
for (int ix = 0; ix < N; ++ix) {
|
|
const double x = x0 + (x1 - x0) * static_cast<double>(ix) / grid_res;
|
|
const Eigen::Vector3d pos(x, y_slice, z);
|
|
// 传递包装器对象,而不是原始指针
|
|
grids[s][iz * N + ix] = static_cast<float>(sdf_fn(subface_wrapper, pos));
|
|
}
|
|
}
|
|
std::cout << "[SDF_VIZ] subface[" << s << "] type=" << static_cast<int>(subface_type) << " ✓\n";
|
|
}
|
|
|
|
// ── 3. 写文件 ──────────────────────────────────────────────────────────
|
|
std::ofstream ofs(output_path);
|
|
if (!ofs) {
|
|
std::cerr << "[SDF_VIZ] Cannot open: " << output_path << "\n";
|
|
return;
|
|
}
|
|
|
|
// 文件头
|
|
ofs << grid_res << ' ' << y_slice << '\n';
|
|
ofs << x0 << ' ' << x1 << ' ' << z0 << ' ' << z1 << '\n';
|
|
ofs << ns << '\n';
|
|
|
|
// 每个 subface 的数据块
|
|
for (uint32_t s = 0; s < ns; ++s) {
|
|
ofs << static_cast<int>(tree.subface_types[s]) << '\n';
|
|
for (int iz = 0; iz < N; ++iz) {
|
|
for (int ix = 0; ix < N; ++ix) {
|
|
if (ix) ofs << ' ';
|
|
ofs << grids[s][iz * N + ix];
|
|
}
|
|
ofs << '\n';
|
|
}
|
|
}
|
|
|
|
std::cout << "[SDF_VIZ] Written → " << output_path << '\n';
|
|
}
|