是否存在可用于将网格转换为矢量表示形式的网格/代码的库/代码,以实现亚体素的精确表示?

时间:2019-05-31 12:30:47

标签: c++ graphics eigen

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

1 个答案:

答案 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++;
}

同样,我不知道该怎么办。随便丢掉。