是否有 library/code snipped 可以将网格转换为向量表示形式的 sdf 以实现亚体素精确表示?

Is there a library/code snipped which which can convert meshes to a sdf in vector representation for subvoxel exact representation?

我需要从 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; //
        }
    }
}

看来你对自卫队到底是什么有点误解。那么让我从这个开始吧。

有符号距离函数是一个二维函数 space,它为您提供相应点到网格上最近点的距离。该距离对于网格外部的点为正,对于内部的点为负(反之亦然)。自然地,直接在网格上的点将具有零距离。我们可以将这个函数正式表示为:

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 的近似值。它计算网格最近的 vertex 而不是最近的 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++;
}

同样,我不知道这应该做什么。别管它了。