c++ - 是否有一个库/代码被剪断,它可以将网格转换为向量表示中的 sdf 以实现亚体素精确表示?
问题描述
我需要从二维网格在网格上生成一个 sdf,以将网格表示为煤渣中的封闭体。
我的第一种方法是使用距离函数(欧几里得)来检查网格点是否接近网格点,然后将值设置为 - 或 +,但这会导致分辨率不佳。接下来,我尝试将距离相加以获得连续的距离场。这导致了一个被炸毁的物体。我不确定如何表示到由网格(凹面或凸面)描述的封闭对象的距离。我目前的方法在下面的代码中描述。
#include <iostream>
#include <fstream>
#include <string>
#include <Eigen/Dense>
#include <vector>
#include <algorithm>
#include <random>
using namespace std;
using namespace Eigen;
typedef Eigen::Matrix<double, 2, 1> Vector2;
typedef Eigen::Matrix<double, 3, 2> Vector32;
typedef std::vector<Vector2, Eigen::aligned_allocator<Vector2> > Vector2List;
typedef std::vector<Eigen::Vector3i, Eigen::aligned_allocator<Eigen::Vector3i> > Vector3iList;
typedef std::vector<Vector32> Vector32List;
typedef Eigen::Array<double, Eigen::Dynamic, Eigen::Dynamic> grid_t;
void f( Vector2List vertices, Vector3iList triangles)
{ // each entry of triangles describe which vertice point belongs
// to a triangle of the mesh
grid_t sdf = grid_t::Zero(resolution, resolution);
for (int x = 0; x < resolution; ++x) {
for (int y = 0; y < resolution; ++y) {
Vector2d pos((x + 0.5) / resolution, (y + 0.5) / resolution);
double dist = 1 / double(resolution*resolution);
double check = 100;
double val = 0;
for (std::vector<Vector2>::iterator mean = vertices.begin(); mean != vertices.end(); ++mean) {
//try sdf with euclidian distance function
check = (pos - *mean).squaredNorm();
if (check < dist) {
val = -1; break;
}
else {
val = 20;
}
}
val *= resolution;
static const double epsilon = 0.01;
if (abs(val) < epsilon) {
val = 0;
numberOfClamped++;
}
sdf(x, y) = val; //
}
}
}
解决方案
似乎您对 SDF 的实际含义略有误解。所以让我从这个开始。
有符号距离函数是二维空间上的函数,它为您提供各个点到网格上最近点的距离。距离对于网格外部的点为正,对于内部的点(或相反)为负。自然,直接在网格上的点将具有零距离。我们可以将这个函数正式表示为:
sdf(x, y) = distance
这是一个连续函数,我们需要一个可以使用的离散表示。一个常见的选择是使用一个统一的网格,就像您要使用的网格一样。然后我们在网格点对 SDF 进行采样。一旦我们获得了所有网格点的距离值,我们就可以在它们之间插入 SDF 以在任何地方获得 SDF。请注意,每个样本对应于一个点而不是一个区域(例如,一个单元格)。
考虑到这一点,让我们看一下您的代码:
Vector2d pos((x + 0.5) / resolution, (y + 0.5) / resolution);
这取决于网格点索引如何映射到全局坐标。这可能是正确的。但是,它看起来好像假设样本位置位于各个单元格的中间。同样,这可能是正确的,但我认为+ 0.5
应该不考虑。
for (std::vector<Vector2>::iterator mean = vertices.begin(); mean != vertices.end(); ++mean)
这是 SDF 的近似值。它计算网格的最近顶点,而不是最近点(可能位于边上)。对于密集的网格,这应该没问题。如果您有粗网格,您应该迭代边缘并计算这些边缘上的最近点。
if (check < dist) {
val = -1; break;
} else {
val = 20;
}
我真的不知道这是什么。如上所述,SDF 的值是有符号距离。不是任意值。此外,该符号不应与网格是否靠近网格位置相对应。所以,你应该做的是:
if(check < val * val) {
//this point is closer than the current closest point
val = std::sqrt(check); //set to absolute distance
if(*mean is inside the mesh)
val *= -1; //invert the sign
}
最后,这件作品:
val *= resolution;
static const double epsilon = 0.01;
if (abs(val) < epsilon) {
val = 0;
numberOfClamped++;
}
再说一次,我不知道这应该做什么。把它放在一边。
推荐阅读
- python - 在熊猫中将宽转换为长
- pandas - 带有 python3.8 的 Anaconda 2020.07 缺乏对 blosc 中“snappy”压缩器的支持?
- php - Laravel 7 自定义身份验证不起作用
- amazon-web-services - 使用 auth0、AWS 和服务器的网站架构
- javascript - 'node modules' 不是内部或外部命令、可运行程序或批处理文件
- terraform - dashboard_body 内的模板文件
- webpack - webpack sideEffects list 在服务器上不起作用,但在我的本地机器上没问题
- reactjs - 如何将 React 应用部署到个人页面的 Github 页面
- python - 无法解压不可迭代的 CustomerPurchaseOrderDetail 对象
- wso2 - 如何启动仪表板微积分器 wso2 ei 7.0