查找网格上离查询点最近的点

c++: Find the closest point on a mesh to a query point

本文关键字:最近 查询 网格 查找      更新时间:2023-10-16

我需要的是:给定三维空间中的一个点(x,y,z)和一个由一些顶点(x,y,z)组成的网格,计算并返回该网格上的闭合点坐标。函数可能像这样:

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

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

但仍有许多细节我不明白:

1:如何对八叉树节点进行细分,使每个节点可能包含0~一些三角形?基于顶点进一步细分单元格并直接存储顶点更容易。

2:八叉树结构如何帮助减少计算,我知道如果单元格是空的,我就忽略它。但是,我是否需要在一个八叉树单元格中的每个三角形面中获得所有离queryPoint最近的点,以便最终获得所有点中最接近的点?听起来还是很重。此外,如果我只是遍历所有的三角形,得到离它们最近的点,这将更容易,这意味着不需要八叉树??

3:有没有一种快速的方法可以让一个点在三角形的表面上离一个点最近?

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

对于#3,这里有一些关于如何获得三角形最近点的代码。它将点投影到三角形的平面上,然后将质心坐标固定为[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;
}