【问题标题】:How to traverse mesh vertices based on their location?如何根据位置遍历网格顶点?
【发布时间】:2018-11-22 22:38:32
【问题描述】:

我正在使用Point Cloud Free Viewer 在 Unity 中可视化点云。它有一个脚本,它解析 .off 文件并创建网格而不需要三角剖分。但是,该代码创建了多个网格,因为它的索引格式是 16 位。我修改了使用 32 位格式的代码,我有一个包含 200 万个点的网格:

我想要做的是创建一个像几何图形一样的网格,并根据点密度为这个点云着色。我想通过乘以最大和最小 x、y、z 值之间的差异来找到这个点云的粗略体积,并将这个体积分成相等的盒子。这些框中的每一个都将根据它们包含的点数进行着色。如果有人能给我提供线索,我会很高兴。我尝试了 KDTree 方法,但它有点慢,因为我有 200 万个点。我还尝试在创建网格之前对点进行排序,但这也需要太多时间。考虑到它们是随机索引的,有没有办法根据位置遍历网格顶点而不访问所有顶点?我相信我正在寻找像mesh.bounds.contains() 这样的解决方案,但我不知道是否存在像空间搜索这样的方法。

【问题讨论】:

  • 反其道而行之。不要循环遍历这些框并询问框中有哪些点,而是遍历这些点并增加相应框的计数器。

标签: c# unity3d mesh traversal point-clouds


【解决方案1】:

不是真的,一个完整的解决方案,更多的是对我追求的方向的提示:首先将您的顶点池分成较小的组,即分成立方体(可能是单独的网格),预先计算,然后您只需在一个很大的范围内搜索较小的区域,在初始搜索一组与您的区域相邻(或接触)的立方体之后。

【讨论】:

  • 感谢您的提示。我的问题是顶点是从文件中解析出来的,随后的顶点不一定彼此相邻,甚至在现实世界几何中有时甚至很接近。
【解决方案2】:

听起来你想要octree

首先,将所有点加载到内存中(200 万点确实不算多 - 假设双倍,即 2,000,000 * 3 * 8 字节 ~= 45 MB)。在解析文件并将点加载到内存中时,记录最小和最大 x、y 和 z 坐标。然后,您可以构建以 N*LogN 为边界的八叉树。然后,对于每个网格体,您可以非常快速地查询树以仅获取该区域中的点。我很确定这是做你想做的最有效的方法。

我建议查看quadtree 文章以了解其对queryRange 的实现,以了解如何完成。八叉树只是四叉树的 3-d 实现,因此底层代码或多或少是相同的(每个节点包含 8 个子节点而不是 4 个)。

【讨论】:

  • 谢谢你我做了更多的研究,一切都导致了八叉树。我会深入研究并编辑我的问题。
【解决方案3】:

对于以后可能会访问此问题的人,我根据 Nico 的评论找到了一个非常快速的解决方案。我通过使用此脚本解析我的扫描文件来遍历所有点

 for (int i = 0; i < numPoints; i++)
    {
        buffer = sr.ReadLine().Split();

        points[i] = new Vector3(float.Parse(buffer[0]) , float.Parse(buffer[1]) , -float.Parse(buffer[2]) );

        //Finding minX, minY, minZ
        if (points[i].x < minX)
            minX = points[i].x;
        if (points[i].y < minY)
            minY = points[i].y;
        if (points[i].z < minZ)
            minZ = points[i].z;
        //Finding maxX, maxY, maxZ
        if (points[i].x > maxX)
            maxX = points[i].x;
        if (points[i].y > maxY)
            maxY = points[i].y;
        if (points[i].z > maxZ)
            maxZ = points[i].z;

    }

这是我和它一起使用的变量FindPointIndex 函数。

    deltaX = maxX - minX;
    deltaY = maxY - minY;
    deltaZ = maxZ - minZ;
    gridCountX = Mathf.CeilToInt(deltaX / gridSize);
    gridCountY = Mathf.CeilToInt(deltaY / gridSize);
    gridCountZ = Mathf.CeilToInt(deltaZ / gridSize);
    Resolution = gridCountX * gridCountY * gridCountZ;
    Histogram = new int[Resolution];

 int FindPointIndex(Vector3 point)
{
    //Finds the grid index of the point 
    int index = Mathf.FloorToInt((point.x - minX) / gridSize) + ((Mathf.FloorToInt((point.z - minZ) / gridSize)) * gridCountX)
           + Mathf.FloorToInt((point.y - minY) / gridSize) * gridCountX * gridCountZ;
    if (index < 0)
    {
        index = 0;
    }
    return index;
}

然后我可以再次遍历这些点以增加每个点的索引,以查看每个网格拥有多少点,如下所示:

 for (int i = 0; i < numPoints; i++)
    {
        Histogram[FindPointIndex(points[i])]++;                                      
    }

最后使用这个直方图,我可以用另一个循环为点云着色。

【讨论】: