除了格雷迪网格丛中,还有其他/更好的体素网格划分算法吗

发布于 2025-02-01 13:58:19 字数 4679 浏览 3 评论 0原文

对于我正在工作的项目,我有大量的体素数据,需要在网格中可视化。

在搜索时,我迅速找到了在Minecraft游戏中/a>文章,由Mikolalysenko撰写,早在2012年,根据我的研究,每个人似乎都提到每个人都在回答这个问题。 他描述了解决这个问题的三种算法:愚蠢的,被淘汰和贪婪。

这两个首先是不高效的,所以我为我为我的项目提供的代码制作了Python版本:

  • 我使用 numba 为了加快计算,
  • 我直接计算三角顶点,而不是四边形,以获取我们的网格释放函数实现,
@njit()
def greedy_mesh(volume, dims):
    def f(i, j, k):
        return(volume[i + dims[0] * (j + dims[1] * k)])
    
    points = []
    # Sweep over 3-axes
    for d in range(3):
        u = (d + 1) % 3
        v = (d + 2) % 3
        x = [0, 0, 0]
        q = [0, 0, 0]
        mask = [0] * (dims[u] * dims[v])
        
        q[d] = 1
        
        x[d] = -1
        while x[d] < dims[d]:
            n = 0
            x[v] = 0
            x[u] = 0
            # Compute mask
            while x[v] < dims[v]:
                while x[u] < dims[u]:
                    a = f(x[0], x[1], x[2]) if x[d] >= 0 else False
                    b = f(x[0] + q[0], x[1] + q[1], x[2] + q[2]) if x[d] < (dims[d] - 1) else False
                                   
                    mask[n] = a != b 
                    n += 1
                    
                    x[u] += 1
                
                x[u] = 0
                x[v] += 1
            
            x[d] += 1
            
            n = 0
            # Generate mesh for mask using lexicographic ordering
            for j in range(0, dims[v]):
                i = 0
                while i < dims[u]:                        
                    if (n < len(mask)) and mask[n]:
                        w = 1
                        # Compute width
                        while (n + w < len(mask)) and (mask[n + w] and ((i + w) < dims[u])):
                            w += 1
                        
                        done = False
                        h = 1
                        # Compute height (slighty awkward according to the autor)
                        while (j + h) < dims[v]:
                            for k in range(0, w):
                                if not mask[n + k + h * dims[u]]:
                                    done = True
                                    break
                                    
                            if done:
                                break
                                
                            h += 1
                        
                        # New quad
                        x[u] = i;
                        x[v] = j;
                        du = [0, 0, 0]
                        dv = [0, 0, 0]
                        
                        du[u] = w
                        dv[v] = h
                        
                        # Triangles
                        A = (x[0],
                             x[1],
                             x[2])
                        B = (x[0] + du[0],
                             x[1] + du[1],
                             x[2] + du[2])
                        C = (x[0] + du[0] + dv[0],
                             x[1] + du[1] + dv[1],
                             x[2] + du[2] + dv[2])
                        D = (x[0] + dv[0],
                             x[1] + dv[1],
                             x[2] + dv[2])
                        
                        points.extend([A, B, C])
                        points.extend([A, C, D])
                        
                        # Zero-out mask
                        for l in range(0, h):
                            for k in range(0, w):
                                mask[n + k + l * dims[u]] = False
                        
                        i += w
                        n += w
                        
                    else:
                        i += 1
                        n += 1

    # Unique set of points
    vertices = [i for i in set(points)]
    
    # Points 
    indices = []
    for p in points:
        indices.append(vertices.index(p))
    
    return np.array(vertices), np.array(indices).reshape(-1, 3)

我使用示例测试了我的代码,Mikolalysenko再次提供了我的代码,并且运行良好。 但是后来我尝试从我们的项目(〜300x300x300)中加载更大的体素数据,现在该算法运行约5s来处理数据。老实说,我很快,但不足以使用,并且我们的数据集更大。

经过一点点的概况,并且没有任何惊喜,大多数计算时间都是由于最终创建了顶点及其索引。不幸的是,这是创建与之使用的Meshing函数的方式,我无法更改此功能。

终于使我的问题引起了我的问题:今天是否有一种比贪婪的网格划分更好的体素网际算法可以帮助我满足自己的要求?

即使我认为没有针对此类任务的最佳解决方案(看起来有点像p = np问题),即使在寻找科学论文时,我也无法在网上找到其他算法。

您对我的问题有任何建议或参考吗?

For the project I'm working, I have large voxel data I need to visualize within a mesh.

While searching I rapidly find the Meshing in a Minecraft Game article article, written by mikolalysenko back in 2012, and according to my research seems to only source everyone is referring to answer this question.
He describes three algorithm to solving this problem: the Stupid, the Culled and the Greedy.

The two first are really non efficient, so I made a Python version of the code he provides for my project with two tweaks:

  • I use Numba to speed up computations
  • I directly compute the triangle vertices instead of quadrilaterals, to mach to our meshing function implementation
@njit()
def greedy_mesh(volume, dims):
    def f(i, j, k):
        return(volume[i + dims[0] * (j + dims[1] * k)])
    
    points = []
    # Sweep over 3-axes
    for d in range(3):
        u = (d + 1) % 3
        v = (d + 2) % 3
        x = [0, 0, 0]
        q = [0, 0, 0]
        mask = [0] * (dims[u] * dims[v])
        
        q[d] = 1
        
        x[d] = -1
        while x[d] < dims[d]:
            n = 0
            x[v] = 0
            x[u] = 0
            # Compute mask
            while x[v] < dims[v]:
                while x[u] < dims[u]:
                    a = f(x[0], x[1], x[2]) if x[d] >= 0 else False
                    b = f(x[0] + q[0], x[1] + q[1], x[2] + q[2]) if x[d] < (dims[d] - 1) else False
                                   
                    mask[n] = a != b 
                    n += 1
                    
                    x[u] += 1
                
                x[u] = 0
                x[v] += 1
            
            x[d] += 1
            
            n = 0
            # Generate mesh for mask using lexicographic ordering
            for j in range(0, dims[v]):
                i = 0
                while i < dims[u]:                        
                    if (n < len(mask)) and mask[n]:
                        w = 1
                        # Compute width
                        while (n + w < len(mask)) and (mask[n + w] and ((i + w) < dims[u])):
                            w += 1
                        
                        done = False
                        h = 1
                        # Compute height (slighty awkward according to the autor)
                        while (j + h) < dims[v]:
                            for k in range(0, w):
                                if not mask[n + k + h * dims[u]]:
                                    done = True
                                    break
                                    
                            if done:
                                break
                                
                            h += 1
                        
                        # New quad
                        x[u] = i;
                        x[v] = j;
                        du = [0, 0, 0]
                        dv = [0, 0, 0]
                        
                        du[u] = w
                        dv[v] = h
                        
                        # Triangles
                        A = (x[0],
                             x[1],
                             x[2])
                        B = (x[0] + du[0],
                             x[1] + du[1],
                             x[2] + du[2])
                        C = (x[0] + du[0] + dv[0],
                             x[1] + du[1] + dv[1],
                             x[2] + du[2] + dv[2])
                        D = (x[0] + dv[0],
                             x[1] + dv[1],
                             x[2] + dv[2])
                        
                        points.extend([A, B, C])
                        points.extend([A, C, D])
                        
                        # Zero-out mask
                        for l in range(0, h):
                            for k in range(0, w):
                                mask[n + k + l * dims[u]] = False
                        
                        i += w
                        n += w
                        
                    else:
                        i += 1
                        n += 1

    # Unique set of points
    vertices = [i for i in set(points)]
    
    # Points 
    indices = []
    for p in points:
        indices.append(vertices.index(p))
    
    return np.array(vertices), np.array(indices).reshape(-1, 3)

I test out my code using the examples provides once again by mikolalysenko and it run perfectly fine.
But then I tried to load bigger voxel data from our project (~ 300x300x300), and now the algorithm run for about 5s to process the data. Honestly I quite fast but not enough for usage, and we have much larger data sets.

After a bit of profile, and without really any surprise, most of computation time is due to creation of the vertices and their indices at the end. Unfortunetly, this is the way the meshing function was created to work with and I'm not able to change this feature.

That's finally leads my to my question: Is there today a voxel meshing algorithm better than Greedy Meshing that could helps me fulfill my requirements?

Even if I believe there is no optimal solution for this kind of task (looks a bit like a P = NP problem), I cannot find alternative algorithms online even while looking for scientific papers.

Do you have any suggestions or references regarding my problem?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文