我需要从2D网格在网格上生成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; //
}
}
}
答案 0 :(得分:0)
似乎您对SDF的实际含义有些误解。因此,让我从这个开始。
符号距离函数是2D空间上的函数,可为您提供各个点到网格上最近点的距离。距离对于网格外部的点为正,而对于内部(或相反)的点为负。自然,直接在网格上的点的距离为零。我们可以将该函数形式表示为:
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的近似值。它计算网格的最近的顶点而不是最近的 point (可能位于一条边上)。对于密集的网格,这应该很好。如果您具有粗网格,则应迭代边缘并计算出这些边缘上的最接近点。
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++;
}
同样,我不知道该怎么办。随便丢掉。