简体   繁体   English

如何在 Python 中偏移/加厚/固化 3D 网格?

[英]How can I offset / thicken / solidify a 3D mesh in Python?

I'm looking for a way to offset a TIN (triangulated irregular.network) mesh (eg of a landscape) by a consistent distance via a Python script.我正在寻找一种通过 Python 脚本以一致的距离偏移 TIN(三角化不规则网络)网格(例如景观)的方法。 In the past I've called Blender's Solidify modifier via the API , which works well, but I'd like to find an alternative that doesn't require Blender as a dependency.过去,我通过 API 调用了 Blender 的 Solidify 修改器,效果很好,但我想找到一个不需要 Blender 作为依赖项的替代方案。

Currently, I'm iterating over each triangle, making a copy of each vertex and moving these along their parent triangle's surface normal by a set distance.目前,我正在遍历每个三角形,制作每个顶点的副本,并将它们沿着父三角形的表面法线移动一定距离。 Where the same vertex appears in multiple triangles I calculate the offset for each normal and use the mean.如果相同的顶点出现在多个三角形中,我会计算每个法线的偏移量并使用平均值。 Then I connect the vertices together again to make an offset mesh.然后我再次将顶点连接在一起以制作偏移网格。

This seems to work ok for small offsets, but sharp features in the mesh can create self-intersections.这似乎适用于较小的偏移量,但网格中的尖锐特征会产生自相交。

Is there a specific algorithm or library which offers a better way?是否有提供更好方法的特定算法或库?

So far, apart from Blender, I've found:到目前为止,除了 Blender,我还发现:

But I haven't found much for Python eg in Open3D or Trimesh .但是我没有在Open3DTrimesh中找到 Python 的太多信息。

I think the easy fix for your offsetting is to move the vertices along the mean normal, instead of moving it by the mean of along each normal.我认为偏移的简单解决方法是沿着平均法线移动顶点,而不是沿着每个法线的平均值移动它。 (ok the difference can be tricky to see in that sentence;) ) (好吧,在那句话中很难看出区别;))

to do it by hand用手做

What I mean is that when you get sharp geometries the mean of neighbooring normal is no more of length 1, so in the end you don't offset your vertex by the desired distance.我的意思是,当你得到尖锐的几何形状时,相邻法线的平均值不再是长度 1,所以最后你不会将你的顶点偏移所需的距离。 I think you should compute the sum of neighbooring normals and then normalize those vectors to get the normal to each vertex.我认为您应该计算相邻法线的总和,然后对这些向量进行归一化以获得每个顶点的法线。 If you have more than 3 triangles connected to each vertex (which is the general case) you also need to make a weighted sum of neighbooring normals by the triangles' connection angle...如果您有超过 3 个三角形连接到每个顶点(这是一般情况),您还需要通过三角形的连接角对相邻法线进行加权和...

or use a python module或使用 python 模块

You can also pymadcad There is a function that does exactly what I said:你也可以pymadcad有一个 function 完全按照我说的做:

from madcad import *

surface = Mesh([points, ...], [triangles, ...])
my_thick_mesh = thicken(surface, distance)

There is 3 function regarding this problem:关于这个问题,有3 个 function

  • inflateoffsets gives the desired offset vectors inflateoffsets给出所需的偏移向量

  • inflate offsets a mesh surface膨胀偏移网格表面

  • thicken create an envelope with加厚创建一个信封

    • the original surface原始表面

    • the offseted surface偏移曲面

    • the sides双方

One of the most robust methods to make uniform offset is rasterization of mesh, eg making voxels filled with signed distances to the surface, and then building iso-surface with desired offset.实现均匀偏移的最可靠方法之一是网格光栅化,例如,使体素填充到表面的有符号距离,然后构建具有所需偏移的等值面。 But this method have limitation: to have voxels filled with signed distances input mesh have to be closed.但是这种方法有局限性:要使体素填充有符号距离,输入网格必须关闭。 Anyway you can make unsigned voxels which lead to shell offset (for non-closed surfaces).无论如何,您可以制作导致 shell 偏移量的无符号体素(对于非封闭表面)。

General advantage of this method is that it can work with self-intersecting mesh.这种方法的一般优点是它可以使用自相交网格。

There is C++ implementation using openvdb in opensource MeshLib library that has python modules.在具有 python 个模块的开源MeshLib库中,使用openvdb实现了 C++。 So you can use following code:所以你可以使用下面的代码:

from meshlib import mrmeshpy

# load closed mesh
closedMesh = mrmeshpy.loadMesh("closedMesh.stl")

# load non-closed mesh
nonClosedMesh = mrmeshpy.loadMesh("nonClosedMesh.stl")


# setup offset parameters
params = mrmeshpy.OffsetParameters()
params.voxelSize = 0.04
params.type = mrmeshpy.OffsetParametersType.Offset # requires closed mesh

# create positive offset mesh
posOffset = mrmeshpy.offsetMesh(closedMesh, 0.2, params)


# create negative offset mesh
negOffset = mrmeshpy.offsetMesh(closedMesh, -0.1, params)


# change offset mode to `Shell`
params.type = mrmeshpy.OffsetParametersType.Shell # does not require closed mesh

# create shell mesh
shell = mrmeshpy.offsetMesh(enonClosedMesh, 0.1, params)

# save results
mrmeshpy.saveMesh(posOffset, "posOffset.stl")
mrmeshpy.saveMesh(negOffset, "negOffset.stl")
mrmeshpy.saveMesh(shell, "shell.stl")

closedMesh.stl closedMesh.stl

封闭网格.stl

posOffset.stl posOffset.stl

位置偏移.stl

negOffset.stl negOffset.stl

负偏移.stl

nonClosedMesh.stl nonClosedMesh.stl

非封闭网格.stl

shell.stl shell.stl

外壳.stl

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM