【问题标题】:c++: Find the closest point on a mesh to a query pointc ++:在网格上找到离查询点最近的点
【发布时间】:2015-08-27 14:53:08
【问题描述】:

这是我需要的: 给定 3d 空间中的一个点 (x,y,z),以及由一些顶点 (x,y,z) 组成的网格,计算并返回该网格上的近点坐标。 函数大概是这样的:

bool closePointOnMesh(const Point& queryPoint, const Mesh& myMesh, float maxDistance);

我做了一些搜索,可能我会选择八叉树来减少计算。

但是还是有很多细节看不懂:

1:八叉树节点是如何细分的,所以每个节点包含的可能包含0~一些三角形?根据顶点进一步细分单元格并直接存储顶点更容易。

2:八叉树结构如何帮助减少计算,我知道如果单元格为空我将忽略它。但是我是否需要将八叉树单元格中每个三角形面内的所有最近点都获取到查询点,所以我最终得到了最接近的点?那声音依旧沉重。除此之外,如果我只是遍历所有三角形,从它们那里得到最近的点会更容易,这意味着不需要八叉树???

3:有没有一种快速的方法来获得最接近三角形面内点的点?

4:maxDistance 限制如何帮助减少计算?

【问题讨论】:

  • 我认为使用二进制 BVH 会更容易,尤其是使用球形边界体积。遍历时总是先访问最近的球体,当你计算出你的第一个距离时,这个距离后面的所有球体都可以忽略。
  • 感谢您的建议 :) 仍然想知道八叉树如何在这种情况下提供帮助,我的意思是最近点搜索。
  • @user1887450 如果你想使用八叉树或BVH找到closet点,你应该沿着树找到你的点所在的叶子节点。然后找到叶子中面的closet点节点和邻居叶节点,并选择最近的一个。在某些情况下,叶子节点和它的邻居都是空的,那么你必须检查邻居的邻居,这并不有趣。
  • 所以我仍然根据网格顶点划分八叉树,当我搜索三角形面上最近的点时,我该怎么做,因为它只是顶点?对于这种情况,您认为哪种算法最有效?请,任何提示或链接甚至源示例将不胜感激。

标签: c++ opengl


【解决方案1】:

对于#3,这里有一些关于如何获取closest point of a triangle 的代码。它将点投影到三角形的平面上,然后将重心坐标钳制为 [0,1],并使用这些值计算最近的点。

复制如下:

vector3 closesPointOnTriangle( const vector3 *triangle, const vector3 &sourcePosition )
{
vector3 edge0 = triangle[1] - triangle[0];
vector3 edge1 = triangle[2] - triangle[0];
vector3 v0 = triangle[0] - sourcePosition;

float a = edge0.dot( edge0 );
float b = edge0.dot( edge1 );
float c = edge1.dot( edge1 );
float d = edge0.dot( v0 );
float e = edge1.dot( v0 );

float det = a*c - b*b;
float s = b*e - c*d;
float t = b*d - a*e;

if ( s + t < det )
{
    if ( s < 0.f )
    {
        if ( t < 0.f )
        {
            if ( d < 0.f )
            {
                s = clamp( -d/a, 0.f, 1.f );
                t = 0.f;
            }
            else
            {
                s = 0.f;
                t = clamp( -e/c, 0.f, 1.f );
            }
        }
        else
        {
            s = 0.f;
            t = clamp( -e/c, 0.f, 1.f );
        }
    }
    else if ( t < 0.f )
    {
        s = clamp( -d/a, 0.f, 1.f );
        t = 0.f;
    }
    else
    {
        float invDet = 1.f / det;
        s *= invDet;
        t *= invDet;
    }
}
else
{
    if ( s < 0.f )
    {
        float tmp0 = b+d;
        float tmp1 = c+e;
        if ( tmp1 > tmp0 )
        {
            float numer = tmp1 - tmp0;
            float denom = a-2*b+c;
            s = clamp( numer/denom, 0.f, 1.f );
            t = 1-s;
        }
        else
        {
            t = clamp( -e/c, 0.f, 1.f );
            s = 0.f;
        }
    }
    else if ( t < 0.f )
    {
        if ( a+d > b+e )
        {
            float numer = c+e-b-d;
            float denom = a-2*b+c;
            s = clamp( numer/denom, 0.f, 1.f );
            t = 1-s;
        }
        else
        {
            s = clamp( -e/c, 0.f, 1.f );
            t = 0.f;
        }
    }
    else
    {
        float numer = c+e-b-d;
        float denom = a-2*b+c;
        s = clamp( numer/denom, 0.f, 1.f );
        t = 1.f - s;
    }
}

return triangle[0] + s * edge0 + t * edge1;
}

【讨论】:

  • 我的问题是这是否真的比仅计算 3 个向量的长度并使用比较更好?
  • 另外为了避免sqrt 的性能下降(不是那么多),我们可以比较length2而不是length。
  • 取决于 OP 是否想要最近的顶点(在这种情况下,只检查每个点是有意义的),还是网格上最近的点(这是他们在他的问题中所说的)......跨度>
  • 是的!你说的对!我在想他正在寻找最接近网格上某个点的点。
  • 谢谢大家。是的,我想要网格上的点,而不是顶点。但是请有人帮忙注释掉上面的代码,我会在pdf文档和代码中挖掘,但仍然不知道这是如何工作的......非常感谢。
猜你喜欢
  • 1970-01-01
  • 2012-11-14
  • 1970-01-01
  • 1970-01-01
  • 2018-06-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-28
相关资源
最近更新 更多